Completed
Branch CASC/preview-page (f4255e)
by
unknown
36:10 queued 17:15
created

Events_Admin_Page::getModelsAndIdsToDelete()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 16

Duplication

Lines 6
Ratio 37.5 %

Importance

Changes 0
Metric Value
cc 4
nc 4
nop 1
dl 6
loc 16
rs 9.7333
c 0
b 0
f 0
1
<?php
2
3
use EventEspresso\admin_pages\events\form_sections\ConfirmEventDeletionForm;
4
use EventEspresso\core\exceptions\InvalidDataTypeException;
5
use EventEspresso\core\exceptions\InvalidInterfaceException;
6
use EventEspresso\core\exceptions\UnexpectedEntityException;
7
use EventEspresso\core\services\orm\tree_traversal\ModelObjNode;
8
9
/**
10
 * Events_Admin_Page
11
 * This contains the logic for setting up the Events related pages.
12
 * Any methods without phpdoc comments have inline docs with parent class.
13
 *
14
 * @package         Events_Admin_Page
15
 * @subpackage      includes/core/admin/Events_Admin_Page.core.php
16
 * @author          Darren Ethier
17
 */
18
class Events_Admin_Page extends EE_Admin_Page_CPT
19
{
20
21
    /**
22
     * This will hold the event object for event_details screen.
23
     *
24
     * @access protected
25
     * @var EE_Event $_event
26
     */
27
    protected $_event;
28
29
30
    /**
31
     * This will hold the category object for category_details screen.
32
     *
33
     * @var stdClass $_category
34
     */
35
    protected $_category;
36
37
38
    /**
39
     * This will hold the event model instance
40
     *
41
     * @var EEM_Event $_event_model
42
     */
43
    protected $_event_model;
44
45
46
    /**
47
     * @var EE_Event
48
     */
49
    protected $_cpt_model_obj = false;
50
51
    /**
52
     * Used to hold onto a form across various stages of a request.
53
     * @var EE_Form_Section_Proper
54
     */
55
    protected $form;
56
57
    /**
58
     * Used so we don't have to repeatedly fetch a potentially large array of data from the WP options table.
59
     * @var array
60
     */
61
    protected $models_and_ids_to_delete;
62
63
64
    /**
65
     * Initialize page props for this admin page group.
66
     */
67
    protected function _init_page_props()
68
    {
69
        $this->page_slug = EVENTS_PG_SLUG;
70
        $this->page_label = EVENTS_LABEL;
71
        $this->_admin_base_url = EVENTS_ADMIN_URL;
72
        $this->_admin_base_path = EVENTS_ADMIN;
73
        $this->_cpt_model_names = array(
74
            'create_new' => 'EEM_Event',
75
            'edit'       => 'EEM_Event',
76
        );
77
        $this->_cpt_edit_routes = array(
78
            'espresso_events' => 'edit',
79
        );
80
        add_action(
81
            'AHEE__EE_Admin_Page_CPT__set_model_object__after_set_object',
82
            array($this, 'verify_event_edit'),
83
            10,
84
            2
85
        );
86
    }
87
88
89
    /**
90
     * Sets the ajax hooks used for this admin page group.
91
     */
92
    protected function _ajax_hooks()
93
    {
94
        add_action('wp_ajax_ee_save_timezone_setting', array($this, 'save_timezonestring_setting'));
95
    }
96
97
98
    /**
99
     * Sets the page properties for this admin page group.
100
     */
101 View Code Duplication
    protected function _define_page_props()
102
    {
103
        $this->_admin_page_title = EVENTS_LABEL;
104
        $this->_labels = array(
105
            'buttons'      => array(
106
                'add'             => esc_html__('Add New Event', 'event_espresso'),
107
                'edit'            => esc_html__('Edit Event', 'event_espresso'),
108
                'delete'          => esc_html__('Delete Event', 'event_espresso'),
109
                'add_category'    => esc_html__('Add New Category', 'event_espresso'),
110
                'edit_category'   => esc_html__('Edit Category', 'event_espresso'),
111
                'delete_category' => esc_html__('Delete Category', 'event_espresso'),
112
            ),
113
            'editor_title' => array(
114
                'espresso_events' => esc_html__('Enter event title here', 'event_espresso'),
115
            ),
116
            'publishbox'   => array(
117
                'create_new'        => esc_html__('Save New Event', 'event_espresso'),
118
                'edit'              => esc_html__('Update Event', 'event_espresso'),
119
                'add_category'      => esc_html__('Save New Category', 'event_espresso'),
120
                'edit_category'     => esc_html__('Update Category', 'event_espresso'),
121
                'template_settings' => esc_html__('Update Settings', 'event_espresso'),
122
            ),
123
        );
124
    }
125
126
127
    /**
128
     * Sets the page routes property for this admin page group.
129
     */
130
    protected function _set_page_routes()
131
    {
132
        // load formatter helper
133
        // load field generator helper
134
        // is there a evt_id in the request?
135
        $evt_id = ! empty($this->_req_data['EVT_ID']) && ! is_array($this->_req_data['EVT_ID'])
136
            ? $this->_req_data['EVT_ID']
137
            : 0;
138
        $evt_id = ! empty($this->_req_data['post']) ? $this->_req_data['post'] : $evt_id;
139
        $this->_page_routes = array(
140
            'default'                       => array(
141
                'func'       => '_events_overview_list_table',
142
                'capability' => 'ee_read_events',
143
            ),
144
            'create_new'                    => array(
145
                'func'       => '_create_new_cpt_item',
146
                'capability' => 'ee_edit_events',
147
            ),
148
            'edit'                          => array(
149
                'func'       => '_edit_cpt_item',
150
                'capability' => 'ee_edit_event',
151
                'obj_id'     => $evt_id,
152
            ),
153
            'copy_event'                    => array(
154
                'func'       => '_copy_events',
155
                'capability' => 'ee_edit_event',
156
                'obj_id'     => $evt_id,
157
                'noheader'   => true,
158
            ),
159
            'trash_event'                   => array(
160
                'func'       => '_trash_or_restore_event',
161
                'args'       => array('event_status' => 'trash'),
162
                'capability' => 'ee_delete_event',
163
                'obj_id'     => $evt_id,
164
                'noheader'   => true,
165
            ),
166
            'trash_events'                  => array(
167
                'func'       => '_trash_or_restore_events',
168
                'args'       => array('event_status' => 'trash'),
169
                'capability' => 'ee_delete_events',
170
                'noheader'   => true,
171
            ),
172
            'restore_event'                 => array(
173
                'func'       => '_trash_or_restore_event',
174
                'args'       => array('event_status' => 'draft'),
175
                'capability' => 'ee_delete_event',
176
                'obj_id'     => $evt_id,
177
                'noheader'   => true,
178
            ),
179
            'restore_events'                => array(
180
                'func'       => '_trash_or_restore_events',
181
                'args'       => array('event_status' => 'draft'),
182
                'capability' => 'ee_delete_events',
183
                'noheader'   => true,
184
            ),
185
            'delete_event'                  => array(
186
                'func'       => '_delete_event',
187
                'capability' => 'ee_delete_event',
188
                'obj_id'     => $evt_id,
189
                'noheader'   => true,
190
            ),
191
            'delete_events'                 => array(
192
                'func'       => '_delete_events',
193
                'capability' => 'ee_delete_events',
194
                'noheader'   => true,
195
            ),
196
            'view_report'                   => array(
197
                'func'      => '_view_report',
198
                'capablity' => 'ee_edit_events',
199
            ),
200
            'default_event_settings'        => array(
201
                'func'       => '_default_event_settings',
202
                'capability' => 'manage_options',
203
            ),
204
            'update_default_event_settings' => array(
205
                'func'       => '_update_default_event_settings',
206
                'capability' => 'manage_options',
207
                'noheader'   => true,
208
            ),
209
            'template_settings'             => array(
210
                'func'       => '_template_settings',
211
                'capability' => 'manage_options',
212
            ),
213
            // event category tab related
214
            'add_category'                  => array(
215
                'func'       => '_category_details',
216
                'capability' => 'ee_edit_event_category',
217
                'args'       => array('add'),
218
            ),
219
            'edit_category'                 => array(
220
                'func'       => '_category_details',
221
                'capability' => 'ee_edit_event_category',
222
                'args'       => array('edit'),
223
            ),
224
            'delete_categories'             => array(
225
                'func'       => '_delete_categories',
226
                'capability' => 'ee_delete_event_category',
227
                'noheader'   => true,
228
            ),
229
            'delete_category'               => array(
230
                'func'       => '_delete_categories',
231
                'capability' => 'ee_delete_event_category',
232
                'noheader'   => true,
233
            ),
234
            'insert_category'               => array(
235
                'func'       => '_insert_or_update_category',
236
                'args'       => array('new_category' => true),
237
                'capability' => 'ee_edit_event_category',
238
                'noheader'   => true,
239
            ),
240
            'update_category'               => array(
241
                'func'       => '_insert_or_update_category',
242
                'args'       => array('new_category' => false),
243
                'capability' => 'ee_edit_event_category',
244
                'noheader'   => true,
245
            ),
246
            'category_list'                 => array(
247
                'func'       => '_category_list_table',
248
                'capability' => 'ee_manage_event_categories',
249
            ),
250
            'preview_deletion' => [
251
                'func' => 'previewDeletion',
252
                'capability' => 'ee_delete_events',
253
            ],
254
            'confirm_deletion' => [
255
                'func' => 'confirmDeletion',
256
                'capability' => 'ee_delete_events',
257
                'noheader' => true,
258
                'headers_sent_route' => 'preview_deletion',
259
            ]
260
        );
261
    }
262
263
264
    /**
265
     * Set the _page_config property for this admin page group.
266
     */
267
    protected function _set_page_config()
268
    {
269
        $this->_page_config = array(
270
            'default'                => array(
271
                'nav'           => array(
272
                    'label' => esc_html__('Overview', 'event_espresso'),
273
                    'order' => 10,
274
                ),
275
                'list_table'    => 'Events_Admin_List_Table',
276
                'help_tabs'     => array(
277
                    'events_overview_help_tab'                       => array(
278
                        'title'    => esc_html__('Events Overview', 'event_espresso'),
279
                        'filename' => 'events_overview',
280
                    ),
281
                    'events_overview_table_column_headings_help_tab' => array(
282
                        'title'    => esc_html__('Events Overview Table Column Headings', 'event_espresso'),
283
                        'filename' => 'events_overview_table_column_headings',
284
                    ),
285
                    'events_overview_filters_help_tab'               => array(
286
                        'title'    => esc_html__('Events Overview Filters', 'event_espresso'),
287
                        'filename' => 'events_overview_filters',
288
                    ),
289
                    'events_overview_view_help_tab'                  => array(
290
                        'title'    => esc_html__('Events Overview Views', 'event_espresso'),
291
                        'filename' => 'events_overview_views',
292
                    ),
293
                    'events_overview_other_help_tab'                 => array(
294
                        'title'    => esc_html__('Events Overview Other', 'event_espresso'),
295
                        'filename' => 'events_overview_other',
296
                    ),
297
                ),
298
                'help_tour'     => array(
299
                    'Event_Overview_Help_Tour',
300
                    // 'New_Features_Test_Help_Tour' for testing multiple help tour
301
                ),
302
                'qtips'         => array(
303
                    'EE_Event_List_Table_Tips',
304
                ),
305
                'require_nonce' => false,
306
            ),
307
            'create_new'             => array(
308
                'nav'           => array(
309
                    'label'      => esc_html__('Add Event', 'event_espresso'),
310
                    'order'      => 5,
311
                    'persistent' => false,
312
                ),
313
                'metaboxes'     => array('_register_event_editor_meta_boxes'),
314
                'help_tabs'     => array(
315
                    'event_editor_help_tab'                            => array(
316
                        'title'    => esc_html__('Event Editor', 'event_espresso'),
317
                        'filename' => 'event_editor',
318
                    ),
319
                    'event_editor_title_richtexteditor_help_tab'       => array(
320
                        'title'    => esc_html__('Event Title & Rich Text Editor', 'event_espresso'),
321
                        'filename' => 'event_editor_title_richtexteditor',
322
                    ),
323
                    'event_editor_venue_details_help_tab'              => array(
324
                        'title'    => esc_html__('Event Venue Details', 'event_espresso'),
325
                        'filename' => 'event_editor_venue_details',
326
                    ),
327
                    'event_editor_event_datetimes_help_tab'            => array(
328
                        'title'    => esc_html__('Event Datetimes', 'event_espresso'),
329
                        'filename' => 'event_editor_event_datetimes',
330
                    ),
331
                    'event_editor_event_tickets_help_tab'              => array(
332
                        'title'    => esc_html__('Event Tickets', 'event_espresso'),
333
                        'filename' => 'event_editor_event_tickets',
334
                    ),
335
                    'event_editor_event_registration_options_help_tab' => array(
336
                        'title'    => esc_html__('Event Registration Options', 'event_espresso'),
337
                        'filename' => 'event_editor_event_registration_options',
338
                    ),
339
                    'event_editor_tags_categories_help_tab'            => array(
340
                        'title'    => esc_html__('Event Tags & Categories', 'event_espresso'),
341
                        'filename' => 'event_editor_tags_categories',
342
                    ),
343
                    'event_editor_questions_registrants_help_tab'      => array(
344
                        'title'    => esc_html__('Questions for Registrants', 'event_espresso'),
345
                        'filename' => 'event_editor_questions_registrants',
346
                    ),
347
                    'event_editor_save_new_event_help_tab'             => array(
348
                        'title'    => esc_html__('Save New Event', 'event_espresso'),
349
                        'filename' => 'event_editor_save_new_event',
350
                    ),
351
                    'event_editor_other_help_tab'                      => array(
352
                        'title'    => esc_html__('Event Other', 'event_espresso'),
353
                        'filename' => 'event_editor_other',
354
                    ),
355
                ),
356
                'help_tour'     => array(
357
                    'Event_Editor_Help_Tour',
358
                ),
359
                'qtips'         => array('EE_Event_Editor_Decaf_Tips'),
360
                'require_nonce' => false,
361
            ),
362
            'edit'                   => array(
363
                'nav'           => array(
364
                    'label'      => esc_html__('Edit Event', 'event_espresso'),
365
                    'order'      => 5,
366
                    'persistent' => false,
367
                    'url'        => isset($this->_req_data['post'])
368
                        ? EE_Admin_Page::add_query_args_and_nonce(
369
                            array('post' => $this->_req_data['post'], 'action' => 'edit'),
370
                            $this->_current_page_view_url
371
                        )
372
                        : $this->_admin_base_url,
373
                ),
374
                'metaboxes'     => array('_register_event_editor_meta_boxes'),
375
                'help_tabs'     => array(
376
                    'event_editor_help_tab'                            => array(
377
                        'title'    => esc_html__('Event Editor', 'event_espresso'),
378
                        'filename' => 'event_editor',
379
                    ),
380
                    'event_editor_title_richtexteditor_help_tab'       => array(
381
                        'title'    => esc_html__('Event Title & Rich Text Editor', 'event_espresso'),
382
                        'filename' => 'event_editor_title_richtexteditor',
383
                    ),
384
                    'event_editor_venue_details_help_tab'              => array(
385
                        'title'    => esc_html__('Event Venue Details', 'event_espresso'),
386
                        'filename' => 'event_editor_venue_details',
387
                    ),
388
                    'event_editor_event_datetimes_help_tab'            => array(
389
                        'title'    => esc_html__('Event Datetimes', 'event_espresso'),
390
                        'filename' => 'event_editor_event_datetimes',
391
                    ),
392
                    'event_editor_event_tickets_help_tab'              => array(
393
                        'title'    => esc_html__('Event Tickets', 'event_espresso'),
394
                        'filename' => 'event_editor_event_tickets',
395
                    ),
396
                    'event_editor_event_registration_options_help_tab' => array(
397
                        'title'    => esc_html__('Event Registration Options', 'event_espresso'),
398
                        'filename' => 'event_editor_event_registration_options',
399
                    ),
400
                    'event_editor_tags_categories_help_tab'            => array(
401
                        'title'    => esc_html__('Event Tags & Categories', 'event_espresso'),
402
                        'filename' => 'event_editor_tags_categories',
403
                    ),
404
                    'event_editor_questions_registrants_help_tab'      => array(
405
                        'title'    => esc_html__('Questions for Registrants', 'event_espresso'),
406
                        'filename' => 'event_editor_questions_registrants',
407
                    ),
408
                    'event_editor_save_new_event_help_tab'             => array(
409
                        'title'    => esc_html__('Save New Event', 'event_espresso'),
410
                        'filename' => 'event_editor_save_new_event',
411
                    ),
412
                    'event_editor_other_help_tab'                      => array(
413
                        'title'    => esc_html__('Event Other', 'event_espresso'),
414
                        'filename' => 'event_editor_other',
415
                    ),
416
                ),
417
                'qtips'         => array('EE_Event_Editor_Decaf_Tips'),
418
                'require_nonce' => false,
419
            ),
420
            'default_event_settings' => array(
421
                'nav'           => array(
422
                    'label' => esc_html__('Default Settings', 'event_espresso'),
423
                    'order' => 40,
424
                ),
425
                'metaboxes'     => array_merge($this->_default_espresso_metaboxes, array('_publish_post_box')),
426
                'labels'        => array(
427
                    'publishbox' => esc_html__('Update Settings', 'event_espresso'),
428
                ),
429
                'help_tabs'     => array(
430
                    'default_settings_help_tab'        => array(
431
                        'title'    => esc_html__('Default Event Settings', 'event_espresso'),
432
                        'filename' => 'events_default_settings',
433
                    ),
434
                    'default_settings_status_help_tab' => array(
435
                        'title'    => esc_html__('Default Registration Status', 'event_espresso'),
436
                        'filename' => 'events_default_settings_status',
437
                    ),
438
                    'default_maximum_tickets_help_tab' => array(
439
                        'title'    => esc_html__('Default Maximum Tickets Per Order', 'event_espresso'),
440
                        'filename' => 'events_default_settings_max_tickets',
441
                    ),
442
                ),
443
                'help_tour'     => array('Event_Default_Settings_Help_Tour'),
444
                'require_nonce' => false,
445
            ),
446
            // template settings
447
            'template_settings'      => array(
448
                'nav'           => array(
449
                    'label' => esc_html__('Templates', 'event_espresso'),
450
                    'order' => 30,
451
                ),
452
                'metaboxes'     => $this->_default_espresso_metaboxes,
453
                'help_tabs'     => array(
454
                    'general_settings_templates_help_tab' => array(
455
                        'title'    => esc_html__('Templates', 'event_espresso'),
456
                        'filename' => 'general_settings_templates',
457
                    ),
458
                ),
459
                'help_tour'     => array('Templates_Help_Tour'),
460
                'require_nonce' => false,
461
            ),
462
            // event category stuff
463
            'add_category'           => array(
464
                'nav'           => array(
465
                    'label'      => esc_html__('Add Category', 'event_espresso'),
466
                    'order'      => 15,
467
                    'persistent' => false,
468
                ),
469
                'help_tabs'     => array(
470
                    'add_category_help_tab' => array(
471
                        'title'    => esc_html__('Add New Event Category', 'event_espresso'),
472
                        'filename' => 'events_add_category',
473
                    ),
474
                ),
475
                'help_tour'     => array('Event_Add_Category_Help_Tour'),
476
                'metaboxes'     => array('_publish_post_box'),
477
                'require_nonce' => false,
478
            ),
479
            'edit_category'          => array(
480
                'nav'           => array(
481
                    'label'      => esc_html__('Edit Category', 'event_espresso'),
482
                    'order'      => 15,
483
                    'persistent' => false,
484
                    'url'        => isset($this->_req_data['EVT_CAT_ID'])
485
                        ? add_query_arg(
486
                            array('EVT_CAT_ID' => $this->_req_data['EVT_CAT_ID']),
487
                            $this->_current_page_view_url
488
                        )
489
                        : $this->_admin_base_url,
490
                ),
491
                'help_tabs'     => array(
492
                    'edit_category_help_tab' => array(
493
                        'title'    => esc_html__('Edit Event Category', 'event_espresso'),
494
                        'filename' => 'events_edit_category',
495
                    ),
496
                ),
497
                /*'help_tour' => array('Event_Edit_Category_Help_Tour'),*/
498
                'metaboxes'     => array('_publish_post_box'),
499
                'require_nonce' => false,
500
            ),
501
            'category_list'          => array(
502
                'nav'           => array(
503
                    'label' => esc_html__('Categories', 'event_espresso'),
504
                    'order' => 20,
505
                ),
506
                'list_table'    => 'Event_Categories_Admin_List_Table',
507
                'help_tabs'     => array(
508
                    'events_categories_help_tab'                       => array(
509
                        'title'    => esc_html__('Event Categories', 'event_espresso'),
510
                        'filename' => 'events_categories',
511
                    ),
512
                    'events_categories_table_column_headings_help_tab' => array(
513
                        'title'    => esc_html__('Event Categories Table Column Headings', 'event_espresso'),
514
                        'filename' => 'events_categories_table_column_headings',
515
                    ),
516
                    'events_categories_view_help_tab'                  => array(
517
                        'title'    => esc_html__('Event Categories Views', 'event_espresso'),
518
                        'filename' => 'events_categories_views',
519
                    ),
520
                    'events_categories_other_help_tab'                 => array(
521
                        'title'    => esc_html__('Event Categories Other', 'event_espresso'),
522
                        'filename' => 'events_categories_other',
523
                    ),
524
                ),
525
                'help_tour'     => array(
526
                    'Event_Categories_Help_Tour',
527
                ),
528
                'metaboxes'     => $this->_default_espresso_metaboxes,
529
                'require_nonce' => false,
530
            ),
531
            'preview_deletion'           => array(
532
                'nav'           => array(
533
                    'label'      => esc_html__('Preview Deletion', 'event_espresso'),
534
                    'order'      => 15,
535
                    'persistent' => false,
536
                ),
537
                'require_nonce' => false
538
            )
539
        );
540
    }
541
542
543
    /**
544
     * Used to register any global screen options if necessary for every route in this admin page group.
545
     */
546
    protected function _add_screen_options()
547
    {
548
    }
549
550
551
    /**
552
     * Implementing the screen options for the 'default' route.
553
     */
554
    protected function _add_screen_options_default()
555
    {
556
        $this->_per_page_screen_option();
557
    }
558
559
560
    /**
561
     * Implementing screen options for the category list route.
562
     */
563 View Code Duplication
    protected function _add_screen_options_category_list()
564
    {
565
        $page_title = $this->_admin_page_title;
566
        $this->_admin_page_title = esc_html__('Categories', 'event_espresso');
567
        $this->_per_page_screen_option();
568
        $this->_admin_page_title = $page_title;
569
    }
570
571
572
    /**
573
     * Used to register any global feature pointers for the admin page group.
574
     */
575
    protected function _add_feature_pointers()
576
    {
577
    }
578
579
580
    /**
581
     * Registers and enqueues any global scripts and styles for the entire admin page group.
582
     */
583 View Code Duplication
    public function load_scripts_styles()
584
    {
585
        wp_register_style(
586
            'events-admin-css',
587
            EVENTS_ASSETS_URL . 'events-admin-page.css',
588
            array(),
589
            EVENT_ESPRESSO_VERSION
590
        );
591
        wp_register_style('ee-cat-admin', EVENTS_ASSETS_URL . 'ee-cat-admin.css', array(), EVENT_ESPRESSO_VERSION);
592
        wp_enqueue_style('events-admin-css');
593
        wp_enqueue_style('ee-cat-admin');
594
        // todo note: we also need to load_scripts_styles per view (i.e. default/view_report/event_details
595
        // registers for all views
596
        // scripts
597
        wp_register_script(
598
            'event_editor_js',
599
            EVENTS_ASSETS_URL . 'event_editor.js',
600
            array('ee_admin_js', 'jquery-ui-slider', 'jquery-ui-timepicker-addon'),
601
            EVENT_ESPRESSO_VERSION,
602
            true
603
        );
604
    }
605
606
607
    /**
608
     * Enqueuing scripts and styles specific to this view
609
     */
610
    public function load_scripts_styles_create_new()
611
    {
612
        $this->load_scripts_styles_edit();
613
    }
614
615
616
    /**
617
     * Enqueuing scripts and styles specific to this view
618
     */
619 View Code Duplication
    public function load_scripts_styles_edit()
620
    {
621
        // styles
622
        wp_enqueue_style('espresso-ui-theme');
623
        wp_register_style(
624
            'event-editor-css',
625
            EVENTS_ASSETS_URL . 'event-editor.css',
626
            array('ee-admin-css'),
627
            EVENT_ESPRESSO_VERSION
628
        );
629
        wp_enqueue_style('event-editor-css');
630
        // scripts
631
        wp_register_script(
632
            'event-datetime-metabox',
633
            EVENTS_ASSETS_URL . 'event-datetime-metabox.js',
634
            array('event_editor_js', 'ee-datepicker'),
635
            EVENT_ESPRESSO_VERSION
636
        );
637
        wp_enqueue_script('event-datetime-metabox');
638
    }
639
640
641
    /**
642
     * Populating the _views property for the category list table view.
643
     */
644 View Code Duplication
    protected function _set_list_table_views_category_list()
645
    {
646
        $this->_views = array(
647
            'all' => array(
648
                'slug'        => 'all',
649
                'label'       => esc_html__('All', 'event_espresso'),
650
                'count'       => 0,
651
                'bulk_action' => array(
652
                    'delete_categories' => esc_html__('Delete Permanently', 'event_espresso'),
653
                ),
654
            ),
655
        );
656
    }
657
658
659
    /**
660
     * For adding anything that fires on the admin_init hook for any route within this admin page group.
661
     */
662
    public function admin_init()
663
    {
664
        EE_Registry::$i18n_js_strings['image_confirm'] = esc_html__(
665
            'Do you really want to delete this image? Please remember to update your event to complete the removal.',
666
            'event_espresso'
667
        );
668
    }
669
670
671
    /**
672
     * For adding anything that should be triggered on the admin_notices hook for any route within this admin page
673
     * group.
674
     */
675
    public function admin_notices()
676
    {
677
    }
678
679
680
    /**
681
     * For adding anything that should be triggered on the `admin_print_footer_scripts` hook for any route within
682
     * this admin page group.
683
     */
684
    public function admin_footer_scripts()
685
    {
686
    }
687
688
689
    /**
690
     * Call this function to verify if an event is public and has tickets for sale.  If it does, then we need to show a
691
     * warning (via EE_Error::add_error());
692
     *
693
     * @param  EE_Event $event Event object
694
     * @param string    $req_type
695
     * @return void
696
     * @throws EE_Error
697
     * @access public
698
     */
699
    public function verify_event_edit($event = null, $req_type = '')
700
    {
701
        // don't need to do this when processing
702
        if (! empty($req_type)) {
703
            return;
704
        }
705
        // no event?
706
        if (empty($event)) {
707
            // set event
708
            $event = $this->_cpt_model_obj;
709
        }
710
        // STILL no event?
711
        if (! $event instanceof EE_Event) {
712
            return;
713
        }
714
        $orig_status = $event->status();
715
        // first check if event is active.
716
        if ($orig_status === EEM_Event::cancelled
717
            || $orig_status === EEM_Event::postponed
718
            || $event->is_expired()
719
            || $event->is_inactive()
720
        ) {
721
            return;
722
        }
723
        // made it here so it IS active... next check that any of the tickets are sold.
724
        if ($event->is_sold_out(true)) {
725
            if ($orig_status !== EEM_Event::sold_out && $event->status() !== $orig_status) {
726
                EE_Error::add_attention(
727
                    sprintf(
728
                        esc_html__(
729
                            'Please note that the Event Status has automatically been changed to %s because there are no more spaces available for this event.  However, this change is not permanent until you update the event.  You can change the status back to something else before updating if you wish.',
730
                            'event_espresso'
731
                        ),
732
                        EEH_Template::pretty_status(EEM_Event::sold_out, false, 'sentence')
733
                    )
734
                );
735
            }
736
            return;
737
        } elseif ($orig_status === EEM_Event::sold_out) {
738
            EE_Error::add_attention(
739
                sprintf(
740
                    esc_html__(
741
                        'Please note that the Event Status has automatically been changed to %s because more spaces have become available for this event, most likely due to abandoned transactions freeing up reserved tickets.  However, this change is not permanent until you update the event. If you wish, you can change the status back to something else before updating.',
742
                        'event_espresso'
743
                    ),
744
                    EEH_Template::pretty_status($event->status(), false, 'sentence')
745
                )
746
            );
747
        }
748
        // now we need to determine if the event has any tickets on sale.  If not then we dont' show the error
749
        if (! $event->tickets_on_sale()) {
750
            return;
751
        }
752
        // made it here so show warning
753
        $this->_edit_event_warning();
754
    }
755
756
757
    /**
758
     * This is the text used for when an event is being edited that is public and has tickets for sale.
759
     * When needed, hook this into a EE_Error::add_error() notice.
760
     *
761
     * @access protected
762
     * @return void
763
     */
764
    protected function _edit_event_warning()
765
    {
766
        // we don't want to add warnings during these requests
767
        if (isset($this->_req_data['action']) && $this->_req_data['action'] === 'editpost') {
768
            return;
769
        }
770
        EE_Error::add_attention(
771
            sprintf(
772
                esc_html__(
773
                    'Your event is open for registration. Making changes may disrupt any transactions in progress. %sLearn more%s',
774
                    'event_espresso'
775
                ),
776
                '<a class="espresso-help-tab-lnk">',
777
                '</a>'
778
            )
779
        );
780
    }
781
782
783
    /**
784
     * When a user is creating a new event, notify them if they haven't set their timezone.
785
     * Otherwise, do the normal logic
786
     *
787
     * @return string
788
     * @throws \EE_Error
789
     */
790
    protected function _create_new_cpt_item()
791
    {
792
        $has_timezone_string = get_option('timezone_string');
793
        // only nag them about setting their timezone if it's their first event, and they haven't already done it
794
        if (! $has_timezone_string && ! EEM_Event::instance()->exists(array())) {
795
            EE_Error::add_attention(
796
                sprintf(
797
                    __(
798
                        'Your website\'s timezone is currently set to a UTC offset. We recommend updating your timezone to a city or region near you before you create an event. Change your timezone now:%1$s%2$s%3$sChange Timezone%4$s',
799
                        'event_espresso'
800
                    ),
801
                    '<br>',
802
                    '<select id="timezone_string" name="timezone_string" aria-describedby="timezone-description">'
803
                    . EEH_DTT_Helper::wp_timezone_choice('', EEH_DTT_Helper::get_user_locale())
804
                    . '</select>',
805
                    '<button class="button button-secondary timezone-submit">',
806
                    '</button><span class="spinner"></span>'
807
                ),
808
                __FILE__,
809
                __FUNCTION__,
810
                __LINE__
811
            );
812
        }
813
        return parent::_create_new_cpt_item();
814
    }
815
816
817
    /**
818
     * Sets the _views property for the default route in this admin page group.
819
     */
820
    protected function _set_list_table_views_default()
821
    {
822
        $this->_views = array(
823
            'all'   => array(
824
                'slug'        => 'all',
825
                'label'       => esc_html__('View All Events', 'event_espresso'),
826
                'count'       => 0,
827
                'bulk_action' => array(
828
                    'trash_events' => esc_html__('Move to Trash', 'event_espresso'),
829
                ),
830
            ),
831
            'draft' => array(
832
                'slug'        => 'draft',
833
                'label'       => esc_html__('Draft', 'event_espresso'),
834
                'count'       => 0,
835
                'bulk_action' => array(
836
                    'trash_events' => esc_html__('Move to Trash', 'event_espresso'),
837
                ),
838
            ),
839
        );
840
        if (EE_Registry::instance()->CAP->current_user_can('ee_delete_events', 'espresso_events_trash_events')) {
841
            $this->_views['trash'] = array(
842
                'slug'        => 'trash',
843
                'label'       => esc_html__('Trash', 'event_espresso'),
844
                'count'       => 0,
845
                'bulk_action' => array(
846
                    'restore_events' => esc_html__('Restore From Trash', 'event_espresso'),
847
                    'delete_events'  => esc_html__('Delete Permanently', 'event_espresso'),
848
                ),
849
            );
850
        }
851
    }
852
853
854
    /**
855
     * Provides the legend item array for the default list table view.
856
     *
857
     * @return array
858
     */
859
    protected function _event_legend_items()
860
    {
861
        $items = array(
862
            'view_details'   => array(
863
                'class' => 'dashicons dashicons-search',
864
                'desc'  => esc_html__('View Event', 'event_espresso'),
865
            ),
866
            'edit_event'     => array(
867
                'class' => 'ee-icon ee-icon-calendar-edit',
868
                'desc'  => esc_html__('Edit Event Details', 'event_espresso'),
869
            ),
870
            'view_attendees' => array(
871
                'class' => 'dashicons dashicons-groups',
872
                'desc'  => esc_html__('View Registrations for Event', 'event_espresso'),
873
            ),
874
        );
875
        $items = apply_filters('FHEE__Events_Admin_Page___event_legend_items__items', $items);
876
        $statuses = array(
877
            'sold_out_status'  => array(
878
                'class' => 'ee-status-legend ee-status-legend-' . EE_Datetime::sold_out,
879
                'desc'  => EEH_Template::pretty_status(EE_Datetime::sold_out, false, 'sentence'),
880
            ),
881
            'active_status'    => array(
882
                'class' => 'ee-status-legend ee-status-legend-' . EE_Datetime::active,
883
                'desc'  => EEH_Template::pretty_status(EE_Datetime::active, false, 'sentence'),
884
            ),
885
            'upcoming_status'  => array(
886
                'class' => 'ee-status-legend ee-status-legend-' . EE_Datetime::upcoming,
887
                'desc'  => EEH_Template::pretty_status(EE_Datetime::upcoming, false, 'sentence'),
888
            ),
889
            'postponed_status' => array(
890
                'class' => 'ee-status-legend ee-status-legend-' . EE_Datetime::postponed,
891
                'desc'  => EEH_Template::pretty_status(EE_Datetime::postponed, false, 'sentence'),
892
            ),
893
            'cancelled_status' => array(
894
                'class' => 'ee-status-legend ee-status-legend-' . EE_Datetime::cancelled,
895
                'desc'  => EEH_Template::pretty_status(EE_Datetime::cancelled, false, 'sentence'),
896
            ),
897
            'expired_status'   => array(
898
                'class' => 'ee-status-legend ee-status-legend-' . EE_Datetime::expired,
899
                'desc'  => EEH_Template::pretty_status(EE_Datetime::expired, false, 'sentence'),
900
            ),
901
            'inactive_status'  => array(
902
                'class' => 'ee-status-legend ee-status-legend-' . EE_Datetime::inactive,
903
                'desc'  => EEH_Template::pretty_status(EE_Datetime::inactive, false, 'sentence'),
904
            ),
905
        );
906
        $statuses = apply_filters('FHEE__Events_Admin_Page__event_legend_items__statuses', $statuses);
907
        return array_merge($items, $statuses);
908
    }
909
910
911
    /**
912
     * @return EEM_Event
913
     */
914
    private function _event_model()
915
    {
916
        if (! $this->_event_model instanceof EEM_Event) {
917
            $this->_event_model = EE_Registry::instance()->load_model('Event');
918
        }
919
        return $this->_event_model;
920
    }
921
922
923
    /**
924
     * Adds extra buttons to the WP CPT permalink field row.
925
     * Method is called from parent and is hooked into the wp 'get_sample_permalink_html' filter.
926
     *
927
     * @param  string $return    the current html
928
     * @param  int    $id        the post id for the page
929
     * @param  string $new_title What the title is
930
     * @param  string $new_slug  what the slug is
931
     * @return string            The new html string for the permalink area
932
     */
933
    public function extra_permalink_field_buttons($return, $id, $new_title, $new_slug)
934
    {
935
        // make sure this is only when editing
936
        if (! empty($id)) {
937
            $post = get_post($id);
938
            $return .= '<a class="button button-small" onclick="prompt(\'Shortcode:\', jQuery(\'#shortcode\').val()); return false;" href="#"  tabindex="-1">'
939
                       . esc_html__('Shortcode', 'event_espresso')
940
                       . '</a> ';
941
            $return .= '<input id="shortcode" type="hidden" value="[ESPRESSO_TICKET_SELECTOR event_id='
942
                       . $post->ID
943
                       . ']">';
944
        }
945
        return $return;
946
    }
947
948
949
    /**
950
     * _events_overview_list_table
951
     * This contains the logic for showing the events_overview list
952
     *
953
     * @access protected
954
     * @return void
955
     * @throws \EE_Error
956
     */
957
    protected function _events_overview_list_table()
958
    {
959
        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
960
        $this->_template_args['after_list_table'] = ! empty($this->_template_args['after_list_table'])
961
            ? (array) $this->_template_args['after_list_table']
962
            : array();
963
        $this->_template_args['after_list_table']['view_event_list_button'] = EEH_HTML::br()
964
                . EEH_Template::get_button_or_link(
965
                    get_post_type_archive_link('espresso_events'),
966
                    esc_html__("View Event Archive Page", "event_espresso"),
967
                    'button'
968
                );
969
        $this->_template_args['after_list_table']['legend'] = $this->_display_legend($this->_event_legend_items());
970
        $this->_admin_page_title .= ' ' . $this->get_action_link_or_button(
971
            'create_new',
972
            'add',
973
            array(),
974
            'add-new-h2'
975
        );
976
        $this->display_admin_list_table_page_with_no_sidebar();
977
    }
978
979
980
    /**
981
     * this allows for extra misc actions in the default WP publish box
982
     *
983
     * @return void
984
     */
985
    public function extra_misc_actions_publish_box()
986
    {
987
        $this->_generate_publish_box_extra_content();
988
    }
989
990
991
    /**
992
     * This is hooked into the WordPress do_action('save_post') hook and runs after the custom post type has been
993
     * saved.
994
     * Typically you would use this to save any additional data.
995
     * Keep in mind also that "save_post" runs on EVERY post update to the database.
996
     * ALSO very important.  When a post transitions from scheduled to published,
997
     * the save_post action is fired but you will NOT have any _POST data containing any extra info you may have from
998
     * other meta saves. So MAKE sure that you handle this accordingly.
999
     *
1000
     * @access protected
1001
     * @abstract
1002
     * @param  string $post_id The ID of the cpt that was saved (so you can link relationally)
1003
     * @param  object $post    The post object of the cpt that was saved.
1004
     * @return void
1005
     * @throws \EE_Error
1006
     */
1007
    protected function _insert_update_cpt_item($post_id, $post)
1008
    {
1009
        if ($post instanceof WP_Post && $post->post_type !== 'espresso_events') {
1010
            // get out we're not processing an event save.
1011
            return;
1012
        }
1013
        $event_values = array(
1014
            'EVT_display_desc'                => ! empty($this->_req_data['display_desc']) ? 1 : 0,
1015
            'EVT_display_ticket_selector'     => ! empty($this->_req_data['display_ticket_selector']) ? 1 : 0,
1016
            'EVT_additional_limit'            => min(
1017
                apply_filters('FHEE__EE_Events_Admin__insert_update_cpt_item__EVT_additional_limit_max', 255),
1018
                ! empty($this->_req_data['additional_limit']) ? $this->_req_data['additional_limit'] : null
1019
            ),
1020
            'EVT_default_registration_status' => ! empty($this->_req_data['EVT_default_registration_status'])
1021
                ? $this->_req_data['EVT_default_registration_status']
1022
                : EE_Registry::instance()->CFG->registration->default_STS_ID,
1023
            'EVT_member_only'                 => ! empty($this->_req_data['member_only']) ? 1 : 0,
1024
            'EVT_allow_overflow'              => ! empty($this->_req_data['EVT_allow_overflow']) ? 1 : 0,
1025
            'EVT_timezone_string'             => ! empty($this->_req_data['timezone_string'])
1026
                ? $this->_req_data['timezone_string'] : null,
1027
            'EVT_external_URL'                => ! empty($this->_req_data['externalURL'])
1028
                ? $this->_req_data['externalURL'] : null,
1029
            'EVT_phone'                       => ! empty($this->_req_data['event_phone'])
1030
                ? $this->_req_data['event_phone'] : null,
1031
        );
1032
        // update event
1033
        $success = $this->_event_model()->update_by_ID($event_values, $post_id);
1034
        // get event_object for other metaboxes... though it would seem to make sense to just use $this->_event_model()->get_one_by_ID( $post_id ).. i have to setup where conditions to override the filters in the model that filter out autodraft and inherit statuses so we GET the inherit id!
1035
        $get_one_where = array(
1036
            $this->_event_model()->primary_key_name() => $post_id,
1037
            'OR'                                      => array(
1038
                'status'   => $post->post_status,
1039
                // if trying to "Publish" a sold out event, it's status will get switched back to "sold_out" in the db,
1040
                // but the returned object here has a status of "publish", so use the original post status as well
1041
                'status*1' => $this->_req_data['original_post_status'],
1042
            ),
1043
        );
1044
        $event = $this->_event_model()->get_one(array($get_one_where));
1045
        // the following are default callbacks for event attachment updates that can be overridden by caffeinated functionality and/or addons.
1046
        $event_update_callbacks = apply_filters(
1047
            'FHEE__Events_Admin_Page___insert_update_cpt_item__event_update_callbacks',
1048
            array(
1049
                array($this, '_default_venue_update'),
1050
                array($this, '_default_tickets_update'),
1051
            )
1052
        );
1053
        $att_success = true;
1054
        foreach ($event_update_callbacks as $e_callback) {
1055
            $_success = is_callable($e_callback)
1056
                ? call_user_func($e_callback, $event, $this->_req_data)
1057
                : false;
1058
            // if ANY of these updates fail then we want the appropriate global error message
1059
            $att_success = ! $att_success ? $att_success : $_success;
1060
        }
1061
        // any errors?
1062 View Code Duplication
        if ($success && false === $att_success) {
1063
            EE_Error::add_error(
1064
                esc_html__(
1065
                    'Event Details saved successfully but something went wrong with saving attachments.',
1066
                    'event_espresso'
1067
                ),
1068
                __FILE__,
1069
                __FUNCTION__,
1070
                __LINE__
1071
            );
1072
        } elseif ($success === false) {
1073
            EE_Error::add_error(
1074
                esc_html__('Event Details did not save successfully.', 'event_espresso'),
1075
                __FILE__,
1076
                __FUNCTION__,
1077
                __LINE__
1078
            );
1079
        }
1080
    }
1081
1082
1083
    /**
1084
     * @see parent::restore_item()
1085
     * @param int $post_id
1086
     * @param int $revision_id
1087
     */
1088
    protected function _restore_cpt_item($post_id, $revision_id)
1089
    {
1090
        // copy existing event meta to new post
1091
        $post_evt = $this->_event_model()->get_one_by_ID($post_id);
1092
        if ($post_evt instanceof EE_Event) {
1093
            // meta revision restore
1094
            $post_evt->restore_revision($revision_id);
1095
            // related objs restore
1096
            $post_evt->restore_revision($revision_id, array('Venue', 'Datetime', 'Price'));
1097
        }
1098
    }
1099
1100
1101
    /**
1102
     * Attach the venue to the Event
1103
     *
1104
     * @param  \EE_Event $evtobj Event Object to add the venue to
1105
     * @param  array     $data   The request data from the form
1106
     * @return bool           Success or fail.
1107
     */
1108
    protected function _default_venue_update(\EE_Event $evtobj, $data)
1109
    {
1110
        require_once(EE_MODELS . 'EEM_Venue.model.php');
1111
        $venue_model = EE_Registry::instance()->load_model('Venue');
1112
        $rows_affected = null;
0 ignored issues
show
Unused Code introduced by
$rows_affected is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1113
        $venue_id = ! empty($data['venue_id']) ? $data['venue_id'] : null;
1114
        // very important.  If we don't have a venue name...
1115
        // then we'll get out because not necessary to create empty venue
1116
        if (empty($data['venue_title'])) {
1117
            return false;
1118
        }
1119
        $venue_array = array(
1120
            'VNU_wp_user'         => $evtobj->get('EVT_wp_user'),
1121
            'VNU_name'            => ! empty($data['venue_title']) ? $data['venue_title'] : null,
1122
            'VNU_desc'            => ! empty($data['venue_description']) ? $data['venue_description'] : null,
1123
            'VNU_identifier'      => ! empty($data['venue_identifier']) ? $data['venue_identifier'] : null,
1124
            'VNU_short_desc'      => ! empty($data['venue_short_description']) ? $data['venue_short_description']
1125
                : null,
1126
            'VNU_address'         => ! empty($data['address']) ? $data['address'] : null,
1127
            'VNU_address2'        => ! empty($data['address2']) ? $data['address2'] : null,
1128
            'VNU_city'            => ! empty($data['city']) ? $data['city'] : null,
1129
            'STA_ID'              => ! empty($data['state']) ? $data['state'] : null,
1130
            'CNT_ISO'             => ! empty($data['countries']) ? $data['countries'] : null,
1131
            'VNU_zip'             => ! empty($data['zip']) ? $data['zip'] : null,
1132
            'VNU_phone'           => ! empty($data['venue_phone']) ? $data['venue_phone'] : null,
1133
            'VNU_capacity'        => ! empty($data['venue_capacity']) ? $data['venue_capacity'] : null,
1134
            'VNU_url'             => ! empty($data['venue_url']) ? $data['venue_url'] : null,
1135
            'VNU_virtual_phone'   => ! empty($data['virtual_phone']) ? $data['virtual_phone'] : null,
1136
            'VNU_virtual_url'     => ! empty($data['virtual_url']) ? $data['virtual_url'] : null,
1137
            'VNU_enable_for_gmap' => isset($data['enable_for_gmap']) ? 1 : 0,
1138
            'status'              => 'publish',
1139
        );
1140
        // if we've got the venue_id then we're just updating the existing venue so let's do that and then get out.
1141
        if (! empty($venue_id)) {
1142
            $update_where = array($venue_model->primary_key_name() => $venue_id);
1143
            $rows_affected = $venue_model->update($venue_array, array($update_where));
1144
            // we've gotta make sure that the venue is always attached to a revision.. add_relation_to should take care of making sure that the relation is already present.
1145
            $evtobj->_add_relation_to($venue_id, 'Venue');
1146
            return $rows_affected > 0 ? true : false;
1147
        } else {
1148
            // we insert the venue
1149
            $venue_id = $venue_model->insert($venue_array);
1150
            $evtobj->_add_relation_to($venue_id, 'Venue');
1151
            return ! empty($venue_id) ? true : false;
1152
        }
1153
        // when we have the ancestor come in it's already been handled by the revision save.
1154
    }
1155
1156
1157
    /**
1158
     * Handles saving everything related to Tickets (datetimes, tickets, prices)
1159
     *
1160
     * @param  EE_Event $evtobj The Event object we're attaching data to
1161
     * @param  array    $data   The request data from the form
1162
     * @return array
1163
     */
1164
    protected function _default_tickets_update(EE_Event $evtobj, $data)
1165
    {
1166
        $success = true;
1167
        $saved_dtt = null;
1168
        $saved_tickets = array();
1169
        $incoming_date_formats = array('Y-m-d', 'h:i a');
1170
        foreach ($data['edit_event_datetimes'] as $row => $dtt) {
1171
            // trim all values to ensure any excess whitespace is removed.
1172
            $dtt = array_map('trim', $dtt);
1173
            $dtt['DTT_EVT_end'] = isset($dtt['DTT_EVT_end']) && ! empty($dtt['DTT_EVT_end']) ? $dtt['DTT_EVT_end']
1174
                : $dtt['DTT_EVT_start'];
1175
            $datetime_values = array(
1176
                'DTT_ID'        => ! empty($dtt['DTT_ID']) ? $dtt['DTT_ID'] : null,
1177
                'DTT_EVT_start' => $dtt['DTT_EVT_start'],
1178
                'DTT_EVT_end'   => $dtt['DTT_EVT_end'],
1179
                'DTT_reg_limit' => empty($dtt['DTT_reg_limit']) ? EE_INF : $dtt['DTT_reg_limit'],
1180
                'DTT_order'     => $row,
1181
            );
1182
            // if we have an id then let's get existing object first and then set the new values.  Otherwise we instantiate a new object for save.
1183
            if (! empty($dtt['DTT_ID'])) {
1184
                $DTM = EE_Registry::instance()
1185
                                  ->load_model('Datetime', array($evtobj->get_timezone()))
1186
                                  ->get_one_by_ID($dtt['DTT_ID']);
1187
                $DTM->set_date_format($incoming_date_formats[0]);
1188
                $DTM->set_time_format($incoming_date_formats[1]);
1189
                foreach ($datetime_values as $field => $value) {
1190
                    $DTM->set($field, $value);
1191
                }
1192
                // make sure the $dtt_id here is saved just in case after the add_relation_to() the autosave replaces it.  We need to do this so we dont' TRASH the parent DTT.
1193
                $saved_dtts[ $DTM->ID() ] = $DTM;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$saved_dtts was never initialized. Although not strictly required by PHP, it is generally a good practice to add $saved_dtts = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
1194
            } else {
1195
                $DTM = EE_Registry::instance()->load_class(
1196
                    'Datetime',
1197
                    array($datetime_values, $evtobj->get_timezone(), $incoming_date_formats),
1198
                    false,
1199
                    false
1200
                );
1201
                foreach ($datetime_values as $field => $value) {
1202
                    $DTM->set($field, $value);
1203
                }
1204
            }
1205
            $DTM->save();
1206
            $DTT = $evtobj->_add_relation_to($DTM, 'Datetime');
1207
            // load DTT helper
1208
            // before going any further make sure our dates are setup correctly so that the end date is always equal or greater than the start date.
1209 View Code Duplication
            if ($DTT->get_raw('DTT_EVT_start') > $DTT->get_raw('DTT_EVT_end')) {
1210
                $DTT->set('DTT_EVT_end', $DTT->get('DTT_EVT_start'));
1211
                $DTT = EEH_DTT_Helper::date_time_add($DTT, 'DTT_EVT_end', 'days');
1212
                $DTT->save();
1213
            }
1214
            // now we got to make sure we add the new DTT_ID to the $saved_dtts array  because it is possible there was a new one created for the autosave.
1215
            $saved_dtt = $DTT;
1216
            $success = ! $success ? $success : $DTT;
1217
            // if ANY of these updates fail then we want the appropriate global error message.
1218
            // //todo this is actually sucky we need a better error message but this is what it is for now.
1219
        }
1220
        // no dtts get deleted so we don't do any of that logic here.
1221
        // update tickets next
1222
        $old_tickets = isset($data['ticket_IDs']) ? explode(',', $data['ticket_IDs']) : array();
1223
        foreach ($data['edit_tickets'] as $row => $tkt) {
1224
            $incoming_date_formats = array('Y-m-d', 'h:i a');
1225
            $update_prices = false;
1226
            $ticket_price = isset($data['edit_prices'][ $row ][1]['PRC_amount'])
1227
                ? $data['edit_prices'][ $row ][1]['PRC_amount'] : 0;
1228
            // trim inputs to ensure any excess whitespace is removed.
1229
            $tkt = array_map('trim', $tkt);
1230
            if (empty($tkt['TKT_start_date'])) {
1231
                // let's use now in the set timezone.
1232
                $now = new DateTime('now', new DateTimeZone($evtobj->get_timezone()));
1233
                $tkt['TKT_start_date'] = $now->format($incoming_date_formats[0] . ' ' . $incoming_date_formats[1]);
1234
            }
1235
            if (empty($tkt['TKT_end_date'])) {
1236
                // use the start date of the first datetime
1237
                $dtt = $evtobj->first_datetime();
1238
                $tkt['TKT_end_date'] = $dtt->start_date_and_time(
1239
                    $incoming_date_formats[0],
1240
                    $incoming_date_formats[1]
1241
                );
1242
            }
1243
            $TKT_values = array(
1244
                'TKT_ID'          => ! empty($tkt['TKT_ID']) ? $tkt['TKT_ID'] : null,
1245
                'TTM_ID'          => ! empty($tkt['TTM_ID']) ? $tkt['TTM_ID'] : 0,
1246
                'TKT_name'        => ! empty($tkt['TKT_name']) ? $tkt['TKT_name'] : '',
1247
                'TKT_description' => ! empty($tkt['TKT_description']) ? $tkt['TKT_description'] : '',
1248
                'TKT_start_date'  => $tkt['TKT_start_date'],
1249
                'TKT_end_date'    => $tkt['TKT_end_date'],
1250
                'TKT_qty'         => ! isset($tkt['TKT_qty']) || $tkt['TKT_qty'] === '' ? EE_INF : $tkt['TKT_qty'],
1251
                'TKT_uses'        => ! isset($tkt['TKT_uses']) || $tkt['TKT_uses'] === '' ? EE_INF : $tkt['TKT_uses'],
1252
                'TKT_min'         => empty($tkt['TKT_min']) ? 0 : $tkt['TKT_min'],
1253
                'TKT_max'         => empty($tkt['TKT_max']) ? EE_INF : $tkt['TKT_max'],
1254
                'TKT_row'         => $row,
1255
                'TKT_order'       => isset($tkt['TKT_order']) ? $tkt['TKT_order'] : $row,
1256
                'TKT_price'       => $ticket_price,
1257
            );
1258
            // if this is a default TKT, then we need to set the TKT_ID to 0 and update accordingly, which means in turn that the prices will become new prices as well.
1259 View Code Duplication
            if (isset($tkt['TKT_is_default']) && $tkt['TKT_is_default']) {
1260
                $TKT_values['TKT_ID'] = 0;
1261
                $TKT_values['TKT_is_default'] = 0;
1262
                $TKT_values['TKT_price'] = $ticket_price;
1263
                $update_prices = true;
1264
            }
1265
            // if we have a TKT_ID then we need to get that existing TKT_obj and update it
1266
            // we actually do our saves a head of doing any add_relations to because its entirely possible that this ticket didn't removed or added to any datetime in the session but DID have it's items modified.
1267
            // keep in mind that if the TKT has been sold (and we have changed pricing information), then we won't be updating the tkt but instead a new tkt will be created and the old one archived.
1268
            if (! empty($tkt['TKT_ID'])) {
1269
                $TKT = EE_Registry::instance()
1270
                                  ->load_model('Ticket', array($evtobj->get_timezone()))
1271
                                  ->get_one_by_ID($tkt['TKT_ID']);
1272
                if ($TKT instanceof EE_Ticket) {
1273
                    $ticket_sold = $TKT->count_related(
1274
                        'Registration',
1275
                        array(
1276
                            array(
1277
                                'STS_ID' => array(
1278
                                    'NOT IN',
1279
                                    array(EEM_Registration::status_id_incomplete),
1280
                                ),
1281
                            ),
1282
                        )
1283
                    ) > 0 ? true : false;
1284
                    // let's just check the total price for the existing ticket and determine if it matches the new total price.  if they are different then we create a new ticket (if tkts sold) if they aren't different then we go ahead and modify existing ticket.
1285
                    $create_new_TKT = $ticket_sold && $ticket_price != $TKT->get('TKT_price')
1286
                                      && ! $TKT->get('TKT_deleted');
1287
                    $TKT->set_date_format($incoming_date_formats[0]);
1288
                    $TKT->set_time_format($incoming_date_formats[1]);
1289
                    // set new values
1290 View Code Duplication
                    foreach ($TKT_values as $field => $value) {
1291
                        if ($field == 'TKT_qty') {
1292
                            $TKT->set_qty($value);
1293
                        } else {
1294
                            $TKT->set($field, $value);
1295
                        }
1296
                    }
1297
                    // if $create_new_TKT is false then we can safely update the existing ticket.  Otherwise we have to create a new ticket.
1298
                    if ($create_new_TKT) {
1299
                        // archive the old ticket first
1300
                        $TKT->set('TKT_deleted', 1);
1301
                        $TKT->save();
1302
                        // make sure this ticket is still recorded in our saved_tkts so we don't run it through the regular trash routine.
1303
                        $saved_tickets[ $TKT->ID() ] = $TKT;
1304
                        // create new ticket that's a copy of the existing except a new id of course (and not archived) AND has the new TKT_price associated with it.
1305
                        $TKT = clone $TKT;
1306
                        $TKT->set('TKT_ID', 0);
1307
                        $TKT->set('TKT_deleted', 0);
1308
                        $TKT->set('TKT_price', $ticket_price);
1309
                        $TKT->set('TKT_sold', 0);
1310
                        // now we need to make sure that $new prices are created as well and attached to new ticket.
1311
                        $update_prices = true;
1312
                    }
1313
                    // make sure price is set if it hasn't been already
1314
                    $TKT->set('TKT_price', $ticket_price);
1315
                }
1316
            } else {
1317
                // no TKT_id so a new TKT
1318
                $TKT_values['TKT_price'] = $ticket_price;
1319
                $TKT = EE_Registry::instance()->load_class('Ticket', array($TKT_values), false, false);
1320
                if ($TKT instanceof EE_Ticket) {
1321
                    // need to reset values to properly account for the date formats
1322
                    $TKT->set_date_format($incoming_date_formats[0]);
1323
                    $TKT->set_time_format($incoming_date_formats[1]);
1324
                    $TKT->set_timezone($evtobj->get_timezone());
1325
                    // set new values
1326 View Code Duplication
                    foreach ($TKT_values as $field => $value) {
1327
                        if ($field == 'TKT_qty') {
1328
                            $TKT->set_qty($value);
1329
                        } else {
1330
                            $TKT->set($field, $value);
1331
                        }
1332
                    }
1333
                    $update_prices = true;
1334
                }
1335
            }
1336
            // cap ticket qty by datetime reg limits
1337
            $TKT->set_qty(min($TKT->qty(), $TKT->qty('reg_limit')));
1338
            // update ticket.
1339
            $TKT->save();
1340
            // before going any further make sure our dates are setup correctly so that the end date is always equal or greater than the start date.
1341 View Code Duplication
            if ($TKT->get_raw('TKT_start_date') > $TKT->get_raw('TKT_end_date')) {
1342
                $TKT->set('TKT_end_date', $TKT->get('TKT_start_date'));
1343
                $TKT = EEH_DTT_Helper::date_time_add($TKT, 'TKT_end_date', 'days');
1344
                $TKT->save();
1345
            }
1346
            // initially let's add the ticket to the dtt
1347
            $saved_dtt->_add_relation_to($TKT, 'Ticket');
1348
            $saved_tickets[ $TKT->ID() ] = $TKT;
1349
            // add prices to ticket
1350
            $this->_add_prices_to_ticket($data['edit_prices'][ $row ], $TKT, $update_prices);
1351
        }
1352
        // however now we need to handle permanently deleting tickets via the ui.  Keep in mind that the ui does not allow deleting/archiving tickets that have ticket sold.  However, it does allow for deleting tickets that have no tickets sold, in which case we want to get rid of permanently because there is no need to save in db.
1353
        $old_tickets = isset($old_tickets[0]) && $old_tickets[0] == '' ? array() : $old_tickets;
1354
        $tickets_removed = array_diff($old_tickets, array_keys($saved_tickets));
1355 View Code Duplication
        foreach ($tickets_removed as $id) {
1356
            $id = absint($id);
1357
            // get the ticket for this id
1358
            $tkt_to_remove = EE_Registry::instance()->load_model('Ticket')->get_one_by_ID($id);
1359
            // need to get all the related datetimes on this ticket and remove from every single one of them (remember this process can ONLY kick off if there are NO tkts_sold)
1360
            $dtts = $tkt_to_remove->get_many_related('Datetime');
1361
            foreach ($dtts as $dtt) {
1362
                $tkt_to_remove->_remove_relation_to($dtt, 'Datetime');
1363
            }
1364
            // need to do the same for prices (except these prices can also be deleted because again, tickets can only be trashed if they don't have any TKTs sold (otherwise they are just archived))
1365
            $tkt_to_remove->delete_related_permanently('Price');
1366
            // finally let's delete this ticket (which should not be blocked at this point b/c we've removed all our relationships)
1367
            $tkt_to_remove->delete_permanently();
1368
        }
1369
        return array($saved_dtt, $saved_tickets);
1370
    }
1371
1372
1373
    /**
1374
     * This attaches a list of given prices to a ticket.
1375
     * Note we dont' have to worry about ever removing relationships (or archiving prices) because if there is a change
1376
     * in price information on a ticket, a new ticket is created anyways so the archived ticket will retain the old
1377
     * price info and prices are automatically "archived" via the ticket.
1378
     *
1379
     * @access  private
1380
     * @param array     $prices     Array of prices from the form.
1381
     * @param EE_Ticket $ticket     EE_Ticket object that prices are being attached to.
1382
     * @param bool      $new_prices Whether attach existing incoming prices or create new ones.
1383
     * @return  void
1384
     */
1385
    private function _add_prices_to_ticket($prices, EE_Ticket $ticket, $new_prices = false)
1386
    {
1387
        foreach ($prices as $row => $prc) {
1388
            $PRC_values = array(
1389
                'PRC_ID'         => ! empty($prc['PRC_ID']) ? $prc['PRC_ID'] : null,
1390
                'PRT_ID'         => ! empty($prc['PRT_ID']) ? $prc['PRT_ID'] : null,
1391
                'PRC_amount'     => ! empty($prc['PRC_amount']) ? $prc['PRC_amount'] : 0,
1392
                'PRC_name'       => ! empty($prc['PRC_name']) ? $prc['PRC_name'] : '',
1393
                'PRC_desc'       => ! empty($prc['PRC_desc']) ? $prc['PRC_desc'] : '',
1394
                'PRC_is_default' => 0, // make sure prices are NOT set as default from this context
1395
                'PRC_order'      => $row,
1396
            );
1397 View Code Duplication
            if ($new_prices || empty($PRC_values['PRC_ID'])) {
1398
                $PRC_values['PRC_ID'] = 0;
1399
                $PRC = EE_Registry::instance()->load_class('Price', array($PRC_values), false, false);
1400
            } else {
1401
                $PRC = EE_Registry::instance()->load_model('Price')->get_one_by_ID($prc['PRC_ID']);
1402
                // update this price with new values
1403
                foreach ($PRC_values as $field => $newprc) {
1404
                    $PRC->set($field, $newprc);
1405
                }
1406
                $PRC->save();
1407
            }
1408
            $ticket->_add_relation_to($PRC, 'Price');
1409
        }
1410
    }
1411
1412
1413
    /**
1414
     * Add in our autosave ajax handlers
1415
     *
1416
     */
1417
    protected function _ee_autosave_create_new()
1418
    {
1419
    }
1420
1421
1422
    /**
1423
     * More autosave handlers.
1424
     */
1425
    protected function _ee_autosave_edit()
1426
    {
1427
        return; // TEMPORARILY EXITING CAUSE THIS IS A TODO
1428
    }
1429
1430
1431
    /**
1432
     *    _generate_publish_box_extra_content
1433
     */
1434
    private function _generate_publish_box_extra_content()
1435
    {
1436
        // load formatter helper
1437
        // args for getting related registrations
1438
        $approved_query_args = array(
1439
            array(
1440
                'REG_deleted' => 0,
1441
                'STS_ID'      => EEM_Registration::status_id_approved,
1442
            ),
1443
        );
1444
        $not_approved_query_args = array(
1445
            array(
1446
                'REG_deleted' => 0,
1447
                'STS_ID'      => EEM_Registration::status_id_not_approved,
1448
            ),
1449
        );
1450
        $pending_payment_query_args = array(
1451
            array(
1452
                'REG_deleted' => 0,
1453
                'STS_ID'      => EEM_Registration::status_id_pending_payment,
1454
            ),
1455
        );
1456
        // publish box
1457
        $publish_box_extra_args = array(
1458
            'view_approved_reg_url'        => add_query_arg(
1459
                array(
1460
                    'action'      => 'default',
1461
                    'event_id'    => $this->_cpt_model_obj->ID(),
1462
                    '_reg_status' => EEM_Registration::status_id_approved,
1463
                ),
1464
                REG_ADMIN_URL
1465
            ),
1466
            'view_not_approved_reg_url'    => add_query_arg(
1467
                array(
1468
                    'action'      => 'default',
1469
                    'event_id'    => $this->_cpt_model_obj->ID(),
1470
                    '_reg_status' => EEM_Registration::status_id_not_approved,
1471
                ),
1472
                REG_ADMIN_URL
1473
            ),
1474
            'view_pending_payment_reg_url' => add_query_arg(
1475
                array(
1476
                    'action'      => 'default',
1477
                    'event_id'    => $this->_cpt_model_obj->ID(),
1478
                    '_reg_status' => EEM_Registration::status_id_pending_payment,
1479
                ),
1480
                REG_ADMIN_URL
1481
            ),
1482
            'approved_regs'                => $this->_cpt_model_obj->count_related(
1483
                'Registration',
1484
                $approved_query_args
1485
            ),
1486
            'not_approved_regs'            => $this->_cpt_model_obj->count_related(
1487
                'Registration',
1488
                $not_approved_query_args
1489
            ),
1490
            'pending_payment_regs'         => $this->_cpt_model_obj->count_related(
1491
                'Registration',
1492
                $pending_payment_query_args
1493
            ),
1494
            'misc_pub_section_class'       => apply_filters(
1495
                'FHEE_Events_Admin_Page___generate_publish_box_extra_content__misc_pub_section_class',
1496
                'misc-pub-section'
1497
            ),
1498
        );
1499
        ob_start();
1500
        do_action(
1501
            'AHEE__Events_Admin_Page___generate_publish_box_extra_content__event_editor_overview_add',
1502
            $this->_cpt_model_obj
1503
        );
1504
        $publish_box_extra_args['event_editor_overview_add'] = ob_get_clean();
1505
        // load template
1506
        EEH_Template::display_template(
1507
            EVENTS_TEMPLATE_PATH . 'event_publish_box_extras.template.php',
1508
            $publish_box_extra_args
1509
        );
1510
    }
1511
1512
1513
    /**
1514
     * @return EE_Event
1515
     */
1516
    public function get_event_object()
1517
    {
1518
        return $this->_cpt_model_obj;
1519
    }
1520
1521
1522
1523
1524
    /** METABOXES * */
1525
    /**
1526
     * _register_event_editor_meta_boxes
1527
     * add all metaboxes related to the event_editor
1528
     *
1529
     * @return void
1530
     */
1531
    protected function _register_event_editor_meta_boxes()
1532
    {
1533
        $this->verify_cpt_object();
1534
        add_meta_box(
1535
            'espresso_event_editor_tickets',
1536
            esc_html__('Event Datetime & Ticket', 'event_espresso'),
1537
            array($this, 'ticket_metabox'),
1538
            $this->page_slug,
1539
            'normal',
1540
            'high'
1541
        );
1542
        add_meta_box(
1543
            'espresso_event_editor_event_options',
1544
            esc_html__('Event Registration Options', 'event_espresso'),
1545
            array($this, 'registration_options_meta_box'),
1546
            $this->page_slug,
1547
            'side',
1548
            'default'
1549
        );
1550
        // NOTE: if you're looking for other metaboxes in here,
1551
        // where a metabox has a related management page in the admin
1552
        // you will find it setup in the related management page's "_Hooks" file.
1553
        // i.e. messages metabox is found in "espresso_events_Messages_Hooks.class.php".
1554
    }
1555
1556
1557
    /**
1558
     * @throws DomainException
1559
     * @throws EE_Error
1560
     */
1561
    public function ticket_metabox()
1562
    {
1563
        $existing_datetime_ids = $existing_ticket_ids = array();
1564
        // defaults for template args
1565
        $template_args = array(
1566
            'existing_datetime_ids'    => '',
1567
            'event_datetime_help_link' => '',
1568
            'ticket_options_help_link' => '',
1569
            'time'                     => null,
1570
            'ticket_rows'              => '',
1571
            'existing_ticket_ids'      => '',
1572
            'total_ticket_rows'        => 1,
1573
            'ticket_js_structure'      => '',
1574
            'trash_icon'               => 'ee-lock-icon',
1575
            'disabled'                 => '',
1576
        );
1577
        $event_id = is_object($this->_cpt_model_obj) ? $this->_cpt_model_obj->ID() : null;
1578
        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
1579
        /**
1580
         * 1. Start with retrieving Datetimes
1581
         * 2. Fore each datetime get related tickets
1582
         * 3. For each ticket get related prices
1583
         */
1584
        $times = EE_Registry::instance()->load_model('Datetime')->get_all_event_dates($event_id);
1585
        /** @type EE_Datetime $first_datetime */
1586
        $first_datetime = reset($times);
1587
        // do we get related tickets?
1588
        if ($first_datetime instanceof EE_Datetime
1589
            && $first_datetime->ID() !== 0
1590
        ) {
1591
            $existing_datetime_ids[] = $first_datetime->get('DTT_ID');
1592
            $template_args['time'] = $first_datetime;
1593
            $related_tickets = $first_datetime->tickets(
1594
                array(
1595
                    array('OR' => array('TKT_deleted' => 1, 'TKT_deleted*' => 0)),
1596
                    'default_where_conditions' => 'none',
1597
                )
1598
            );
1599
            if (! empty($related_tickets)) {
1600
                $template_args['total_ticket_rows'] = count($related_tickets);
1601
                $row = 0;
1602
                foreach ($related_tickets as $ticket) {
1603
                    $existing_ticket_ids[] = $ticket->get('TKT_ID');
1604
                    $template_args['ticket_rows'] .= $this->_get_ticket_row($ticket, false, $row);
1605
                    $row++;
1606
                }
1607 View Code Duplication
            } else {
1608
                $template_args['total_ticket_rows'] = 1;
1609
                /** @type EE_Ticket $ticket */
1610
                $ticket = EE_Registry::instance()->load_model('Ticket')->create_default_object();
1611
                $template_args['ticket_rows'] .= $this->_get_ticket_row($ticket);
1612
            }
1613 View Code Duplication
        } else {
1614
            $template_args['time'] = $times[0];
1615
            /** @type EE_Ticket $ticket */
1616
            $ticket = EE_Registry::instance()->load_model('Ticket')->get_all_default_tickets();
1617
            $template_args['ticket_rows'] .= $this->_get_ticket_row($ticket[1]);
1618
            // NOTE: we're just sending the first default row
1619
            // (decaf can't manage default tickets so this should be sufficient);
1620
        }
1621
        $template_args['event_datetime_help_link'] = $this->_get_help_tab_link(
1622
            'event_editor_event_datetimes_help_tab'
1623
        );
1624
        $template_args['ticket_options_help_link'] = $this->_get_help_tab_link('ticket_options_info');
1625
        $template_args['existing_datetime_ids'] = implode(',', $existing_datetime_ids);
1626
        $template_args['existing_ticket_ids'] = implode(',', $existing_ticket_ids);
1627
        $template_args['ticket_js_structure'] = $this->_get_ticket_row(
1628
            EE_Registry::instance()->load_model('Ticket')->create_default_object(),
1629
            true
1630
        );
1631
        $template = apply_filters(
1632
            'FHEE__Events_Admin_Page__ticket_metabox__template',
1633
            EVENTS_TEMPLATE_PATH . 'event_tickets_metabox_main.template.php'
1634
        );
1635
        EEH_Template::display_template($template, $template_args);
1636
    }
1637
1638
1639
    /**
1640
     * Setup an individual ticket form for the decaf event editor page
1641
     *
1642
     * @access private
1643
     * @param  EE_Ticket $ticket   the ticket object
1644
     * @param  boolean   $skeleton whether we're generating a skeleton for js manipulation
1645
     * @param int        $row
1646
     * @return string generated html for the ticket row.
1647
     */
1648
    private function _get_ticket_row($ticket, $skeleton = false, $row = 0)
1649
    {
1650
        $template_args = array(
1651
            'tkt_status_class'    => ' tkt-status-' . $ticket->ticket_status(),
1652
            'tkt_archive_class'   => $ticket->ticket_status() === EE_Ticket::archived && ! $skeleton ? ' tkt-archived'
1653
                : '',
1654
            'ticketrow'           => $skeleton ? 'TICKETNUM' : $row,
1655
            'TKT_ID'              => $ticket->get('TKT_ID'),
1656
            'TKT_name'            => $ticket->get('TKT_name'),
1657
            'TKT_start_date'      => $skeleton ? '' : $ticket->get_date('TKT_start_date', 'Y-m-d h:i a'),
1658
            'TKT_end_date'        => $skeleton ? '' : $ticket->get_date('TKT_end_date', 'Y-m-d h:i a'),
1659
            'TKT_is_default'      => $ticket->get('TKT_is_default'),
1660
            'TKT_qty'             => $ticket->get_pretty('TKT_qty', 'input'),
1661
            'edit_ticketrow_name' => $skeleton ? 'TICKETNAMEATTR' : 'edit_tickets',
1662
            'TKT_sold'            => $skeleton ? 0 : $ticket->get('TKT_sold'),
1663
            'trash_icon'          => ($skeleton || (! empty($ticket) && ! $ticket->get('TKT_deleted')))
1664
                                     && (! empty($ticket) && $ticket->get('TKT_sold') === 0)
1665
                ? 'trash-icon dashicons dashicons-post-trash clickable' : 'ee-lock-icon',
1666
            'disabled'            => $skeleton || (! empty($ticket) && ! $ticket->get('TKT_deleted')) ? ''
1667
                : ' disabled=disabled',
1668
        );
1669
        $price = $ticket->ID() !== 0
0 ignored issues
show
Unused Code Bug introduced by
The strict comparison !== seems to always evaluate to true as the types of $ticket->ID() (string) and 0 (integer) can never be identical. Maybe you want to use a loose comparison != instead?
Loading history...
1670
            ? $ticket->get_first_related('Price', array('default_where_conditions' => 'none'))
1671
            : EE_Registry::instance()->load_model('Price')->create_default_object();
1672
        $price_args = array(
1673
            'price_currency_symbol' => EE_Registry::instance()->CFG->currency->sign,
1674
            'PRC_amount'            => $price->get('PRC_amount'),
1675
            'PRT_ID'                => $price->get('PRT_ID'),
1676
            'PRC_ID'                => $price->get('PRC_ID'),
1677
            'PRC_is_default'        => $price->get('PRC_is_default'),
1678
        );
1679
        // make sure we have default start and end dates if skeleton
1680
        // handle rows that should NOT be empty
1681
        if (empty($template_args['TKT_start_date'])) {
1682
            // if empty then the start date will be now.
1683
            $template_args['TKT_start_date'] = date('Y-m-d h:i a', current_time('timestamp'));
1684
        }
1685
        if (empty($template_args['TKT_end_date'])) {
1686
            // get the earliest datetime (if present);
1687
            $earliest_dtt = $this->_cpt_model_obj->ID() > 0
1688
                ? $this->_cpt_model_obj->get_first_related(
1689
                    'Datetime',
1690
                    array('order_by' => array('DTT_EVT_start' => 'ASC'))
1691
                )
1692
                : null;
1693
            if (! empty($earliest_dtt)) {
1694
                $template_args['TKT_end_date'] = $earliest_dtt->get_datetime('DTT_EVT_start', 'Y-m-d', 'h:i a');
1695 View Code Duplication
            } else {
1696
                $template_args['TKT_end_date'] = date(
1697
                    'Y-m-d h:i a',
1698
                    mktime(0, 0, 0, date("m"), date("d") + 7, date("Y"))
1699
                );
1700
            }
1701
        }
1702
        $template_args = array_merge($template_args, $price_args);
1703
        $template = apply_filters(
1704
            'FHEE__Events_Admin_Page__get_ticket_row__template',
1705
            EVENTS_TEMPLATE_PATH . 'event_tickets_metabox_ticket_row.template.php',
1706
            $ticket
1707
        );
1708
        return EEH_Template::display_template($template, $template_args, true);
1709
    }
1710
1711
1712
    /**
1713
     * @throws DomainException
1714
     */
1715
    public function registration_options_meta_box()
1716
    {
1717
        $yes_no_values = array(
1718
            array('id' => true, 'text' => esc_html__('Yes', 'event_espresso')),
1719
            array('id' => false, 'text' => esc_html__('No', 'event_espresso')),
1720
        );
1721
        $default_reg_status_values = EEM_Registration::reg_status_array(
1722
            array(
1723
                EEM_Registration::status_id_cancelled,
1724
                EEM_Registration::status_id_declined,
1725
                EEM_Registration::status_id_incomplete,
1726
            ),
1727
            true
1728
        );
1729
        // $template_args['is_active_select'] = EEH_Form_Fields::select_input('is_active', $yes_no_values, $this->_cpt_model_obj->is_active());
1730
        $template_args['_event'] = $this->_cpt_model_obj;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$template_args was never initialized. Although not strictly required by PHP, it is generally a good practice to add $template_args = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
1731
        $template_args['active_status'] = $this->_cpt_model_obj->pretty_active_status(false);
1732
        $template_args['additional_limit'] = $this->_cpt_model_obj->additional_limit();
1733
        $template_args['default_registration_status'] = EEH_Form_Fields::select_input(
1734
            'default_reg_status',
1735
            $default_reg_status_values,
1736
            $this->_cpt_model_obj->default_registration_status()
0 ignored issues
show
Bug introduced by
It seems like $this->_cpt_model_obj->d...t_registration_status() targeting EE_Event::default_registration_status() can also be of type boolean; however, EEH_Form_Fields::select_input() does only seem to accept string, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
1737
        );
1738
        $template_args['display_description'] = EEH_Form_Fields::select_input(
1739
            'display_desc',
1740
            $yes_no_values,
1741
            $this->_cpt_model_obj->display_description()
1742
        );
1743
        $template_args['display_ticket_selector'] = EEH_Form_Fields::select_input(
1744
            'display_ticket_selector',
1745
            $yes_no_values,
1746
            $this->_cpt_model_obj->display_ticket_selector(),
1747
            '',
1748
            '',
1749
            false
1750
        );
1751
        $template_args['additional_registration_options'] = apply_filters(
1752
            'FHEE__Events_Admin_Page__registration_options_meta_box__additional_registration_options',
1753
            '',
1754
            $template_args,
1755
            $yes_no_values,
1756
            $default_reg_status_values
1757
        );
1758
        EEH_Template::display_template(
1759
            EVENTS_TEMPLATE_PATH . 'event_registration_options.template.php',
1760
            $template_args
1761
        );
1762
    }
1763
1764
1765
    /**
1766
     * _get_events()
1767
     * This method simply returns all the events (for the given _view and paging)
1768
     *
1769
     * @access public
1770
     * @param int  $per_page     count of items per page (20 default);
1771
     * @param int  $current_page what is the current page being viewed.
1772
     * @param bool $count        if TRUE then we just return a count of ALL events matching the given _view.
1773
     *                           If FALSE then we return an array of event objects
1774
     *                           that match the given _view and paging parameters.
1775
     * @return array an array of event objects.
1776
     */
1777
    public function get_events($per_page = 10, $current_page = 1, $count = false)
1778
    {
1779
        $EEME = $this->_event_model();
1780
        $offset = ($current_page - 1) * $per_page;
1781
        $limit = $count ? null : $offset . ',' . $per_page;
1782
        $orderby = isset($this->_req_data['orderby']) ? $this->_req_data['orderby'] : 'EVT_ID';
1783
        $order = isset($this->_req_data['order']) ? $this->_req_data['order'] : "DESC";
1784
        if (isset($this->_req_data['month_range'])) {
1785
            $pieces = explode(' ', $this->_req_data['month_range'], 3);
1786
            // simulate the FIRST day of the month, that fixes issues for months like February
1787
            // where PHP doesn't know what to assume for date.
1788
            // @see https://events.codebasehq.com/projects/event-espresso/tickets/10437
1789
            $month_r = ! empty($pieces[0]) ? date('m', \EEH_DTT_Helper::first_of_month_timestamp($pieces[0])) : '';
1790
            $year_r = ! empty($pieces[1]) ? $pieces[1] : '';
1791
        }
1792
        $where = array();
1793
        $status = isset($this->_req_data['status']) ? $this->_req_data['status'] : null;
1794
        // determine what post_status our condition will have for the query.
1795
        switch ($status) {
1796
            case 'month':
1797
            case 'today':
1798
            case null:
1799
            case 'all':
1800
                break;
1801
            case 'draft':
1802
                $where['status'] = array('IN', array('draft', 'auto-draft'));
1803
                break;
1804
            default:
1805
                $where['status'] = $status;
1806
        }
1807
        // categories?
1808
        $category = isset($this->_req_data['EVT_CAT']) && $this->_req_data['EVT_CAT'] > 0
1809
            ? $this->_req_data['EVT_CAT'] : null;
1810
        if (! empty($category)) {
1811
            $where['Term_Taxonomy.taxonomy'] = EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY;
1812
            $where['Term_Taxonomy.term_id'] = $category;
1813
        }
1814
        // date where conditions
1815
        $start_formats = EEM_Datetime::instance()->get_formats_for('DTT_EVT_start');
1816
        if (isset($this->_req_data['month_range']) && $this->_req_data['month_range'] != '') {
1817
            $DateTime = new DateTime(
1818
                $year_r . '-' . $month_r . '-01 00:00:00',
1819
                new DateTimeZone(EEM_Datetime::instance()->get_timezone())
1820
            );
1821
            $start = $DateTime->format(implode(' ', $start_formats));
1822
            $end = $DateTime->setDate(
1823
                $year_r,
1824
                $month_r,
1825
                $DateTime
1826
                    ->format('t')
1827
            )->setTime(23, 59, 59)
1828
                            ->format(implode(' ', $start_formats));
1829
            $where['Datetime.DTT_EVT_start'] = array('BETWEEN', array($start, $end));
1830
        } elseif (isset($this->_req_data['status']) && $this->_req_data['status'] == 'today') {
1831
            $DateTime = new DateTime('now', new DateTimeZone(EEM_Event::instance()->get_timezone()));
1832
            $start = $DateTime->setTime(0, 0, 0)->format(implode(' ', $start_formats));
1833
            $end = $DateTime->setTime(23, 59, 59)->format(implode(' ', $start_formats));
1834
            $where['Datetime.DTT_EVT_start'] = array('BETWEEN', array($start, $end));
1835
        } elseif (isset($this->_req_data['status']) && $this->_req_data['status'] == 'month') {
1836
            $now = date('Y-m-01');
1837
            $DateTime = new DateTime($now, new DateTimeZone(EEM_Event::instance()->get_timezone()));
1838
            $start = $DateTime->setTime(0, 0, 0)->format(implode(' ', $start_formats));
1839
            $end = $DateTime->setDate(date('Y'), date('m'), $DateTime->format('t'))
1840
                            ->setTime(23, 59, 59)
1841
                            ->format(implode(' ', $start_formats));
1842
            $where['Datetime.DTT_EVT_start'] = array('BETWEEN', array($start, $end));
1843
        }
1844 View Code Duplication
        if (! EE_Registry::instance()->CAP->current_user_can('ee_read_others_events', 'get_events')) {
1845
            $where['EVT_wp_user'] = get_current_user_id();
1846
        } else {
1847
            if (! isset($where['status'])) {
1848
                if (! EE_Registry::instance()->CAP->current_user_can('ee_read_private_events', 'get_events')) {
1849
                    $where['OR'] = array(
1850
                        'status*restrict_private' => array('!=', 'private'),
1851
                        'AND'                     => array(
1852
                            'status*inclusive' => array('=', 'private'),
1853
                            'EVT_wp_user'      => get_current_user_id(),
1854
                        ),
1855
                    );
1856
                }
1857
            }
1858
        }
1859
        if (isset($this->_req_data['EVT_wp_user'])) {
1860
            if ($this->_req_data['EVT_wp_user'] != get_current_user_id()
1861
                && EE_Registry::instance()->CAP->current_user_can('ee_read_others_events', 'get_events')
1862
            ) {
1863
                $where['EVT_wp_user'] = $this->_req_data['EVT_wp_user'];
1864
            }
1865
        }
1866
        // search query handling
1867
        if (isset($this->_req_data['s'])) {
1868
            $search_string = '%' . $this->_req_data['s'] . '%';
1869
            $where['OR'] = array(
1870
                'EVT_name'       => array('LIKE', $search_string),
1871
                'EVT_desc'       => array('LIKE', $search_string),
1872
                'EVT_short_desc' => array('LIKE', $search_string),
1873
            );
1874
        }
1875
        // filter events by venue.
1876
        if (isset($this->_req_data['venue']) && ! empty($this->_req_data['venue'])) {
1877
            $where['Venue.VNU_ID'] = absint($this->_req_data['venue']);
1878
        }
1879
        $where = apply_filters('FHEE__Events_Admin_Page__get_events__where', $where, $this->_req_data);
1880
        $query_params = apply_filters(
1881
            'FHEE__Events_Admin_Page__get_events__query_params',
1882
            array(
1883
                $where,
1884
                'limit'    => $limit,
1885
                'order_by' => $orderby,
1886
                'order'    => $order,
1887
                'group_by' => 'EVT_ID',
1888
            ),
1889
            $this->_req_data
1890
        );
1891
        // let's first check if we have special requests coming in.
1892
        if (isset($this->_req_data['active_status'])) {
1893
            switch ($this->_req_data['active_status']) {
1894
                case 'upcoming':
1895
                    return $EEME->get_upcoming_events($query_params, $count);
1896
                    break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
1897
                case 'expired':
1898
                    return $EEME->get_expired_events($query_params, $count);
1899
                    break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
1900
                case 'active':
1901
                    return $EEME->get_active_events($query_params, $count);
1902
                    break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
1903
                case 'inactive':
1904
                    return $EEME->get_inactive_events($query_params, $count);
1905
                    break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
1906
            }
1907
        }
1908
1909
        $events = $count ? $EEME->count(array($where), 'EVT_ID', true) : $EEME->get_all($query_params);
1910
        return $events;
1911
    }
1912
1913
1914
    /**
1915
     * handling for WordPress CPT actions (trash, restore, delete)
1916
     *
1917
     * @param string $post_id
1918
     */
1919
    public function trash_cpt_item($post_id)
1920
    {
1921
        $this->_req_data['EVT_ID'] = $post_id;
1922
        $this->_trash_or_restore_event('trash', false);
1923
    }
1924
1925
1926
    /**
1927
     * @param string $post_id
1928
     */
1929
    public function restore_cpt_item($post_id)
1930
    {
1931
        $this->_req_data['EVT_ID'] = $post_id;
1932
        $this->_trash_or_restore_event('draft', false);
1933
    }
1934
1935
1936
    /**
1937
     * @param string $post_id
1938
     */
1939
    public function delete_cpt_item($post_id)
1940
    {
1941
        throw new EE_Error(esc_html__('Please contact Event Espresso support with the details of the steps taken to produce this error.', 'event_espresso'));
1942
        $this->_req_data['EVT_ID'] = $post_id;
1943
        $this->_delete_event();
1944
    }
1945
1946
1947
    /**
1948
     * _trash_or_restore_event
1949
     *
1950
     * @access protected
1951
     * @param  string $event_status
1952
     * @param bool    $redirect_after
1953
     */
1954 View Code Duplication
    protected function _trash_or_restore_event($event_status = 'trash', $redirect_after = true)
1955
    {
1956
        // determine the event id and set to array.
1957
        $EVT_ID = isset($this->_req_data['EVT_ID']) ? absint($this->_req_data['EVT_ID']) : false;
1958
        // loop thru events
1959
        if ($EVT_ID) {
1960
            // clean status
1961
            $event_status = sanitize_key($event_status);
1962
            // grab status
1963
            if (! empty($event_status)) {
1964
                $success = $this->_change_event_status($EVT_ID, $event_status);
1965
            } else {
1966
                $success = false;
1967
                $msg = esc_html__(
1968
                    'An error occurred. The event could not be moved to the trash because a valid event status was not not supplied.',
1969
                    'event_espresso'
1970
                );
1971
                EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
1972
            }
1973
        } else {
1974
            $success = false;
1975
            $msg = esc_html__(
1976
                'An error occurred. The event could not be moved to the trash because a valid event ID was not not supplied.',
1977
                'event_espresso'
1978
            );
1979
            EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
1980
        }
1981
        $action = $event_status == 'trash' ? 'moved to the trash' : 'restored from the trash';
1982
        if ($redirect_after) {
1983
            $this->_redirect_after_action($success, 'Event', $action, array('action' => 'default'));
1984
        }
1985
    }
1986
1987
1988
    /**
1989
     * _trash_or_restore_events
1990
     *
1991
     * @access protected
1992
     * @param  string $event_status
1993
     * @return void
1994
     */
1995 View Code Duplication
    protected function _trash_or_restore_events($event_status = 'trash')
1996
    {
1997
        // clean status
1998
        $event_status = sanitize_key($event_status);
1999
        // grab status
2000
        if (! empty($event_status)) {
2001
            $success = true;
2002
            // determine the event id and set to array.
2003
            $EVT_IDs = isset($this->_req_data['EVT_IDs']) ? (array) $this->_req_data['EVT_IDs'] : array();
2004
            // loop thru events
2005
            foreach ($EVT_IDs as $EVT_ID) {
2006
                if ($EVT_ID = absint($EVT_ID)) {
2007
                    $results = $this->_change_event_status($EVT_ID, $event_status);
2008
                    $success = $results !== false ? $success : false;
2009
                } else {
2010
                    $msg = sprintf(
2011
                        esc_html__(
2012
                            'An error occurred. Event #%d could not be moved to the trash because a valid event ID was not not supplied.',
2013
                            'event_espresso'
2014
                        ),
2015
                        $EVT_ID
2016
                    );
2017
                    EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2018
                    $success = false;
2019
                }
2020
            }
2021
        } else {
2022
            $success = false;
2023
            $msg = esc_html__(
2024
                'An error occurred. The event could not be moved to the trash because a valid event status was not not supplied.',
2025
                'event_espresso'
2026
            );
2027
            EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2028
        }
2029
        // in order to force a pluralized result message we need to send back a success status greater than 1
2030
        $success = $success ? 2 : false;
2031
        $action = $event_status == 'trash' ? 'moved to the trash' : 'restored from the trash';
2032
        $this->_redirect_after_action($success, 'Events', $action, array('action' => 'default'));
2033
    }
2034
2035
2036
    /**
2037
     * _trash_or_restore_events
2038
     *
2039
     * @access  private
2040
     * @param  int    $EVT_ID
2041
     * @param  string $event_status
2042
     * @return bool
2043
     */
2044 View Code Duplication
    private function _change_event_status($EVT_ID = 0, $event_status = '')
2045
    {
2046
        // grab event id
2047
        if (! $EVT_ID) {
2048
            $msg = esc_html__(
2049
                'An error occurred. No Event ID or an invalid Event ID was received.',
2050
                'event_espresso'
2051
            );
2052
            EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2053
            return false;
2054
        }
2055
        $this->_cpt_model_obj = EEM_Event::instance()->get_one_by_ID($EVT_ID);
2056
        // clean status
2057
        $event_status = sanitize_key($event_status);
2058
        // grab status
2059
        if (empty($event_status)) {
2060
            $msg = esc_html__(
2061
                'An error occurred. No Event Status or an invalid Event Status was received.',
2062
                'event_espresso'
2063
            );
2064
            EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2065
            return false;
2066
        }
2067
        // was event trashed or restored ?
2068
        switch ($event_status) {
2069
            case 'draft':
2070
                $action = 'restored from the trash';
2071
                $hook = 'AHEE_event_restored_from_trash';
2072
                break;
2073
            case 'trash':
2074
                $action = 'moved to the trash';
2075
                $hook = 'AHEE_event_moved_to_trash';
2076
                break;
2077
            default:
2078
                $action = 'updated';
2079
                $hook = false;
2080
        }
2081
        // use class to change status
2082
        $this->_cpt_model_obj->set_status($event_status);
2083
        $success = $this->_cpt_model_obj->save();
2084
        if ($success === false) {
2085
            $msg = sprintf(esc_html__('An error occurred. The event could not be %s.', 'event_espresso'), $action);
2086
            EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2087
            return false;
2088
        }
2089
        if ($hook) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $hook of type string|false is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
2090
            do_action($hook);
2091
        }
2092
        return true;
2093
    }
2094
2095
2096
    /**
2097
     * _delete_event
2098
     *
2099
     * @access protected
2100
     * @param bool $redirect_after
0 ignored issues
show
Bug introduced by
There is no parameter named $redirect_after. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
2101
     */
2102
    protected function _delete_event()
2103
    {
2104
        $this->generateDeletionPreview(isset($this->_req_data['EVT_ID']) ? $this->_req_data['EVT_ID'] : array());
2105
    }
2106
2107
2108
    /**
2109
     * _delete_events
2110
     *
2111
     * @access protected
2112
     * @return void
2113
     */
2114
    protected function _delete_events()
2115
    {
2116
        $this->generateDeletionPreview(isset($this->_req_data['EVT_IDs']) ? (array) $this->_req_data['EVT_IDs'] : array());
2117
    }
2118
2119
    protected function generateDeletionPreview($event_ids)
2120
    {
2121
        $event_ids = (array) $event_ids;
2122
        // Set a code we can use to reference this deletion task in the batch jobs and preview page.
2123
        $deletion_job_code = wp_generate_password(6, false);
2124
        $return_url = EE_Admin_Page::add_query_args_and_nonce(
2125
            [
2126
                'action' => 'preview_deletion',
2127
                'deletion_job_code' => $deletion_job_code,
2128
            ],
2129
            $this->_admin_base_url
2130
        );
2131
        foreach ($event_ids as $EVT_ID) {
0 ignored issues
show
Bug introduced by
The expression $event_ids of type array|integer is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
2132
            $event_ids = (int) $EVT_ID;
2133
        }
2134
2135
        EEH_URL::safeRedirectAndExit(
2136
            EE_Admin_Page::add_query_args_and_nonce(
2137
                array(
2138
                    'page'        => 'espresso_batch',
2139
                    'batch'       => EED_Batch::batch_job,
2140
                    'EVT_IDs[]'      => $event_ids,
2141
                    'deletion_job_code' => $deletion_job_code,
2142
                    'job_handler' => urlencode('EventEspressoBatchRequest\JobHandlers\PreviewEventDeletion'),
2143
                    'return_url'  => urlencode($return_url),
2144
                ),
2145
                admin_url()
2146
            )
2147
        );
2148
    }
2149
2150
    /**
2151
     * Checks for a POST submission
2152
     * @since $VID:$
2153
     */
2154
    protected function confirmDeletion()
2155
    {
2156
        $deletion_job_code = isset($this->_req_data['deletion_job_code']) ? $this->_req_data['deletion_job_code'] : '';
2157
        $this->models_and_ids_to_delete = $this->getModelsAndIdsToDelete($deletion_job_code);
2158
        $this->form = new ConfirmEventDeletionForm($this->models_and_ids_to_delete['Event']);
2159
        if ($_SERVER['REQUEST_METHOD'] == 'POST') {
2160
            // Initialize the form from the request, and check if its valid.
2161
            $this->form->receive_form_submission($this->_req_data);
2162
            if($this->form->is_valid()){
2163
                // Redirect the user to the deletion batch job.
2164
                EEH_URL::safeRedirectAndExit(
2165
                    EE_Admin_Page::add_query_args_and_nonce(
2166
                        array(
2167
                            'page'        => 'espresso_batch',
2168
                            'batch'       => EED_Batch::batch_job,
2169
                            'deletion_job_code' => $deletion_job_code,
2170
                            'job_handler' => urlencode('EventEspressoBatchRequest\JobHandlers\ExecuteBatchDeletion'),
2171
                            'return_url'  => urlencode(
2172
                                add_query_arg(
2173
                                    [
2174
                                        'status' => 'trash'
2175
                                    ],
2176
                                    EVENTS_ADMIN_URL
2177
                                )
2178
                            )
2179
                        ),
2180
                        admin_url()
2181
                    )
2182
                );
2183
            } else {
2184
                EE_Error::add_error(
2185
                    __(
2186
                        'Data was not deleted because you did not complete the form correctly.',
2187
                        'event_espresso'
2188
                    ),
2189
                    __FILE__,
2190
                    __FUNCTION__,
2191
                    __LINE__
2192
                );
2193
            }
2194
        }
2195
    }
2196
2197
    /**
2198
     * Uses the querystring and job option to figure out what we intend to delete.
2199
     * @since $VID:$
2200
     * @return array top-level keys are model names, and their values are arrays of IDs.
2201
     * @throws EE_Error
2202
     * @throws InvalidArgumentException
2203
     * @throws InvalidDataTypeException
2204
     * @throws InvalidInterfaceException
2205
     * @throws ReflectionException
2206
     * @throws UnexpectedEntityException
2207
     */
2208
    protected function getModelsAndIdsToDelete($deletion_job_code)
2209
    {
2210
        if( ! $deletion_job_code){
2211
            throw new Exception(esc_html__('We aren’t sure which job you are performing. Please press back in your browser and try again.', 'event_espresso'));
2212
        }
2213
        $deletion_data = get_option('ee_deletion_' . $deletion_job_code, []);
2214
2215
        $models_and_ids_to_delete = [];
2216 View Code Duplication
        foreach ($deletion_data as $root) {
2217
            if (! $root instanceof ModelObjNode) {
2218
                throw new UnexpectedEntityException($root, 'ModelObjNode');
2219
            }
2220
            $models_and_ids_to_delete = array_replace_recursive($models_and_ids_to_delete, $root->getIds());
2221
        }
2222
        return $models_and_ids_to_delete;
2223
    }
2224
2225
    /**
2226
     * A page for users to preview what exactly will be deleted, and confirm they want to delete it.
2227
     * @since $VID:$
2228
     */
2229
    protected function previewDeletion()
2230
    {
2231
        $deletion_job_code = isset($this->_req_data['deletion_job_code']) ? $this->_req_data['deletion_job_code'] : '';
2232
        if(! $this->form instanceof ConfirmEventDeletionForm){
2233
            $this->models_and_ids_to_delete = $this->getModelsAndIdsToDelete($deletion_job_code);
2234
            $this->form = new ConfirmEventDeletionForm($this->models_and_ids_to_delete['Event']);
2235
        }
2236
        // If they're not in debug mode, don't list all model objectss that will be deleted. They'll just be confused.
2237
        if(! WP_DEBUG){
2238
            $models_to_mention = [
2239
                'Event',
2240
                'Datetime',
2241
                'Ticket',
2242
                'Registration'
2243
            ];
2244
2245
            $this->models_and_ids_to_delete = array_intersect_key($this->models_and_ids_to_delete, array_flip($models_to_mention));
2246
        };
2247
        $confirm_deletion_args = [
2248
            'action' => 'confirm_deletion',
2249
            'deletion_job_code' => $deletion_job_code
2250
        ];
2251
2252
        $this->_template_args['admin_page_content'] = EEH_Template::display_template(
2253
            EVENTS_TEMPLATE_PATH . 'event_preview_deletion.template.php',
2254
            [
2255
                'form_url' => EE_Admin_Page::add_query_args_and_nonce(
2256
                    $confirm_deletion_args,
2257
                    $this->admin_base_url()
2258
                ),
2259
                'form' => $this->form,
2260
                'models_and_ids_to_delete' => $this->models_and_ids_to_delete,
2261
                'quantity_to_preview' => 20
2262
            ],
2263
            true
2264
        );
2265
        $this->display_admin_page_with_no_sidebar();
2266
    }
2267
2268
    /**
2269
     * _permanently_delete_event
2270
     *
2271
     * @access  private
2272
     * @param  int $EVT_ID
2273
     * @return bool
2274
     */
2275
    private function _permanently_delete_event($EVT_ID = 0)
2276
    {
2277
        // grab event id
2278
        if (! $EVT_ID) {
2279
            $msg = esc_html__(
2280
                'An error occurred. No Event ID or an invalid Event ID was received.',
2281
                'event_espresso'
2282
            );
2283
            EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2284
            return false;
2285
        }
2286
        if (! $this->_cpt_model_obj instanceof EE_Event
2287
            || $this->_cpt_model_obj->ID() !== $EVT_ID
2288
        ) {
2289
            $this->_cpt_model_obj = EEM_Event::instance()->get_one_by_ID($EVT_ID);
2290
        }
2291
        if (! $this->_cpt_model_obj instanceof EE_Event) {
2292
            return false;
2293
        }
2294
        // need to delete related tickets and prices first.
2295
        $datetimes = $this->_cpt_model_obj->get_many_related('Datetime');
2296
        foreach ($datetimes as $datetime) {
2297
            $this->_cpt_model_obj->_remove_relation_to($datetime, 'Datetime');
2298
            $tickets = $datetime->get_many_related('Ticket');
2299
            foreach ($tickets as $ticket) {
2300
                $ticket->_remove_relation_to($datetime, 'Datetime');
2301
                $ticket->delete_related_permanently('Price');
2302
                $ticket->delete_permanently();
2303
            }
2304
            $datetime->delete();
2305
        }
2306
        // what about related venues or terms?
2307
        $venues = $this->_cpt_model_obj->get_many_related('Venue');
2308
        foreach ($venues as $venue) {
2309
            $this->_cpt_model_obj->_remove_relation_to($venue, 'Venue');
2310
        }
2311
        // any attached question groups?
2312
        $question_groups = $this->_cpt_model_obj->get_many_related('Question_Group');
2313
        if (! empty($question_groups)) {
2314
            foreach ($question_groups as $question_group) {
2315
                $this->_cpt_model_obj->_remove_relation_to($question_group, 'Question_Group');
2316
            }
2317
        }
2318
        // Message Template Groups
2319
        $this->_cpt_model_obj->_remove_relations('Message_Template_Group');
2320
        /** @type EE_Term_Taxonomy[] $term_taxonomies */
2321
        $term_taxonomies = $this->_cpt_model_obj->term_taxonomies();
2322
        foreach ($term_taxonomies as $term_taxonomy) {
2323
            $this->_cpt_model_obj->remove_relation_to_term_taxonomy($term_taxonomy);
2324
        }
2325
        $success = $this->_cpt_model_obj->delete_permanently();
2326
        // did it all go as planned ?
2327 View Code Duplication
        if ($success) {
2328
            $msg = sprintf(esc_html__('Event ID # %d has been deleted.', 'event_espresso'), $EVT_ID);
2329
            EE_Error::add_success($msg);
2330
        } else {
2331
            $msg = sprintf(
2332
                esc_html__('An error occurred. Event ID # %d could not be deleted.', 'event_espresso'),
2333
                $EVT_ID
2334
            );
2335
            EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2336
            return false;
2337
        }
2338
        do_action('AHEE__Events_Admin_Page___permanently_delete_event__after_event_deleted', $EVT_ID);
2339
        return true;
2340
    }
2341
2342
2343
    /**
2344
     * get total number of events
2345
     *
2346
     * @access public
2347
     * @return int
2348
     */
2349
    public function total_events()
2350
    {
2351
        $count = EEM_Event::instance()->count(array('caps' => 'read_admin'), 'EVT_ID', true);
2352
        return $count;
2353
    }
2354
2355
2356
    /**
2357
     * get total number of draft events
2358
     *
2359
     * @access public
2360
     * @return int
2361
     */
2362
    public function total_events_draft()
2363
    {
2364
        $where = array(
2365
            'status' => array('IN', array('draft', 'auto-draft')),
2366
        );
2367
        $count = EEM_Event::instance()->count(array($where, 'caps' => 'read_admin'), 'EVT_ID', true);
2368
        return $count;
2369
    }
2370
2371
2372
    /**
2373
     * get total number of trashed events
2374
     *
2375
     * @access public
2376
     * @return int
2377
     */
2378
    public function total_trashed_events()
2379
    {
2380
        $where = array(
2381
            'status' => 'trash',
2382
        );
2383
        $count = EEM_Event::instance()->count(array($where, 'caps' => 'read_admin'), 'EVT_ID', true);
2384
        return $count;
2385
    }
2386
2387
2388
    /**
2389
     *    _default_event_settings
2390
     *    This generates the Default Settings Tab
2391
     *
2392
     * @return void
2393
     * @throws EE_Error
2394
     */
2395 View Code Duplication
    protected function _default_event_settings()
2396
    {
2397
        $this->_set_add_edit_form_tags('update_default_event_settings');
2398
        $this->_set_publish_post_box_vars(null, false, false, null, false);
2399
        $this->_template_args['admin_page_content'] = $this->_default_event_settings_form()->get_html();
2400
        $this->display_admin_page_with_sidebar();
2401
    }
2402
2403
2404
    /**
2405
     * Return the form for event settings.
2406
     *
2407
     * @return EE_Form_Section_Proper
2408
     * @throws EE_Error
2409
     */
2410
    protected function _default_event_settings_form()
2411
    {
2412
        $registration_config = EE_Registry::instance()->CFG->registration;
2413
        $registration_stati_for_selection = EEM_Registration::reg_status_array(
2414
            // exclude
2415
            array(
2416
                EEM_Registration::status_id_cancelled,
2417
                EEM_Registration::status_id_declined,
2418
                EEM_Registration::status_id_incomplete,
2419
                EEM_Registration::status_id_wait_list,
2420
            ),
2421
            true
2422
        );
2423
        return new EE_Form_Section_Proper(
2424
            array(
2425
                'name'            => 'update_default_event_settings',
2426
                'html_id'         => 'update_default_event_settings',
2427
                'html_class'      => 'form-table',
2428
                'layout_strategy' => new EE_Admin_Two_Column_Layout(),
2429
                'subsections'     => apply_filters(
2430
                    'FHEE__Events_Admin_Page___default_event_settings_form__form_subsections',
2431
                    array(
2432
                        'default_reg_status'  => new EE_Select_Input(
2433
                            $registration_stati_for_selection,
2434
                            array(
2435
                                'default'         => isset($registration_config->default_STS_ID)
2436
                                                     && array_key_exists(
2437
                                                         $registration_config->default_STS_ID,
2438
                                                         $registration_stati_for_selection
2439
                                                     )
2440
                                    ? sanitize_text_field($registration_config->default_STS_ID)
2441
                                    : EEM_Registration::status_id_pending_payment,
2442
                                'html_label_text' => esc_html__('Default Registration Status', 'event_espresso')
2443
                                                     . EEH_Template::get_help_tab_link(
2444
                                                         'default_settings_status_help_tab'
2445
                                                     ),
2446
                                'html_help_text'  => esc_html__(
2447
                                    'This setting allows you to preselect what the default registration status setting is when creating an event.  Note that changing this setting does NOT retroactively apply it to existing events.',
2448
                                    'event_espresso'
2449
                                ),
2450
                            )
2451
                        ),
2452
                        'default_max_tickets' => new EE_Integer_Input(
2453
                            array(
2454
                                'default'         => isset($registration_config->default_maximum_number_of_tickets)
2455
                                    ? $registration_config->default_maximum_number_of_tickets
2456
                                    : EEM_Event::get_default_additional_limit(),
2457
                                'html_label_text' => esc_html__(
2458
                                    'Default Maximum Tickets Allowed Per Order:',
2459
                                    'event_espresso'
2460
                                )
2461
                                                     . EEH_Template::get_help_tab_link(
2462
                                                         'default_maximum_tickets_help_tab"'
2463
                                                     ),
2464
                                'html_help_text'  => esc_html__(
2465
                                    'This setting allows you to indicate what will be the default for the maximum number of tickets per order when creating new events.',
2466
                                    'event_espresso'
2467
                                ),
2468
                            )
2469
                        ),
2470
                    )
2471
                ),
2472
            )
2473
        );
2474
    }
2475
2476
2477
    /**
2478
     * _update_default_event_settings
2479
     *
2480
     * @access protected
2481
     * @return void
2482
     * @throws EE_Error
2483
     */
2484
    protected function _update_default_event_settings()
2485
    {
2486
        $registration_config = EE_Registry::instance()->CFG->registration;
2487
        $form = $this->_default_event_settings_form();
2488
        if ($form->was_submitted()) {
2489
            $form->receive_form_submission();
2490
            if ($form->is_valid()) {
2491
                $valid_data = $form->valid_data();
2492
                if (isset($valid_data['default_reg_status'])) {
2493
                    $registration_config->default_STS_ID = $valid_data['default_reg_status'];
2494
                }
2495
                if (isset($valid_data['default_max_tickets'])) {
2496
                    $registration_config->default_maximum_number_of_tickets = $valid_data['default_max_tickets'];
2497
                }
2498
                // update because data was valid!
2499
                EE_Registry::instance()->CFG->update_espresso_config();
2500
                EE_Error::overwrite_success();
2501
                EE_Error::add_success(
2502
                    __('Default Event Settings were updated', 'event_espresso')
2503
                );
2504
            }
2505
        }
2506
        $this->_redirect_after_action(0, '', '', array('action' => 'default_event_settings'), true);
2507
    }
2508
2509
2510
    /*************        Templates        *************/
2511 View Code Duplication
    protected function _template_settings()
2512
    {
2513
        $this->_admin_page_title = esc_html__('Template Settings (Preview)', 'event_espresso');
2514
        $this->_template_args['preview_img'] = '<img src="'
2515
                                               . EVENTS_ASSETS_URL
2516
                                               . '/images/'
2517
                                               . 'caffeinated_template_features.jpg" alt="'
2518
                                               . esc_attr__('Template Settings Preview screenshot', 'event_espresso')
2519
                                               . '" />';
2520
        $this->_template_args['preview_text'] = '<strong>'
2521
                                                . esc_html__(
2522
                                                    'Template Settings is a feature that is only available in the premium version of Event Espresso 4 which is available with a support license purchase on EventEspresso.com. Template Settings allow you to configure some of the appearance options for both the Event List and Event Details pages.',
2523
                                                    'event_espresso'
2524
                                                ) . '</strong>';
2525
        $this->display_admin_caf_preview_page('template_settings_tab');
2526
    }
2527
2528
2529
    /** Event Category Stuff **/
2530
    /**
2531
     * set the _category property with the category object for the loaded page.
2532
     *
2533
     * @access private
2534
     * @return void
2535
     */
2536
    private function _set_category_object()
2537
    {
2538
        if (isset($this->_category->id) && ! empty($this->_category->id)) {
2539
            return;
2540
        } //already have the category object so get out.
2541
        // set default category object
2542
        $this->_set_empty_category_object();
2543
        // only set if we've got an id
2544
        if (! isset($this->_req_data['EVT_CAT_ID'])) {
2545
            return;
2546
        }
2547
        $category_id = absint($this->_req_data['EVT_CAT_ID']);
2548
        $term = get_term($category_id, EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY);
2549
        if (! empty($term)) {
2550
            $this->_category->category_name = $term->name;
2551
            $this->_category->category_identifier = $term->slug;
2552
            $this->_category->category_desc = $term->description;
2553
            $this->_category->id = $term->term_id;
2554
            $this->_category->parent = $term->parent;
2555
        }
2556
    }
2557
2558
2559
    /**
2560
     * Clears out category properties.
2561
     */
2562
    private function _set_empty_category_object()
2563
    {
2564
        $this->_category = new stdClass();
2565
        $this->_category->category_name = $this->_category->category_identifier = $this->_category->category_desc = '';
2566
        $this->_category->id = $this->_category->parent = 0;
2567
    }
2568
2569
2570
    /**
2571
     * @throws EE_Error
2572
     */
2573 View Code Duplication
    protected function _category_list_table()
2574
    {
2575
        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
2576
        $this->_search_btn_label = esc_html__('Categories', 'event_espresso');
2577
        $this->_admin_page_title .= ' ' . $this->get_action_link_or_button(
2578
            'add_category',
2579
            'add_category',
2580
            array(),
2581
            'add-new-h2'
2582
        );
2583
        $this->display_admin_list_table_page_with_sidebar();
2584
    }
2585
2586
2587
    /**
2588
     * Output category details view.
2589
     */
2590 View Code Duplication
    protected function _category_details($view)
2591
    {
2592
        // load formatter helper
2593
        // load field generator helper
2594
        $route = $view == 'edit' ? 'update_category' : 'insert_category';
2595
        $this->_set_add_edit_form_tags($route);
2596
        $this->_set_category_object();
2597
        $id = ! empty($this->_category->id) ? $this->_category->id : '';
2598
        $delete_action = 'delete_category';
2599
        // custom redirect
2600
        $redirect = EE_Admin_Page::add_query_args_and_nonce(
2601
            array('action' => 'category_list'),
2602
            $this->_admin_base_url
2603
        );
2604
        $this->_set_publish_post_box_vars('EVT_CAT_ID', $id, $delete_action, $redirect);
2605
        // take care of contents
2606
        $this->_template_args['admin_page_content'] = $this->_category_details_content();
2607
        $this->display_admin_page_with_sidebar();
2608
    }
2609
2610
2611
    /**
2612
     * Output category details content.
2613
     */
2614 View Code Duplication
    protected function _category_details_content()
2615
    {
2616
        $editor_args['category_desc'] = array(
0 ignored issues
show
Coding Style Comprehensibility introduced by
$editor_args was never initialized. Although not strictly required by PHP, it is generally a good practice to add $editor_args = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
2617
            'type'          => 'wp_editor',
2618
            'value'         => EEH_Formatter::admin_format_content($this->_category->category_desc),
2619
            'class'         => 'my_editor_custom',
2620
            'wpeditor_args' => array('media_buttons' => false),
2621
        );
2622
        $_wp_editor = $this->_generate_admin_form_fields($editor_args, 'array');
2623
        $all_terms = get_terms(
2624
            array(EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY),
2625
            array('hide_empty' => 0, 'exclude' => array($this->_category->id))
2626
        );
2627
        // setup category select for term parents.
2628
        $category_select_values[] = array(
0 ignored issues
show
Coding Style Comprehensibility introduced by
$category_select_values was never initialized. Although not strictly required by PHP, it is generally a good practice to add $category_select_values = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
2629
            'text' => esc_html__('No Parent', 'event_espresso'),
2630
            'id'   => 0,
2631
        );
2632
        foreach ($all_terms as $term) {
2633
            $category_select_values[] = array(
2634
                'text' => $term->name,
2635
                'id'   => $term->term_id,
2636
            );
2637
        }
2638
        $category_select = EEH_Form_Fields::select_input(
2639
            'category_parent',
2640
            $category_select_values,
2641
            $this->_category->parent
2642
        );
2643
        $template_args = array(
2644
            'category'                 => $this->_category,
2645
            'category_select'          => $category_select,
2646
            'unique_id_info_help_link' => $this->_get_help_tab_link('unique_id_info'),
2647
            'category_desc_editor'     => $_wp_editor['category_desc']['field'],
2648
            'disable'                  => '',
2649
            'disabled_message'         => false,
2650
        );
2651
        $template = EVENTS_TEMPLATE_PATH . 'event_category_details.template.php';
2652
        return EEH_Template::display_template($template, $template_args, true);
2653
    }
2654
2655
2656
    /**
2657
     * Handles deleting categories.
2658
     */
2659 View Code Duplication
    protected function _delete_categories()
2660
    {
2661
        $cat_ids = isset($this->_req_data['EVT_CAT_ID']) ? (array) $this->_req_data['EVT_CAT_ID']
2662
            : (array) $this->_req_data['category_id'];
2663
        foreach ($cat_ids as $cat_id) {
2664
            $this->_delete_category($cat_id);
2665
        }
2666
        // doesn't matter what page we're coming from... we're going to the same place after delete.
2667
        $query_args = array(
2668
            'action' => 'category_list',
2669
        );
2670
        $this->_redirect_after_action(0, '', '', $query_args);
2671
    }
2672
2673
2674
    /**
2675
     * Handles deleting specific category.
2676
     *
2677
     * @param int $cat_id
2678
     */
2679
    protected function _delete_category($cat_id)
2680
    {
2681
        $cat_id = absint($cat_id);
2682
        wp_delete_term($cat_id, EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY);
2683
    }
2684
2685
2686
    /**
2687
     * Handles triggering the update or insertion of a new category.
2688
     *
2689
     * @param bool $new_category true means we're triggering the insert of a new category.
2690
     */
2691 View Code Duplication
    protected function _insert_or_update_category($new_category)
2692
    {
2693
        $cat_id = $new_category ? $this->_insert_category() : $this->_insert_category(true);
2694
        $success = 0; // we already have a success message so lets not send another.
2695
        if ($cat_id) {
2696
            $query_args = array(
2697
                'action'     => 'edit_category',
2698
                'EVT_CAT_ID' => $cat_id,
2699
            );
2700
        } else {
2701
            $query_args = array('action' => 'add_category');
2702
        }
2703
        $this->_redirect_after_action($success, '', '', $query_args, true);
2704
    }
2705
2706
2707
    /**
2708
     * Inserts or updates category
2709
     *
2710
     * @param bool $update (true indicates we're updating a category).
2711
     * @return bool|mixed|string
2712
     */
2713
    private function _insert_category($update = false)
2714
    {
2715
        $cat_id = $update ? $this->_req_data['EVT_CAT_ID'] : '';
2716
        $category_name = isset($this->_req_data['category_name']) ? $this->_req_data['category_name'] : '';
2717
        $category_desc = isset($this->_req_data['category_desc']) ? $this->_req_data['category_desc'] : '';
2718
        $category_parent = isset($this->_req_data['category_parent']) ? $this->_req_data['category_parent'] : 0;
2719
        if (empty($category_name)) {
2720
            $msg = esc_html__('You must add a name for the category.', 'event_espresso');
2721
            EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2722
            return false;
2723
        }
2724
        $term_args = array(
2725
            'name'        => $category_name,
2726
            'description' => $category_desc,
2727
            'parent'      => $category_parent,
2728
        );
2729
        // was the category_identifier input disabled?
2730
        if (isset($this->_req_data['category_identifier'])) {
2731
            $term_args['slug'] = $this->_req_data['category_identifier'];
2732
        }
2733
        $insert_ids = $update
2734
            ? wp_update_term($cat_id, EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY, $term_args)
2735
            : wp_insert_term($category_name, EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY, $term_args);
2736 View Code Duplication
        if (! is_array($insert_ids)) {
2737
            $msg = esc_html__(
2738
                'An error occurred and the category has not been saved to the database.',
2739
                'event_espresso'
2740
            );
2741
            EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2742
        } else {
2743
            $cat_id = $insert_ids['term_id'];
2744
            $msg = sprintf(esc_html__('The category %s was successfully saved', 'event_espresso'), $category_name);
2745
            EE_Error::add_success($msg);
2746
        }
2747
        return $cat_id;
2748
    }
2749
2750
2751
    /**
2752
     * Gets categories or count of categories matching the arguments in the request.
2753
     *
2754
     * @param int  $per_page
2755
     * @param int  $current_page
2756
     * @param bool $count
2757
     * @return EE_Base_Class[]|EE_Term_Taxonomy[]|int
2758
     */
2759 View Code Duplication
    public function get_categories($per_page = 10, $current_page = 1, $count = false)
2760
    {
2761
        // testing term stuff
2762
        $orderby = isset($this->_req_data['orderby']) ? $this->_req_data['orderby'] : 'Term.term_id';
2763
        $order = isset($this->_req_data['order']) ? $this->_req_data['order'] : 'DESC';
2764
        $limit = ($current_page - 1) * $per_page;
2765
        $where = array('taxonomy' => EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY);
2766
        if (isset($this->_req_data['s'])) {
2767
            $sstr = '%' . $this->_req_data['s'] . '%';
2768
            $where['OR'] = array(
2769
                'Term.name'   => array('LIKE', $sstr),
2770
                'description' => array('LIKE', $sstr),
2771
            );
2772
        }
2773
        $query_params = array(
2774
            $where,
2775
            'order_by'   => array($orderby => $order),
2776
            'limit'      => $limit . ',' . $per_page,
2777
            'force_join' => array('Term'),
2778
        );
2779
        $categories = $count
2780
            ? EEM_Term_Taxonomy::instance()->count($query_params, 'term_id')
2781
            : EEM_Term_Taxonomy::instance()->get_all($query_params);
2782
        return $categories;
2783
    }
2784
2785
    /* end category stuff */
2786
    /**************/
2787
2788
2789
    /**
2790
     * Callback for the `ee_save_timezone_setting` ajax action.
2791
     *
2792
     * @throws EE_Error
2793
     */
2794
    public function save_timezonestring_setting()
2795
    {
2796
        $timezone_string = isset($this->_req_data['timezone_selected'])
2797
            ? $this->_req_data['timezone_selected']
2798
            : '';
2799
        if (empty($timezone_string) || ! EEH_DTT_Helper::validate_timezone($timezone_string, false)) {
2800
            EE_Error::add_error(
2801
                esc_html__('An invalid timezone string submitted.', 'event_espresso'),
2802
                __FILE__,
2803
                __FUNCTION__,
2804
                __LINE__
2805
            );
2806
            $this->_template_args['error'] = true;
2807
            $this->_return_json();
2808
        }
2809
2810
        update_option('timezone_string', $timezone_string);
2811
        EE_Error::add_success(
2812
            esc_html__('Your timezone string was updated.', 'event_espresso')
2813
        );
2814
        $this->_template_args['success'] = true;
2815
        $this->_return_json(true, array('action' => 'create_new'));
2816
    }
2817
}
2818