Completed
Branch FET-10766-extract-activation-d... (6ba6fc)
by
unknown
84:12 queued 72:44
created
caffeinated/admin/new/pricing/espresso_events_Pricing_Hooks.class.php 2 patches
Indentation   +2108 added lines, -2108 removed lines patch added patch discarded remove patch
@@ -15,2114 +15,2114 @@
 block discarded – undo
15 15
 class espresso_events_Pricing_Hooks extends EE_Admin_Hooks
16 16
 {
17 17
 
18
-    /**
19
-     * This property is just used to hold the status of whether an event is currently being
20
-     * created (true) or edited (false)
21
-     *
22
-     * @access protected
23
-     * @var bool
24
-     */
25
-    protected $_is_creating_event;
26
-
27
-
28
-    /**
29
-     * Used to contain the format strings for date and time that will be used for php date and
30
-     * time.
31
-     * Is set in the _set_hooks_properties() method.
32
-     *
33
-     * @var array
34
-     */
35
-    protected $_date_format_strings;
36
-
37
-
38
-    /**
39
-     * @var string $_date_time_format
40
-     */
41
-    protected $_date_time_format;
42
-
43
-
44
-
45
-    /**
46
-     *
47
-     */
48
-    protected function _set_hooks_properties()
49
-    {
50
-        $this->_name = 'pricing';
51
-        //capability check
52
-        if (! EE_Registry::instance()->CAP->current_user_can(
53
-            'ee_read_default_prices',
54
-            'advanced_ticket_datetime_metabox'
55
-        )) {
56
-            return;
57
-        }
58
-        $this->_setup_metaboxes();
59
-        $this->_set_date_time_formats();
60
-        $this->_validate_format_strings();
61
-        $this->_set_scripts_styles();
62
-        // commented out temporarily until logic is implemented in callback
63
-        // add_action(
64
-        //     'AHEE__EE_Admin_Page_CPT__do_extra_autosave_stuff__after_Extend_Events_Admin_Page',
65
-        //     array($this, 'autosave_handling')
66
-        // );
67
-        add_filter(
68
-            'FHEE__Events_Admin_Page___insert_update_cpt_item__event_update_callbacks',
69
-            array($this, 'caf_updates')
70
-        );
71
-    }
72
-
73
-
74
-
75
-    /**
76
-     * @return void
77
-     */
78
-    protected function _setup_metaboxes()
79
-    {
80
-        //if we were going to add our own metaboxes we'd use the below.
81
-        $this->_metaboxes = array(
82
-            0 => array(
83
-                'page_route' => array('edit', 'create_new'),
84
-                'func'       => 'pricing_metabox',
85
-                'label'      => esc_html__('Event Tickets & Datetimes', 'event_espresso'),
86
-                'priority'   => 'high',
87
-                'context'    => 'normal',
88
-            ),
89
-        );
90
-        $this->_remove_metaboxes = array(
91
-            0 => array(
92
-                'page_route' => array('edit', 'create_new'),
93
-                'id'         => 'espresso_event_editor_tickets',
94
-                'context'    => 'normal',
95
-            ),
96
-        );
97
-    }
98
-
99
-
100
-
101
-    /**
102
-     * @return void
103
-     */
104
-    protected function _set_date_time_formats()
105
-    {
106
-        /**
107
-         * Format strings for date and time.  Defaults are existing behaviour from 4.1.
108
-         * Note, that if you return null as the value for 'date', and 'time' in the array, then
109
-         * EE will automatically use the set wp_options, 'date_format', and 'time_format'.
110
-         *
111
-         * @since 4.6.7
112
-         * @var array  Expected an array returned with 'date' and 'time' keys.
113
-         */
114
-        $this->_date_format_strings = apply_filters(
115
-            'FHEE__espresso_events_Pricing_Hooks___set_hooks_properties__date_format_strings',
116
-            array(
117
-                'date' => 'Y-m-d',
118
-                'time' => 'h:i a',
119
-            )
120
-        );
121
-        //validate
122
-        $this->_date_format_strings['date'] = isset($this->_date_format_strings['date'])
123
-            ? $this->_date_format_strings['date']
124
-            : null;
125
-        $this->_date_format_strings['time'] = isset($this->_date_format_strings['time'])
126
-            ? $this->_date_format_strings['time']
127
-            : null;
128
-        $this->_date_time_format = $this->_date_format_strings['date'] . ' ' . $this->_date_format_strings['time'];
129
-    }
130
-
131
-
132
-
133
-    /**
134
-     * @return void
135
-     */
136
-    protected function _validate_format_strings()
137
-    {
138
-        //validate format strings
139
-        $format_validation = EEH_DTT_Helper::validate_format_string(
140
-            $this->_date_time_format
141
-        );
142
-        if (is_array($format_validation)) {
143
-            $msg = '<p>';
144
-            $msg .= sprintf(
145
-                esc_html__(
146
-                    'The format "%s" was likely added via a filter and is invalid for the following reasons:',
147
-                    'event_espresso'
148
-                ),
149
-                $this->_date_time_format
150
-            );
151
-            $msg .= '</p><ul>';
152
-            foreach ($format_validation as $error) {
153
-                $msg .= '<li>' . $error . '</li>';
154
-            }
155
-            $msg .= '</ul><p>';
156
-            $msg .= sprintf(
157
-                esc_html__(
158
-                    '%sPlease note that your date and time formats have been reset to "Y-m-d" and "h:i a" respectively.%s',
159
-                    'event_espresso'
160
-                ),
161
-                '<span style="color:#D54E21;">',
162
-                '</span>'
163
-            );
164
-            $msg .= '</p>';
165
-            EE_Error::add_attention($msg, __FILE__, __FUNCTION__, __LINE__);
166
-            $this->_date_format_strings = array(
167
-                'date' => 'Y-m-d',
168
-                'time' => 'h:i a',
169
-            );
170
-        }
171
-    }
172
-
173
-
174
-
175
-    /**
176
-     * @return void
177
-     */
178
-    protected function _set_scripts_styles()
179
-    {
180
-        $this->_scripts_styles = array(
181
-            'registers'   => array(
182
-                'ee-tickets-datetimes-css' => array(
183
-                    'url'  => PRICING_ASSETS_URL . 'event-tickets-datetimes.css',
184
-                    'type' => 'css',
185
-                ),
186
-                'ee-dtt-ticket-metabox'    => array(
187
-                    'url'     => PRICING_ASSETS_URL . 'ee-datetime-ticket-metabox.js',
188
-                    'depends' => array('ee-datepicker', 'ee-dialog', 'underscore'),
189
-                ),
190
-            ),
191
-            'deregisters' => array(
192
-                'event-editor-css'       => array('type' => 'css'),
193
-                'event-datetime-metabox' => array('type' => 'js'),
194
-            ),
195
-            'enqueues'    => array(
196
-                'ee-tickets-datetimes-css' => array('edit', 'create_new'),
197
-                'ee-dtt-ticket-metabox'    => array('edit', 'create_new'),
198
-            ),
199
-            'localize'    => array(
200
-                'ee-dtt-ticket-metabox' => array(
201
-                    'DTT_TRASH_BLOCK'       => array(
202
-                        'main_warning'            => esc_html__(
203
-                            'The Datetime you are attempting to trash is the only datetime selected for the following ticket(s):',
204
-                            'event_espresso'
205
-                        ),
206
-                        'after_warning'           => esc_html__(
207
-                            'In order to trash this datetime you must first make sure the above ticket(s) are assigned to other datetimes.',
208
-                            'event_espresso'
209
-                        ),
210
-                        'cancel_button'           => '<button class="button-secondary ee-modal-cancel">'
211
-                                                     . esc_html__('Cancel', 'event_espresso') . '</button>',
212
-                        'close_button'            => '<button class="button-secondary ee-modal-cancel">'
213
-                                                     . esc_html__('Close', 'event_espresso') . '</button>',
214
-                        'single_warning_from_tkt' => esc_html__(
215
-                            'The Datetime you are attempting to unassign from this ticket is the only remaining datetime for this ticket. Tickets must always have at least one datetime assigned to them.',
216
-                            'event_espresso'
217
-                        ),
218
-                        'single_warning_from_dtt' => esc_html__(
219
-                            'The ticket you are attempting to unassign from this datetime cannot be unassigned because the datetime is the only remaining datetime for the ticket.  Tickets must always have at least one datetime assigned to them.',
220
-                            'event_espresso'
221
-                        ),
222
-                        'dismiss_button'          => '<button class="button-secondary ee-modal-cancel">'
223
-                                                     . esc_html__('Dismiss', 'event_espresso') . '</button>',
224
-                    ),
225
-                    'DTT_ERROR_MSG'         => array(
226
-                        'no_ticket_name' => esc_html__('General Admission', 'event_espresso'),
227
-                        'dismiss_button' => '<div class="save-cancel-button-container"><button class="button-secondary ee-modal-cancel">'
228
-                                            . esc_html__('Dismiss', 'event_espresso') . '</button></div>',
229
-                    ),
230
-                    'DTT_OVERSELL_WARNING'  => array(
231
-                        'datetime_ticket' => esc_html__(
232
-                            'You cannot add this ticket to this datetime because it has a sold amount that is greater than the amount of spots remaining for this datetime.',
233
-                            'event_espresso'
234
-                        ),
235
-                        'ticket_datetime' => esc_html__(
236
-                            'You cannot add this datetime to this ticket because the ticket has a sold amount that is greater than the amount of spots remaining on the datetime.',
237
-                            'event_espresso'
238
-                        ),
239
-                    ),
240
-                    'DTT_CONVERTED_FORMATS' => EEH_DTT_Helper::convert_php_to_js_and_moment_date_formats(
241
-                        $this->_date_format_strings['date'],
242
-                        $this->_date_format_strings['time']
243
-                    ),
244
-                    'DTT_START_OF_WEEK'     => array('dayValue' => (int)get_option('start_of_week')),
245
-                ),
246
-            ),
247
-        );
248
-    }
249
-
250
-
251
-
252
-    /**
253
-     * @param array $update_callbacks
254
-     * @return array
255
-     */
256
-    public function caf_updates(array $update_callbacks)
257
-    {
258
-        foreach ($update_callbacks as $key => $callback) {
259
-            if ($callback[1] === '_default_tickets_update') {
260
-                unset($update_callbacks[$key]);
261
-            }
262
-        }
263
-        $update_callbacks[] = array($this, 'datetime_and_tickets_caf_update');
264
-        return $update_callbacks;
265
-    }
266
-
267
-
268
-    /**
269
-     * Handles saving everything related to Tickets (datetimes, tickets, prices)
270
-     *
271
-     * @param  EE_Event $event The Event object we're attaching data to
272
-     * @param  array $data The request data from the form
273
-     * @throws EE_Error
274
-     * @throws InvalidArgumentException
275
-     */
276
-    public function datetime_and_tickets_caf_update($event, $data)
277
-    {
278
-        //first we need to start with datetimes cause they are the "root" items attached to events.
279
-        $saved_datetimes = $this->_update_datetimes($event, $data);
280
-        //next tackle the tickets (and prices?)
281
-        $this->_update_tickets($event, $saved_datetimes, $data);
282
-    }
283
-
284
-
285
-    /**
286
-     * update event_datetimes
287
-     *
288
-     * @param  EE_Event $event Event being updated
289
-     * @param  array $data the request data from the form
290
-     * @return EE_Datetime[]
291
-     * @throws InvalidArgumentException
292
-     * @throws EE_Error
293
-     */
294
-    protected function _update_datetimes($event, $data)
295
-    {
296
-        $timezone = isset($data['timezone_string']) ? $data['timezone_string'] : null;
297
-        $saved_dtt_ids = array();
298
-        $saved_dtt_objs = array();
299
-        if (empty($data['edit_event_datetimes']) || !is_array($data['edit_event_datetimes'])) {
300
-            throw new InvalidArgumentException(
301
-                esc_html__(
302
-                    'The "edit_event_datetimes" array is invalid therefore the event can not be updated.',
303
-                    'event_espresso'
304
-                )
305
-            );
306
-        }
307
-        foreach ($data['edit_event_datetimes'] as $row => $datetime_data) {
308
-            //trim all values to ensure any excess whitespace is removed.
309
-            $datetime_data = array_map(
310
-                function ($datetime_data) {
311
-                    return is_array($datetime_data) ? $datetime_data : trim($datetime_data);
312
-                },
313
-                $datetime_data
314
-            );
315
-            $datetime_data['DTT_EVT_end'] = isset($datetime_data['DTT_EVT_end'])
316
-                                            && ! empty($datetime_data['DTT_EVT_end'])
317
-                ? $datetime_data['DTT_EVT_end']
318
-                : $datetime_data['DTT_EVT_start'];
319
-            $datetime_values = array(
320
-                'DTT_ID'          => ! empty($datetime_data['DTT_ID'])
321
-                    ? $datetime_data['DTT_ID']
322
-                    : null,
323
-                'DTT_name'        => ! empty($datetime_data['DTT_name'])
324
-                    ? $datetime_data['DTT_name']
325
-                    : '',
326
-                'DTT_description' => ! empty($datetime_data['DTT_description'])
327
-                    ? $datetime_data['DTT_description']
328
-                    : '',
329
-                'DTT_EVT_start'   => $datetime_data['DTT_EVT_start'],
330
-                'DTT_EVT_end'     => $datetime_data['DTT_EVT_end'],
331
-                'DTT_reg_limit'   => empty($datetime_data['DTT_reg_limit'])
332
-                    ? EE_INF
333
-                    : $datetime_data['DTT_reg_limit'],
334
-                'DTT_order'       => ! isset($datetime_data['DTT_order'])
335
-                    ? $row
336
-                    : $datetime_data['DTT_order'],
337
-            );
338
-            // if we have an id then let's get existing object first and then set the new values.
339
-            // Otherwise we instantiate a new object for save.
340
-            if (! empty($datetime_data['DTT_ID'])) {
341
-                $datetime = EE_Registry::instance()
342
-                                       ->load_model('Datetime', array($timezone))
343
-                                       ->get_one_by_ID($datetime_data['DTT_ID']);
344
-                //set date and time format according to what is set in this class.
345
-                $datetime->set_date_format($this->_date_format_strings['date']);
346
-                $datetime->set_time_format($this->_date_format_strings['time']);
347
-                foreach ($datetime_values as $field => $value) {
348
-                    $datetime->set($field, $value);
349
-                }
350
-                // make sure the $dtt_id here is saved just in case
351
-                // after the add_relation_to() the autosave replaces it.
352
-                // We need to do this so we dont' TRASH the parent DTT.
353
-                // (save the ID for both key and value to avoid duplications)
354
-                $saved_dtt_ids[$datetime->ID()] = $datetime->ID();
355
-            } else {
356
-                $datetime = EE_Registry::instance()->load_class(
357
-                    'Datetime',
358
-                    array(
359
-                        $datetime_values,
360
-                        $timezone,
361
-                        array($this->_date_format_strings['date'], $this->_date_format_strings['time']),
362
-                    ),
363
-                    false,
364
-                    false
365
-                );
366
-                foreach ($datetime_values as $field => $value) {
367
-                    $datetime->set($field, $value);
368
-                }
369
-            }
370
-            $datetime->save();
371
-            $datetime = $event->_add_relation_to($datetime, 'Datetime');
372
-            // before going any further make sure our dates are setup correctly
373
-            // so that the end date is always equal or greater than the start date.
374
-            if ($datetime->get_raw('DTT_EVT_start') > $datetime->get_raw('DTT_EVT_end')) {
375
-                $datetime->set('DTT_EVT_end', $datetime->get('DTT_EVT_start'));
376
-                $datetime = EEH_DTT_Helper::date_time_add($datetime, 'DTT_EVT_end', 'days');
377
-                $datetime->save();
378
-            }
379
-            //	now we have to make sure we add the new DTT_ID to the $saved_dtt_ids array
380
-            // because it is possible there was a new one created for the autosave.
381
-            // (save the ID for both key and value to avoid duplications)
382
-            $DTT_ID = $datetime->ID();
383
-            $saved_dtt_ids[$DTT_ID] = $DTT_ID;
384
-            $saved_dtt_objs[$row] = $datetime;
385
-            //todo if ANY of these updates fail then we want the appropriate global error message.
386
-        }
387
-        $event->save();
388
-        // now we need to REMOVE any datetimes that got deleted.
389
-        // Keep in mind that this process will only kick in for datetimes that don't have any DTT_sold on them.
390
-        // So its safe to permanently delete at this point.
391
-        $old_datetimes = explode(',', $data['datetime_IDs']);
392
-        $old_datetimes = $old_datetimes[0] === '' ? array() : $old_datetimes;
393
-        if (is_array($old_datetimes)) {
394
-            $datetimes_to_delete = array_diff($old_datetimes, $saved_dtt_ids);
395
-            foreach ($datetimes_to_delete as $id) {
396
-                $id = absint($id);
397
-                if (empty($id)) {
398
-                    continue;
399
-                }
400
-                $dtt_to_remove = EE_Registry::instance()->load_model('Datetime')->get_one_by_ID($id);
401
-                //remove tkt relationships.
402
-                $related_tickets = $dtt_to_remove->get_many_related('Ticket');
403
-                foreach ($related_tickets as $tkt) {
404
-                    $dtt_to_remove->_remove_relation_to($tkt, 'Ticket');
405
-                }
406
-                $event->_remove_relation_to($id, 'Datetime');
407
-                $dtt_to_remove->refresh_cache_of_related_objects();
408
-            }
409
-        }
410
-        return $saved_dtt_objs;
411
-    }
412
-
413
-
414
-    /**
415
-     * update tickets
416
-     *
417
-     * @param  EE_Event $event Event object being updated
418
-     * @param  EE_Datetime[] $saved_datetimes an array of datetime ids being updated
419
-     * @param  array $data incoming request data
420
-     * @return EE_Ticket[]
421
-     * @throws InvalidArgumentException
422
-     * @throws EE_Error
423
-     */
424
-    protected function _update_tickets($event, $saved_datetimes, $data)
425
-    {
426
-        $new_tkt = null;
427
-        $new_default = null;
428
-        //stripslashes because WP filtered the $_POST ($data) array to add slashes
429
-        $data = stripslashes_deep($data);
430
-        $timezone = isset($data['timezone_string']) ? $data['timezone_string'] : null;
431
-        $saved_tickets = $datetimes_on_existing = array();
432
-        $old_tickets = isset($data['ticket_IDs']) ? explode(',', $data['ticket_IDs']) : array();
433
-        if(empty($data['edit_tickets']) || ! is_array($data['edit_tickets'])){
434
-            throw new InvalidArgumentException(
435
-                esc_html__(
436
-                    'The "edit_tickets" array is invalid therefore the event can not be updated.',
437
-                    'event_espresso'
438
-                )
439
-            );
440
-        }
441
-        foreach ($data['edit_tickets'] as $row => $tkt) {
442
-            $update_prices = $create_new_TKT = false;
443
-            // figure out what datetimes were added to the ticket
444
-            // and what datetimes were removed from the ticket in the session.
445
-            $starting_tkt_dtt_rows = explode(',', $data['starting_ticket_datetime_rows'][$row]);
446
-            $tkt_dtt_rows = explode(',', $data['ticket_datetime_rows'][$row]);
447
-            $datetimes_added = array_diff($tkt_dtt_rows, $starting_tkt_dtt_rows);
448
-            $datetimes_removed = array_diff($starting_tkt_dtt_rows, $tkt_dtt_rows);
449
-            // trim inputs to ensure any excess whitespace is removed.
450
-            $tkt = array_map(
451
-                function ($ticket_data) {
452
-                    return is_array($ticket_data) ? $ticket_data : trim($ticket_data);
453
-                },
454
-                $tkt
455
-            );
456
-            // note we are doing conversions to floats here instead of allowing EE_Money_Field to handle
457
-            // because we're doing calculations prior to using the models.
458
-            // note incoming ['TKT_price'] value is already in standard notation (via js).
459
-            $ticket_price = isset($tkt['TKT_price'])
460
-                ? round((float)$tkt['TKT_price'], 3)
461
-                : 0;
462
-            //note incoming base price needs converted from localized value.
463
-            $base_price = isset($tkt['TKT_base_price'])
464
-                ? EEH_Money::convert_to_float_from_localized_money($tkt['TKT_base_price'])
465
-                : 0;
466
-            //if ticket price == 0 and $base_price != 0 then ticket price == base_price
467
-            $ticket_price = $ticket_price === 0 && $base_price !== 0
468
-                ? $base_price
469
-                : $ticket_price;
470
-            $base_price_id = isset($tkt['TKT_base_price_ID'])
471
-                ? $tkt['TKT_base_price_ID']
472
-                : 0;
473
-            $price_rows = is_array($data['edit_prices']) && isset($data['edit_prices'][$row])
474
-                ? $data['edit_prices'][$row]
475
-                : array();
476
-            $now = null;
477
-            if (empty($tkt['TKT_start_date'])) {
478
-                //lets' use now in the set timezone.
479
-                $now = new DateTime('now', new DateTimeZone($event->get_timezone()));
480
-                $tkt['TKT_start_date'] = $now->format($this->_date_time_format);
481
-            }
482
-            if (empty($tkt['TKT_end_date'])) {
483
-                /**
484
-                 * set the TKT_end_date to the first datetime attached to the ticket.
485
-                 */
486
-                $first_dtt = $saved_datetimes[reset($tkt_dtt_rows)];
487
-                $tkt['TKT_end_date'] = $first_dtt->start_date_and_time($this->_date_time_format);
488
-            }
489
-            $TKT_values = array(
490
-                'TKT_ID'          => ! empty($tkt['TKT_ID']) ? $tkt['TKT_ID'] : null,
491
-                'TTM_ID'          => ! empty($tkt['TTM_ID']) ? $tkt['TTM_ID'] : 0,
492
-                'TKT_name'        => ! empty($tkt['TKT_name']) ? $tkt['TKT_name'] : '',
493
-                'TKT_description' => ! empty($tkt['TKT_description'])
494
-                                     && $tkt['TKT_description'] !== esc_html__(
495
-                    'You can modify this description',
496
-                    'event_espresso'
497
-                )
498
-                    ? $tkt['TKT_description']
499
-                    : '',
500
-                'TKT_start_date'  => $tkt['TKT_start_date'],
501
-                'TKT_end_date'    => $tkt['TKT_end_date'],
502
-                'TKT_qty'         => ! isset($tkt['TKT_qty']) || $tkt['TKT_qty'] === ''
503
-                    ? EE_INF
504
-                    : $tkt['TKT_qty'],
505
-                'TKT_uses'        => ! isset($tkt['TKT_uses']) || $tkt['TKT_uses'] === ''
506
-                    ? EE_INF
507
-                    : $tkt['TKT_uses'],
508
-                'TKT_min'         => empty($tkt['TKT_min']) ? 0 : $tkt['TKT_min'],
509
-                'TKT_max'         => empty($tkt['TKT_max']) ? EE_INF : $tkt['TKT_max'],
510
-                'TKT_row'         => $row,
511
-                'TKT_order'       => isset($tkt['TKT_order']) ? $tkt['TKT_order'] : 0,
512
-                'TKT_taxable'     => ! empty($tkt['TKT_taxable']) ? 1 : 0,
513
-                'TKT_required'    => ! empty($tkt['TKT_required']) ? 1 : 0,
514
-                'TKT_price'       => $ticket_price,
515
-            );
516
-            // if this is a default TKT, then we need to set the TKT_ID to 0 and update accordingly,
517
-            // which means in turn that the prices will become new prices as well.
518
-            if (isset($tkt['TKT_is_default']) && $tkt['TKT_is_default']) {
519
-                $TKT_values['TKT_ID'] = 0;
520
-                $TKT_values['TKT_is_default'] = 0;
521
-                $update_prices = true;
522
-            }
523
-            // if we have a TKT_ID then we need to get that existing TKT_obj and update it
524
-            // we actually do our saves ahead of doing any add_relations to
525
-            // because its entirely possible that this ticket wasn't removed or added to any datetime in the session
526
-            // but DID have it's items modified.
527
-            // keep in mind that if the TKT has been sold (and we have changed pricing information),
528
-            // then we won't be updating the tkt but instead a new tkt will be created and the old one archived.
529
-            if (absint($TKT_values['TKT_ID'])) {
530
-                $ticket = EE_Registry::instance()
531
-                                     ->load_model('Ticket', array($timezone))
532
-                                     ->get_one_by_ID($tkt['TKT_ID']);
533
-                if ($ticket instanceof EE_Ticket) {
534
-                    $ticket = $this->_update_ticket_datetimes(
535
-                        $ticket,
536
-                        $saved_datetimes,
537
-                        $datetimes_added,
538
-                        $datetimes_removed
539
-                    );
540
-                    // are there any registrations using this ticket ?
541
-                    $tickets_sold = $ticket->count_related(
542
-                        'Registration',
543
-                        array(
544
-                            array(
545
-                                'STS_ID' => array('NOT IN', array(EEM_Registration::status_id_incomplete)),
546
-                            ),
547
-                        )
548
-                    );
549
-                    //set ticket formats
550
-                    $ticket->set_date_format($this->_date_format_strings['date']);
551
-                    $ticket->set_time_format($this->_date_format_strings['time']);
552
-                    // let's just check the total price for the existing ticket
553
-                    // and determine if it matches the new total price.
554
-                    // if they are different then we create a new ticket (if tickets sold)
555
-                    // if they aren't different then we go ahead and modify existing ticket.
556
-                    $create_new_TKT = $tickets_sold > 0 && $ticket_price !== $ticket->price() && ! $ticket->deleted();
557
-                    //set new values
558
-                    foreach ($TKT_values as $field => $value) {
559
-                        if ($field === 'TKT_qty') {
560
-                            $ticket->set_qty($value);
561
-                        } else {
562
-                            $ticket->set($field, $value);
563
-                        }
564
-                    }
565
-                    // if $create_new_TKT is false then we can safely update the existing ticket.
566
-                    // Otherwise we have to create a new ticket.
567
-                    if ($create_new_TKT) {
568
-                        $new_tkt = $this->_duplicate_ticket($ticket, $price_rows, $ticket_price, $base_price,
569
-                            $base_price_id);
570
-                    }
571
-                }
572
-            } else {
573
-                // no TKT_id so a new TKT
574
-                $ticket = EE_Ticket::new_instance(
575
-                    $TKT_values,
576
-                    $timezone,
577
-                    array($this->_date_format_strings['date'], $this->_date_format_strings['time'])
578
-                );
579
-                if ($ticket instanceof EE_Ticket) {
580
-                    // make sure ticket has an ID of setting relations won't work
581
-                    $ticket->save();
582
-                    $ticket = $this->_update_ticket_datetimes(
583
-                        $ticket,
584
-                        $saved_datetimes,
585
-                        $datetimes_added,
586
-                        $datetimes_removed
587
-                    );
588
-                    $update_prices = true;
589
-                }
590
-            }
591
-            //make sure any current values have been saved.
592
-            //$ticket->save();
593
-            // before going any further make sure our dates are setup correctly
594
-            // so that the end date is always equal or greater than the start date.
595
-            if ($ticket->get_raw('TKT_start_date') > $ticket->get_raw('TKT_end_date')) {
596
-                $ticket->set('TKT_end_date', $ticket->get('TKT_start_date'));
597
-                $ticket = EEH_DTT_Helper::date_time_add($ticket, 'TKT_end_date', 'days');
598
-            }
599
-            //let's make sure the base price is handled
600
-            $ticket = ! $create_new_TKT ? $this->_add_prices_to_ticket(array(), $ticket, $update_prices, $base_price,
601
-                $base_price_id) : $ticket;
602
-            //add/update price_modifiers
603
-            $ticket = ! $create_new_TKT ? $this->_add_prices_to_ticket($price_rows, $ticket, $update_prices) : $ticket;
604
-            //need to make sue that the TKT_price is accurate after saving the prices.
605
-            $ticket->ensure_TKT_Price_correct();
606
-            //handle CREATING a default tkt from the incoming tkt but ONLY if this isn't an autosave.
607
-            if (! defined('DOING_AUTOSAVE') && ! empty($tkt['TKT_is_default_selector'])) {
608
-                $update_prices = true;
609
-                $new_default = clone $ticket;
610
-                $new_default->set('TKT_ID', 0);
611
-                $new_default->set('TKT_is_default', 1);
612
-                $new_default->set('TKT_row', 1);
613
-                $new_default->set('TKT_price', $ticket_price);
614
-                // remove any dtt relations cause we DON'T want dtt relations attached
615
-                // (note this is just removing the cached relations in the object)
616
-                $new_default->_remove_relations('Datetime');
617
-                //todo we need to add the current attached prices as new prices to the new default ticket.
618
-                $new_default = $this->_add_prices_to_ticket($price_rows, $new_default, $update_prices);
619
-                //don't forget the base price!
620
-                $new_default = $this->_add_prices_to_ticket(
621
-                    array(),
622
-                    $new_default,
623
-                    $update_prices,
624
-                    $base_price,
625
-                    $base_price_id
626
-                );
627
-                $new_default->save();
628
-                do_action(
629
-                    'AHEE__espresso_events_Pricing_Hooks___update_tkts_new_default_ticket',
630
-                    $new_default,
631
-                    $row,
632
-                    $ticket,
633
-                    $data
634
-                );
635
-            }
636
-            // DO ALL dtt relationships for both current tickets and any archived tickets
637
-            // for the given dtt that are related to the current ticket.
638
-            // TODO... not sure exactly how we're going to do this considering we don't know
639
-            // what current ticket the archived tickets are related to
640
-            // (and TKT_parent is used for autosaves so that's not a field we can reliably use).
641
-            //let's assign any tickets that have been setup to the saved_tickets tracker
642
-            //save existing TKT
643
-            $ticket->save();
644
-            if ($create_new_TKT && $new_tkt instanceof EE_Ticket) {
645
-                //save new TKT
646
-                $new_tkt->save();
647
-                //add new ticket to array
648
-                $saved_tickets[$new_tkt->ID()] = $new_tkt;
649
-                do_action(
650
-                    'AHEE__espresso_events_Pricing_Hooks___update_tkts_new_ticket',
651
-                    $new_tkt,
652
-                    $row,
653
-                    $tkt,
654
-                    $data
655
-                );
656
-            } else {
657
-                //add tkt to saved tkts
658
-                $saved_tickets[$ticket->ID()] = $ticket;
659
-                do_action(
660
-                    'AHEE__espresso_events_Pricing_Hooks___update_tkts_update_ticket',
661
-                    $ticket,
662
-                    $row,
663
-                    $tkt,
664
-                    $data
665
-                );
666
-            }
667
-        }
668
-        // now we need to handle tickets actually "deleted permanently".
669
-        // There are cases where we'd want this to happen
670
-        // (i.e. autosaves are happening and then in between autosaves the user trashes a ticket).
671
-        // Or a draft event was saved and in the process of editing a ticket is trashed.
672
-        // No sense in keeping all the related data in the db!
673
-        $old_tickets = isset($old_tickets[0]) && $old_tickets[0] === '' ? array() : $old_tickets;
674
-        $tickets_removed = array_diff($old_tickets, array_keys($saved_tickets));
675
-        foreach ($tickets_removed as $id) {
676
-            $id = absint($id);
677
-            //get the ticket for this id
678
-            $tkt_to_remove = EE_Registry::instance()->load_model('Ticket')->get_one_by_ID($id);
679
-            //if this tkt is a default tkt we leave it alone cause it won't be attached to the datetime
680
-            if ($tkt_to_remove->get('TKT_is_default')) {
681
-                continue;
682
-            }
683
-            // if this tkt has any registrations attached so then we just ARCHIVE
684
-            // because we don't actually permanently delete these tickets.
685
-            if ($tkt_to_remove->count_related('Registration') > 0) {
686
-                $tkt_to_remove->delete();
687
-                continue;
688
-            }
689
-            // need to get all the related datetimes on this ticket and remove from every single one of them
690
-            // (remember this process can ONLY kick off if there are NO tkts_sold)
691
-            $datetimes = $tkt_to_remove->get_many_related('Datetime');
692
-            foreach ($datetimes as $datetime) {
693
-                $tkt_to_remove->_remove_relation_to($datetime, 'Datetime');
694
-            }
695
-            // need to do the same for prices (except these prices can also be deleted because again,
696
-            // tickets can only be trashed if they don't have any TKTs sold (otherwise they are just archived))
697
-            $tkt_to_remove->delete_related_permanently('Price');
698
-            do_action('AHEE__espresso_events_Pricing_Hooks___update_tkts_delete_ticket', $tkt_to_remove);
699
-            // finally let's delete this ticket
700
-            // (which should not be blocked at this point b/c we've removed all our relationships)
701
-            $tkt_to_remove->delete_permanently();
702
-        }
703
-        return $saved_tickets;
704
-    }
705
-
706
-
707
-
708
-    /**
709
-     * @access  protected
710
-     * @param \EE_Ticket     $ticket
711
-     * @param \EE_Datetime[] $saved_datetimes
712
-     * @param \EE_Datetime[] $added_datetimes
713
-     * @param \EE_Datetime[] $removed_datetimes
714
-     * @return \EE_Ticket
715
-     * @throws \EE_Error
716
-     */
717
-    protected function _update_ticket_datetimes(
718
-        EE_Ticket $ticket,
719
-        $saved_datetimes = array(),
720
-        $added_datetimes = array(),
721
-        $removed_datetimes = array()
722
-    ) {
723
-        // to start we have to add the ticket to all the datetimes its supposed to be with,
724
-        // and removing the ticket from datetimes it got removed from.
725
-        // first let's add datetimes
726
-        if (! empty($added_datetimes) && is_array($added_datetimes)) {
727
-            foreach ($added_datetimes as $row_id) {
728
-                $row_id = (int)$row_id;
729
-                if (isset($saved_datetimes[$row_id]) && $saved_datetimes[$row_id] instanceof EE_Datetime) {
730
-                    $ticket->_add_relation_to($saved_datetimes[$row_id], 'Datetime');
731
-                    // Is this an existing ticket (has an ID) and does it have any sold?
732
-                    // If so, then we need to add that to the DTT sold because this DTT is getting added.
733
-                    if ($ticket->ID() && $ticket->sold() > 0) {
734
-                        $saved_datetimes[$row_id]->increase_sold($ticket->sold());
735
-                        $saved_datetimes[$row_id]->save();
736
-                    }
737
-                }
738
-            }
739
-        }
740
-        // then remove datetimes
741
-        if (! empty($removed_datetimes) && is_array($removed_datetimes)) {
742
-            foreach ($removed_datetimes as $row_id) {
743
-                $row_id = (int)$row_id;
744
-                // its entirely possible that a datetime got deleted (instead of just removed from relationship.
745
-                // So make sure we skip over this if the dtt isn't in the $saved_datetimes array)
746
-                if (isset($saved_datetimes[$row_id]) && $saved_datetimes[$row_id] instanceof EE_Datetime) {
747
-                    $ticket->_remove_relation_to($saved_datetimes[$row_id], 'Datetime');
748
-                    // Is this an existing ticket (has an ID) and does it have any sold?
749
-                    // If so, then we need to remove it's sold from the DTT_sold.
750
-                    if ($ticket->ID() && $ticket->sold() > 0) {
751
-                        $saved_datetimes[$row_id]->decrease_sold($ticket->sold());
752
-                        $saved_datetimes[$row_id]->save();
753
-                    }
754
-                }
755
-            }
756
-        }
757
-        // cap ticket qty by datetime reg limits
758
-        $ticket->set_qty(min($ticket->qty(), $ticket->qty('reg_limit')));
759
-        return $ticket;
760
-    }
761
-
762
-
763
-
764
-    /**
765
-     * @access  protected
766
-     * @param \EE_Ticket $ticket
767
-     * @param array      $price_rows
768
-     * @param int        $ticket_price
769
-     * @param int        $base_price
770
-     * @param int        $base_price_id
771
-     * @return \EE_Ticket
772
-     * @throws \EE_Error
773
-     */
774
-    protected function _duplicate_ticket(
775
-        EE_Ticket $ticket,
776
-        $price_rows = array(),
777
-        $ticket_price = 0,
778
-        $base_price = 0,
779
-        $base_price_id = 0
780
-    ) {
781
-        // create new ticket that's a copy of the existing
782
-        // except a new id of course (and not archived)
783
-        // AND has the new TKT_price associated with it.
784
-        $new_ticket = clone $ticket;
785
-        $new_ticket->set('TKT_ID', 0);
786
-        $new_ticket->set_deleted(0);
787
-        $new_ticket->set_price($ticket_price);
788
-        $new_ticket->set_sold(0);
789
-        // let's get a new ID for this ticket
790
-        $new_ticket->save();
791
-        // we also need to make sure this new ticket gets the same datetime attachments as the archived ticket
792
-        $datetimes_on_existing = $ticket->datetimes();
793
-        $new_ticket = $this->_update_ticket_datetimes(
794
-            $new_ticket,
795
-            $datetimes_on_existing,
796
-            array_keys($datetimes_on_existing)
797
-        );
798
-        // $ticket will get archived later b/c we are NOT adding it to the saved_tickets array.
799
-        // if existing $ticket has sold amount, then we need to adjust the qty for the new TKT to = the remaining
800
-        // available.
801
-        if ($ticket->sold() > 0) {
802
-            $new_qty = $ticket->qty() - $ticket->sold();
803
-            $new_ticket->set_qty($new_qty);
804
-        }
805
-        //now we update the prices just for this ticket
806
-        $new_ticket = $this->_add_prices_to_ticket($price_rows, $new_ticket, true);
807
-        //and we update the base price
808
-        $new_ticket = $this->_add_prices_to_ticket(array(), $new_ticket, true, $base_price, $base_price_id);
809
-        return $new_ticket;
810
-    }
811
-
812
-
813
-
814
-    /**
815
-     * This attaches a list of given prices to a ticket.
816
-     * Note we dont' have to worry about ever removing relationships (or archiving prices) because if there is a change
817
-     * in price information on a ticket, a new ticket is created anyways so the archived ticket will retain the old
818
-     * price info and prices are automatically "archived" via the ticket.
819
-     *
820
-     * @access  private
821
-     * @param array     $prices        Array of prices from the form.
822
-     * @param EE_Ticket $ticket        EE_Ticket object that prices are being attached to.
823
-     * @param bool      $new_prices    Whether attach existing incoming prices or create new ones.
824
-     * @param int|bool  $base_price    if FALSE then NOT doing a base price add.
825
-     * @param int|bool  $base_price_id if present then this is the base_price_id being updated.
826
-     * @return EE_Ticket
827
-     * @throws EE_Error
828
-     */
829
-    protected function _add_prices_to_ticket(
830
-        $prices = array(),
831
-        EE_Ticket $ticket,
832
-        $new_prices = false,
833
-        $base_price = false,
834
-        $base_price_id = false
835
-    ) {
836
-        // let's just get any current prices that may exist on the given ticket
837
-        // so we can remove any prices that got trashed in this session.
838
-        $current_prices_on_ticket = $base_price !== false
839
-            ? $ticket->base_price(true)
840
-            : $ticket->price_modifiers();
841
-        $updated_prices = array();
842
-        // if $base_price ! FALSE then updating a base price.
843
-        if ($base_price !== false) {
844
-            $prices[1] = array(
845
-                'PRC_ID'     => $new_prices || $base_price_id === 1 ? null : $base_price_id,
846
-                'PRT_ID'     => 1,
847
-                'PRC_amount' => $base_price,
848
-                'PRC_name'   => $ticket->get('TKT_name'),
849
-                'PRC_desc'   => $ticket->get('TKT_description'),
850
-            );
851
-        }
852
-        //possibly need to save tkt
853
-        if (! $ticket->ID()) {
854
-            $ticket->save();
855
-        }
856
-        foreach ($prices as $row => $prc) {
857
-            $prt_id = ! empty($prc['PRT_ID']) ? $prc['PRT_ID'] : null;
858
-            if (empty($prt_id)) {
859
-                continue;
860
-            } //prices MUST have a price type id.
861
-            $PRC_values = array(
862
-                'PRC_ID'         => ! empty($prc['PRC_ID']) ? $prc['PRC_ID'] : null,
863
-                'PRT_ID'         => $prt_id,
864
-                'PRC_amount'     => ! empty($prc['PRC_amount']) ? $prc['PRC_amount'] : 0,
865
-                'PRC_name'       => ! empty($prc['PRC_name']) ? $prc['PRC_name'] : '',
866
-                'PRC_desc'       => ! empty($prc['PRC_desc']) ? $prc['PRC_desc'] : '',
867
-                'PRC_is_default' => false,
868
-                //make sure we set PRC_is_default to false for all ticket saves from event_editor
869
-                'PRC_order'      => $row,
870
-            );
871
-            if ($new_prices || empty($PRC_values['PRC_ID'])) {
872
-                $PRC_values['PRC_ID'] = 0;
873
-                $price = EE_Registry::instance()->load_class(
874
-                    'Price',
875
-                    array($PRC_values),
876
-                    false,
877
-                    false
878
-                );
879
-            } else {
880
-                $price = EE_Registry::instance()->load_model('Price')->get_one_by_ID($prc['PRC_ID']);
881
-                //update this price with new values
882
-                foreach ($PRC_values as $field => $value) {
883
-                    $price->set($field, $value);
884
-                }
885
-            }
886
-            $price->save();
887
-            $updated_prices[$price->ID()] = $price;
888
-            $ticket->_add_relation_to($price, 'Price');
889
-        }
890
-        //now let's remove any prices that got removed from the ticket
891
-        if (! empty ($current_prices_on_ticket)) {
892
-            $current = array_keys($current_prices_on_ticket);
893
-            $updated = array_keys($updated_prices);
894
-            $prices_to_remove = array_diff($current, $updated);
895
-            if (! empty($prices_to_remove)) {
896
-                foreach ($prices_to_remove as $prc_id) {
897
-                    $p = $current_prices_on_ticket[$prc_id];
898
-                    $ticket->_remove_relation_to($p, 'Price');
899
-                    //delete permanently the price
900
-                    $p->delete_permanently();
901
-                }
902
-            }
903
-        }
904
-        return $ticket;
905
-    }
906
-
907
-
908
-
909
-    /**
910
-     * @param Events_Admin_Page $event_admin_obj
911
-     * @return Events_Admin_Page
912
-     */
913
-    public function autosave_handling( Events_Admin_Page $event_admin_obj)
914
-    {
915
-        return $event_admin_obj;
916
-        //doing nothing for the moment.
917
-        // todo when I get to this remember that I need to set the template args on the $event_admin_obj
918
-        // (use the set_template_args() method)
919
-        /**
920
-         * need to remember to handle TICKET DEFAULT saves correctly:  I've got two input fields in the dom:
921
-         * 1. TKT_is_default_selector (visible)
922
-         * 2. TKT_is_default (hidden)
923
-         * I think we'll use the TKT_is_default for recording whether the ticket displayed IS a default ticket
924
-         * (on new event creations). Whereas the TKT_is_default_selector is for the user to indicate they want
925
-         * this ticket to be saved as a default.
926
-         * The tricky part is, on an initial display on create or edit (or after manually updating),
927
-         * the TKT_is_default_selector will always be unselected and the TKT_is_default will only be true
928
-         * if this is a create.  However, after an autosave, users will want some sort of indicator that
929
-         * the TKT HAS been saved as a default..
930
-         * in other words we don't want to remove the check on TKT_is_default_selector. So here's what I'm thinking.
931
-         * On Autosave:
932
-         * 1. If TKT_is_default is true: we create a new TKT, send back the new id and add id to related elements,
933
-         * then set the TKT_is_default to false.
934
-         * 2. If TKT_is_default_selector is true: we create/edit existing ticket (following conditions above as well).
935
-         *  We do NOT create a new default ticket.  The checkbox stays selected after autosave.
936
-         * 3. only on MANUAL update do we check for the selection and if selected create the new default ticket.
937
-         */
938
-    }
939
-
940
-
941
-
942
-    /**
943
-     * @throws DomainException
944
-     * @throws EE_Error
945
-     */
946
-    public function pricing_metabox()
947
-    {
948
-        $existing_datetime_ids = $existing_ticket_ids = $datetime_tickets = $ticket_datetimes = array();
949
-        $event = $this->_adminpage_obj->get_cpt_model_obj();
950
-        //set is_creating_event property.
951
-        $EVT_ID = $event->ID();
952
-        $this->_is_creating_event = absint($EVT_ID) === 0;
953
-        //default main template args
954
-        $main_template_args = array(
955
-            'event_datetime_help_link' => EEH_Template::get_help_tab_link(
956
-                'event_editor_event_datetimes_help_tab',
957
-                $this->_adminpage_obj->page_slug,
958
-                $this->_adminpage_obj->get_req_action(),
959
-                false,
960
-                false
961
-            ),
962
-            // todo need to add a filter to the template for the help text
963
-            // in the Events_Admin_Page core file so we can add further help
964
-            'existing_datetime_ids'    => '',
965
-            'total_dtt_rows'           => 1,
966
-            'add_new_dtt_help_link'    => EEH_Template::get_help_tab_link(
967
-                'add_new_dtt_info',
968
-                $this->_adminpage_obj->page_slug,
969
-                $this->_adminpage_obj->get_req_action(),
970
-                false,
971
-                false
972
-            ),
973
-            //todo need to add this help info id to the Events_Admin_Page core file so we can access it here.
974
-            'datetime_rows'            => '',
975
-            'show_tickets_container'   => '',
976
-            //$this->_adminpage_obj->get_cpt_model_obj()->ID() > 1 ? ' style="display:none;"' : '',
977
-            'ticket_rows'              => '',
978
-            'existing_ticket_ids'      => '',
979
-            'total_ticket_rows'        => 1,
980
-            'ticket_js_structure'      => '',
981
-            'ee_collapsible_status'    => ' ee-collapsible-open'
982
-            //$this->_adminpage_obj->get_cpt_model_obj()->ID() > 0 ? ' ee-collapsible-closed' : ' ee-collapsible-open'
983
-        );
984
-        $timezone = $event instanceof EE_Event ? $event->timezone_string() : null;
985
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
986
-        /**
987
-         * 1. Start with retrieving Datetimes
988
-         * 2. For each datetime get related tickets
989
-         * 3. For each ticket get related prices
990
-         */
991
-        /** @var EEM_Datetime $datetime_model */
992
-        $datetime_model = EE_Registry::instance()->load_model('Datetime', array($timezone));
993
-        $datetimes = $datetime_model->get_all_event_dates($EVT_ID);
994
-        $main_template_args['total_dtt_rows'] = count($datetimes);
995
-        /**
996
-         * @see https://events.codebasehq.com/projects/event-espresso/tickets/9486
997
-         * for why we are counting $datetime_row and then setting that on the Datetime object
998
-         */
999
-        $datetime_row = 1;
1000
-        foreach ($datetimes as $datetime) {
1001
-            $DTT_ID = $datetime->get('DTT_ID');
1002
-            $datetime->set('DTT_order', $datetime_row);
1003
-            $existing_datetime_ids[] = $DTT_ID;
1004
-            //tickets attached
1005
-            $related_tickets = $datetime->ID() > 0
1006
-                ? $datetime->get_many_related(
1007
-                    'Ticket',
1008
-                    array(
1009
-                        array(
1010
-                            'OR' => array('TKT_deleted' => 1, 'TKT_deleted*' => 0),
1011
-                        ),
1012
-                        'default_where_conditions' => 'none',
1013
-                        'order_by'                 => array('TKT_order' => 'ASC'),
1014
-                    )
1015
-                )
1016
-                : array();
1017
-            //if there are no related tickets this is likely a new event OR autodraft
1018
-            // event so we need to generate the default tickets because datetimes
1019
-            // ALWAYS have at least one related ticket!!.  EXCEPT, we dont' do this if there is already more than one
1020
-            // datetime on the event.
1021
-            if (empty ($related_tickets) && count($datetimes) < 2) {
1022
-                /** @var EEM_Ticket $ticket_model */
1023
-                $ticket_model = EE_Registry::instance()->load_model('Ticket');
1024
-                $related_tickets = $ticket_model->get_all_default_tickets();
1025
-                // this should be ordered by TKT_ID, so let's grab the first default ticket
1026
-                // (which will be the main default) and ensure it has any default prices added to it (but do NOT save).
1027
-                $default_prices = EEM_Price::instance()->get_all_default_prices();
1028
-                $main_default_ticket = reset($related_tickets);
1029
-                if ($main_default_ticket instanceof EE_Ticket) {
1030
-                    foreach ($default_prices as $default_price) {
1031
-                        if ($default_price instanceof EE_Price && $default_price->is_base_price()) {
1032
-                            continue;
1033
-                        }
1034
-                        $main_default_ticket->cache('Price', $default_price);
1035
-                    }
1036
-                }
1037
-            }
1038
-            // we can't actually setup rows in this loop yet cause we don't know all
1039
-            // the unique tickets for this event yet (tickets are linked through all datetimes).
1040
-            // So we're going to temporarily cache some of that information.
1041
-            //loop through and setup the ticket rows and make sure the order is set.
1042
-            foreach ($related_tickets as $ticket) {
1043
-                $TKT_ID = $ticket->get('TKT_ID');
1044
-                $ticket_row = $ticket->get('TKT_row');
1045
-                //we only want unique tickets in our final display!!
1046
-                if (! in_array($TKT_ID, $existing_ticket_ids, true)) {
1047
-                    $existing_ticket_ids[] = $TKT_ID;
1048
-                    $all_tickets[] = $ticket;
1049
-                }
1050
-                //temporary cache of this ticket info for this datetime for later processing of datetime rows.
1051
-                $datetime_tickets[$DTT_ID][] = $ticket_row;
1052
-                //temporary cache of this datetime info for this ticket for later processing of ticket rows.
1053
-                if (
1054
-                    ! isset($ticket_datetimes[$TKT_ID])
1055
-                    || ! in_array($datetime_row, $ticket_datetimes[$TKT_ID], true)
1056
-                ) {
1057
-                    $ticket_datetimes[$TKT_ID][] = $datetime_row;
1058
-                }
1059
-            }
1060
-            $datetime_row++;
1061
-        }
1062
-        $main_template_args['total_ticket_rows'] = count($existing_ticket_ids);
1063
-        $main_template_args['existing_ticket_ids'] = implode(',', $existing_ticket_ids);
1064
-        $main_template_args['existing_datetime_ids'] = implode(',', $existing_datetime_ids);
1065
-        //sort $all_tickets by order
1066
-        usort(
1067
-            $all_tickets,
1068
-            function (EE_Ticket $a, EE_Ticket $b) {
1069
-                $a_order = (int)$a->get('TKT_order');
1070
-                $b_order = (int)$b->get('TKT_order');
1071
-                if ($a_order === $b_order) {
1072
-                    return 0;
1073
-                }
1074
-                return ($a_order < $b_order) ? -1 : 1;
1075
-            }
1076
-        );
1077
-        // k NOW we have all the data we need for setting up the dtt rows
1078
-        // and ticket rows so we start our dtt loop again.
1079
-        $datetime_row = 1;
1080
-        foreach ($datetimes as $datetime) {
1081
-            $main_template_args['datetime_rows'] .= $this->_get_datetime_row(
1082
-                $datetime_row,
1083
-                $datetime,
1084
-                $datetime_tickets,
1085
-                $all_tickets,
1086
-                false,
1087
-                $datetimes
1088
-            );
1089
-            $datetime_row++;
1090
-        }
1091
-        //then loop through all tickets for the ticket rows.
1092
-        $ticket_row = 1;
1093
-        foreach ($all_tickets as $ticket) {
1094
-            $main_template_args['ticket_rows'] .= $this->_get_ticket_row(
1095
-                $ticket_row,
1096
-                $ticket,
1097
-                $ticket_datetimes,
1098
-                $datetimes,
1099
-                false,
1100
-                $all_tickets
1101
-            );
1102
-            $ticket_row++;
1103
-        }
1104
-        $main_template_args['ticket_js_structure'] = $this->_get_ticket_js_structure($datetimes, $all_tickets);
1105
-        EEH_Template::display_template(
1106
-            PRICING_TEMPLATE_PATH . 'event_tickets_metabox_main.template.php',
1107
-            $main_template_args
1108
-        );
1109
-    }
1110
-
1111
-
1112
-
1113
-    /**
1114
-     * @param int         $datetime_row
1115
-     * @param EE_Datetime $datetime
1116
-     * @param array       $datetime_tickets
1117
-     * @param array       $all_tickets
1118
-     * @param bool        $default
1119
-     * @param array       $all_datetimes
1120
-     * @return mixed
1121
-     * @throws DomainException
1122
-     * @throws EE_Error
1123
-     */
1124
-    protected function _get_datetime_row(
1125
-        $datetime_row,
1126
-        EE_Datetime $datetime,
1127
-        $datetime_tickets = array(),
1128
-        $all_tickets = array(),
1129
-        $default = false,
1130
-        $all_datetimes = array()
1131
-    ) {
1132
-        $dtt_display_template_args = array(
1133
-            'dtt_edit_row'             => $this->_get_dtt_edit_row($datetime_row, $datetime, $default, $all_datetimes),
1134
-            'dtt_attached_tickets_row' => $this->_get_dtt_attached_tickets_row(
1135
-                $datetime_row,
1136
-                $datetime,
1137
-                $datetime_tickets,
1138
-                $all_tickets,
1139
-                $default
1140
-            ),
1141
-            'dtt_row'                  => $default ? 'DTTNUM' : $datetime_row,
1142
-        );
1143
-        return EEH_Template::display_template(
1144
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_row_wrapper.template.php',
1145
-            $dtt_display_template_args,
1146
-            true
1147
-        );
1148
-    }
1149
-
1150
-
1151
-
1152
-    /**
1153
-     * This method is used to generate a dtt fields  edit row.
1154
-     * The same row is used to generate a row with valid DTT objects
1155
-     * and the default row that is used as the skeleton by the js.
1156
-     *
1157
-     * @param int           $datetime_row  The row number for the row being generated.
1158
-     * @param EE_Datetime   $datetime
1159
-     * @param bool          $default       Whether a default row is being generated or not.
1160
-     * @param EE_Datetime[] $all_datetimes This is the array of all datetimes used in the editor.
1161
-     * @return string
1162
-     * @throws DomainException
1163
-     * @throws EE_Error
1164
-     */
1165
-    protected function _get_dtt_edit_row($datetime_row, $datetime, $default, $all_datetimes)
1166
-    {
1167
-        // if the incoming $datetime object is NOT an instance of EE_Datetime then force default to true.
1168
-        $default = ! $datetime instanceof EE_Datetime ? true : $default;
1169
-        $template_args = array(
1170
-            'dtt_row'              => $default ? 'DTTNUM' : $datetime_row,
1171
-            'event_datetimes_name' => $default ? 'DTTNAMEATTR' : 'edit_event_datetimes',
1172
-            'edit_dtt_expanded'    => '',
1173
-            'DTT_ID'               => $default ? '' : $datetime->ID(),
1174
-            'DTT_name'             => $default ? '' : $datetime->name(),
1175
-            'DTT_description'      => $default ? '' : $datetime->description(),
1176
-            'DTT_EVT_start'        => $default ? '' : $datetime->start_date($this->_date_time_format),
1177
-            'DTT_EVT_end'          => $default ? '' : $datetime->end_date($this->_date_time_format),
1178
-            'DTT_reg_limit'        => $default
1179
-                ? ''
1180
-                : $datetime->get_pretty(
1181
-                    'DTT_reg_limit',
1182
-                    'input'
1183
-                ),
1184
-            'DTT_order'            => $default ? 'DTTNUM' : $datetime_row,
1185
-            'dtt_sold'             => $default ? '0' : $datetime->get('DTT_sold'),
1186
-            'dtt_reserved'         => $default ? '0' : $datetime->reserved(),
1187
-            'clone_icon'           => ! empty($datetime) && $datetime->get('DTT_sold') > 0
1188
-                ? ''
1189
-                : 'clone-icon ee-icon ee-icon-clone clickable',
1190
-            'trash_icon'           => ! empty($datetime) && $datetime->get('DTT_sold') > 0
1191
-                ? 'ee-lock-icon'
1192
-                : 'trash-icon dashicons dashicons-post-trash clickable',
1193
-            'reg_list_url'         => $default || ! $datetime->event() instanceof \EE_Event
1194
-                ? ''
1195
-                : EE_Admin_Page::add_query_args_and_nonce(
1196
-                    array('event_id' => $datetime->event()->ID(), 'datetime_id' => $datetime->ID()),
1197
-                    REG_ADMIN_URL
1198
-                ),
1199
-        );
1200
-        $template_args['show_trash'] = count($all_datetimes) === 1 && $template_args['trash_icon'] !== 'ee-lock-icon'
1201
-            ? ' style="display:none"'
1202
-            : '';
1203
-        //allow filtering of template args at this point.
1204
-        $template_args = apply_filters(
1205
-            'FHEE__espresso_events_Pricing_Hooks___get_dtt_edit_row__template_args',
1206
-            $template_args,
1207
-            $datetime_row,
1208
-            $datetime,
1209
-            $default,
1210
-            $all_datetimes,
1211
-            $this->_is_creating_event
1212
-        );
1213
-        return EEH_Template::display_template(
1214
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_edit_row.template.php',
1215
-            $template_args,
1216
-            true
1217
-        );
1218
-    }
1219
-
1220
-
1221
-
1222
-    /**
1223
-     * @param int         $datetime_row
1224
-     * @param EE_Datetime $datetime
1225
-     * @param array       $datetime_tickets
1226
-     * @param array       $all_tickets
1227
-     * @param bool        $default
1228
-     * @return mixed
1229
-     * @throws DomainException
1230
-     * @throws EE_Error
1231
-     */
1232
-    protected function _get_dtt_attached_tickets_row(
1233
-        $datetime_row,
1234
-        $datetime,
1235
-        $datetime_tickets = array(),
1236
-        $all_tickets = array(),
1237
-        $default
1238
-    ) {
1239
-        $template_args = array(
1240
-            'dtt_row'                           => $default ? 'DTTNUM' : $datetime_row,
1241
-            'event_datetimes_name'              => $default ? 'DTTNAMEATTR' : 'edit_event_datetimes',
1242
-            'DTT_description'                   => $default ? '' : $datetime->description(),
1243
-            'datetime_tickets_list'             => $default ? '<li class="hidden"></li>' : '',
1244
-            'show_tickets_row'                  => ' style="display:none;"',
1245
-            'add_new_datetime_ticket_help_link' => EEH_Template::get_help_tab_link(
1246
-                'add_new_ticket_via_datetime',
1247
-                $this->_adminpage_obj->page_slug,
1248
-                $this->_adminpage_obj->get_req_action(),
1249
-                false,
1250
-                false
1251
-            ),
1252
-            //todo need to add this help info id to the Events_Admin_Page core file so we can access it here.
1253
-            'DTT_ID'                            => $default ? '' : $datetime->ID(),
1254
-        );
1255
-        //need to setup the list items (but only if this isn't a default skeleton setup)
1256
-        if (! $default) {
1257
-            $ticket_row = 1;
1258
-            foreach ($all_tickets as $ticket) {
1259
-                $template_args['datetime_tickets_list'] .= $this->_get_datetime_tickets_list_item(
1260
-                    $datetime_row,
1261
-                    $ticket_row,
1262
-                    $datetime,
1263
-                    $ticket,
1264
-                    $datetime_tickets,
1265
-                    $default
1266
-                );
1267
-                $ticket_row++;
1268
-            }
1269
-        }
1270
-        //filter template args at this point
1271
-        $template_args = apply_filters(
1272
-            'FHEE__espresso_events_Pricing_Hooks___get_dtt_attached_ticket_row__template_args',
1273
-            $template_args,
1274
-            $datetime_row,
1275
-            $datetime,
1276
-            $datetime_tickets,
1277
-            $all_tickets,
1278
-            $default,
1279
-            $this->_is_creating_event
1280
-        );
1281
-        return EEH_Template::display_template(
1282
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_attached_tickets_row.template.php',
1283
-            $template_args,
1284
-            true
1285
-        );
1286
-    }
1287
-
1288
-
1289
-
1290
-    /**
1291
-     * @param int         $datetime_row
1292
-     * @param int         $ticket_row
1293
-     * @param EE_Datetime $datetime
1294
-     * @param EE_Ticket   $ticket
1295
-     * @param array       $datetime_tickets
1296
-     * @param bool        $default
1297
-     * @return mixed
1298
-     * @throws DomainException
1299
-     * @throws EE_Error
1300
-     */
1301
-    protected function _get_datetime_tickets_list_item(
1302
-        $datetime_row,
1303
-        $ticket_row,
1304
-        $datetime,
1305
-        $ticket,
1306
-        $datetime_tickets = array(),
1307
-        $default
1308
-    ) {
1309
-        $dtt_tkts = $datetime instanceof EE_Datetime && isset($datetime_tickets[$datetime->ID()])
1310
-            ? $datetime_tickets[$datetime->ID()]
1311
-            : array();
1312
-        $display_row = $ticket instanceof EE_Ticket ? $ticket->get('TKT_row') : 0;
1313
-        $no_ticket = $default && empty($ticket);
1314
-        $template_args = array(
1315
-            'dtt_row'                 => $default
1316
-                ? 'DTTNUM'
1317
-                : $datetime_row,
1318
-            'tkt_row'                 => $no_ticket
1319
-                ? 'TICKETNUM'
1320
-                : $ticket_row,
1321
-            'datetime_ticket_checked' => in_array($display_row, $dtt_tkts, true)
1322
-                ? ' checked="checked"'
1323
-                : '',
1324
-            'ticket_selected'         => in_array($display_row, $dtt_tkts, true)
1325
-                ? ' ticket-selected'
1326
-                : '',
1327
-            'TKT_name'                => $no_ticket
1328
-                ? 'TKTNAME'
1329
-                : $ticket->get('TKT_name'),
1330
-            'tkt_status_class'        => $no_ticket || $this->_is_creating_event
1331
-                ? ' tkt-status-' . EE_Ticket::onsale
1332
-                : ' tkt-status-' . $ticket->ticket_status(),
1333
-        );
1334
-        //filter template args
1335
-        $template_args = apply_filters(
1336
-            'FHEE__espresso_events_Pricing_Hooks___get_datetime_tickets_list_item__template_args',
1337
-            $template_args,
1338
-            $datetime_row,
1339
-            $ticket_row,
1340
-            $datetime,
1341
-            $ticket,
1342
-            $datetime_tickets,
1343
-            $default,
1344
-            $this->_is_creating_event
1345
-        );
1346
-        return EEH_Template::display_template(
1347
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_dtt_tickets_list.template.php',
1348
-            $template_args,
1349
-            true
1350
-        );
1351
-    }
1352
-
1353
-
1354
-
1355
-    /**
1356
-     * This generates the ticket row for tickets.
1357
-     * This same method is used to generate both the actual rows and the js skeleton row
1358
-     * (when default === true)
1359
-     *
1360
-     * @param int           $ticket_row       Represents the row number being generated.
1361
-     * @param               $ticket
1362
-     * @param EE_Datetime[] $ticket_datetimes Either an array of all datetimes on all tickets indexed by each ticket
1363
-     *                                        or empty for default
1364
-     * @param EE_Datetime[] $all_datetimes    All Datetimes on the event or empty for default.
1365
-     * @param bool          $default          Whether default row being generated or not.
1366
-     * @param EE_Ticket[]   $all_tickets      This is an array of all tickets attached to the event
1367
-     *                                        (or empty in the case of defaults)
1368
-     * @return mixed
1369
-     * @throws DomainException
1370
-     * @throws EE_Error
1371
-     */
1372
-    protected function _get_ticket_row(
1373
-        $ticket_row,
1374
-        $ticket,
1375
-        $ticket_datetimes,
1376
-        $all_datetimes,
1377
-        $default = false,
1378
-        $all_tickets = array()
1379
-    ) {
1380
-        // if $ticket is not an instance of EE_Ticket then force default to true.
1381
-        $default = ! $ticket instanceof EE_Ticket ? true : $default;
1382
-        $prices = ! empty($ticket) && ! $default ? $ticket->get_many_related('Price',
1383
-            array('default_where_conditions' => 'none', 'order_by' => array('PRC_order' => 'ASC'))) : array();
1384
-        // if there is only one price (which would be the base price)
1385
-        // or NO prices and this ticket is a default ticket,
1386
-        // let's just make sure there are no cached default prices on the object.
1387
-        // This is done by not including any query_params.
1388
-        if ($ticket instanceof EE_Ticket && $ticket->is_default() && (count($prices) === 1 || empty($prices))) {
1389
-            $prices = $ticket->prices();
1390
-        }
1391
-        // check if we're dealing with a default ticket in which case
1392
-        // we don't want any starting_ticket_datetime_row values set
1393
-        // (otherwise there won't be any new relationships created for tickets based off of the default ticket).
1394
-        // This will future proof in case there is ever any behaviour change between what the primary_key defaults to.
1395
-        $default_dtt = $default || ($ticket instanceof EE_Ticket && $ticket->is_default());
1396
-        $tkt_datetimes = $ticket instanceof EE_Ticket && isset($ticket_datetimes[$ticket->ID()])
1397
-            ? $ticket_datetimes[$ticket->ID()]
1398
-            : array();
1399
-        $ticket_subtotal = $default ? 0 : $ticket->get_ticket_subtotal();
1400
-        $base_price = $default ? null : $ticket->base_price();
1401
-        $count_price_mods = EEM_Price::instance()->get_all_default_prices(true);
1402
-        //breaking out complicated condition for ticket_status
1403
-        if ($default) {
1404
-            $ticket_status_class = ' tkt-status-' . EE_Ticket::onsale;
1405
-        } else {
1406
-            $ticket_status_class = $ticket->is_default()
1407
-                ? ' tkt-status-' . EE_Ticket::onsale
1408
-                : ' tkt-status-' . $ticket->ticket_status();
1409
-        }
1410
-        //breaking out complicated condition for TKT_taxable
1411
-        if ($default) {
1412
-            $TKT_taxable = '';
1413
-        } else {
1414
-            $TKT_taxable = $ticket->taxable()
1415
-                ? ' checked="checked"'
1416
-                : '';
1417
-        }
1418
-        if ($default) {
1419
-            $TKT_status = EEH_Template::pretty_status(EE_Ticket::onsale, false, 'sentence');
1420
-        } elseif ($ticket->is_default()) {
1421
-            $TKT_status = EEH_Template::pretty_status(EE_Ticket::onsale, false, 'sentence');
1422
-        } else {
1423
-            $TKT_status = $ticket->ticket_status(true);
1424
-        }
1425
-        if ($default) {
1426
-            $TKT_min = '';
1427
-        } else {
1428
-            $TKT_min = $ticket->min();
1429
-            if ($TKT_min === -1 || $TKT_min === 0) {
1430
-                $TKT_min = '';
1431
-            }
1432
-        }
1433
-        $template_args = array(
1434
-            'tkt_row'                       => $default ? 'TICKETNUM' : $ticket_row,
1435
-            'TKT_order'                     => $default ? 'TICKETNUM' : $ticket_row,
1436
-            //on initial page load this will always be the correct order.
1437
-            'tkt_status_class'              => $ticket_status_class,
1438
-            'display_edit_tkt_row'          => ' style="display:none;"',
1439
-            'edit_tkt_expanded'             => '',
1440
-            'edit_tickets_name'             => $default ? 'TICKETNAMEATTR' : 'edit_tickets',
1441
-            'TKT_name'                      => $default ? '' : $ticket->name(),
1442
-            'TKT_start_date'                => $default
1443
-                ? ''
1444
-                : $ticket->get_date('TKT_start_date', $this->_date_time_format),
1445
-            'TKT_end_date'                  => $default
1446
-                ? ''
1447
-                : $ticket->get_date('TKT_end_date', $this->_date_time_format),
1448
-            'TKT_status'                    => $TKT_status,
1449
-            'TKT_price'                     => $default
1450
-                ? ''
1451
-                : EEH_Template::format_currency(
1452
-                    $ticket->get_ticket_total_with_taxes(),
1453
-                    false,
1454
-                    false
1455
-                ),
1456
-            'TKT_price_code'                => EE_Registry::instance()->CFG->currency->code,
1457
-            'TKT_price_amount'              => $default ? 0 : $ticket_subtotal,
1458
-            'TKT_qty'                       => $default
1459
-                ? ''
1460
-                : $ticket->get_pretty('TKT_qty', 'symbol'),
1461
-            'TKT_qty_for_input'             => $default
1462
-                ? ''
1463
-                : $ticket->get_pretty('TKT_qty', 'input'),
1464
-            'TKT_uses'                      => $default
1465
-                ? ''
1466
-                : $ticket->get_pretty('TKT_uses', 'input'),
1467
-            'TKT_min'                       => $TKT_min,
1468
-            'TKT_max'                       => $default
1469
-                ? ''
1470
-                : $ticket->get_pretty('TKT_max', 'input'),
1471
-            'TKT_sold'                      => $default ? 0 : $ticket->tickets_sold('ticket'),
1472
-            'TKT_reserved'                  => $default ? 0 : $ticket->reserved(),
1473
-            'TKT_registrations'             => $default
1474
-                ? 0
1475
-                : $ticket->count_registrations(
1476
-                    array(
1477
-                        array(
1478
-                            'STS_ID' => array(
1479
-                                '!=',
1480
-                                EEM_Registration::status_id_incomplete,
1481
-                            ),
1482
-                        ),
1483
-                    )
1484
-                ),
1485
-            'TKT_ID'                        => $default ? 0 : $ticket->ID(),
1486
-            'TKT_description'               => $default ? '' : $ticket->description(),
1487
-            'TKT_is_default'                => $default ? 0 : $ticket->is_default(),
1488
-            'TKT_required'                  => $default ? 0 : $ticket->required(),
1489
-            'TKT_is_default_selector'       => '',
1490
-            'ticket_price_rows'             => '',
1491
-            'TKT_base_price'                => $default || ! $base_price instanceof EE_Price
1492
-                ? ''
1493
-                : $base_price->get_pretty('PRC_amount', 'localized_float'),
1494
-            'TKT_base_price_ID'             => $default || ! $base_price instanceof EE_Price ? 0 : $base_price->ID(),
1495
-            'show_price_modifier'           => count($prices) > 1 || ($default && $count_price_mods > 0)
1496
-                ? ''
1497
-                : ' style="display:none;"',
1498
-            'show_price_mod_button'         => count($prices) > 1
1499
-                                               || ($default && $count_price_mods > 0)
1500
-                                               || (! $default && $ticket->deleted())
1501
-                ? ' style="display:none;"'
1502
-                : '',
1503
-            'total_price_rows'              => count($prices) > 1 ? count($prices) : 1,
1504
-            'ticket_datetimes_list'         => $default ? '<li class="hidden"></li>' : '',
1505
-            'starting_ticket_datetime_rows' => $default || $default_dtt ? '' : implode(',', $tkt_datetimes),
1506
-            'ticket_datetime_rows'          => $default ? '' : implode(',', $tkt_datetimes),
1507
-            'existing_ticket_price_ids'     => $default ? '' : implode(',', array_keys($prices)),
1508
-            'ticket_template_id'            => $default ? 0 : $ticket->get('TTM_ID'),
1509
-            'TKT_taxable'                   => $TKT_taxable,
1510
-            'display_subtotal'              => $ticket instanceof EE_Ticket && $ticket->taxable()
1511
-                ? ''
1512
-                : ' style="display:none"',
1513
-            'price_currency_symbol'         => EE_Registry::instance()->CFG->currency->sign,
1514
-            'TKT_subtotal_amount_display'   => EEH_Template::format_currency(
1515
-                $ticket_subtotal,
1516
-                false,
1517
-                false
1518
-            ),
1519
-            'TKT_subtotal_amount'           => $ticket_subtotal,
1520
-            'tax_rows'                      => $this->_get_tax_rows($ticket_row, $ticket),
1521
-            'disabled'                      => $ticket instanceof EE_Ticket && $ticket->deleted(),
1522
-            'ticket_archive_class'          => $ticket instanceof EE_Ticket && $ticket->deleted()
1523
-                ? ' ticket-archived'
1524
-                : '',
1525
-            'trash_icon'                    => $ticket instanceof EE_Ticket
1526
-                                               && $ticket->deleted()
1527
-                                               && ! $ticket->is_permanently_deleteable()
1528
-                ? 'ee-lock-icon '
1529
-                : 'trash-icon dashicons dashicons-post-trash clickable',
1530
-            'clone_icon'                    => $ticket instanceof EE_Ticket && $ticket->deleted()
1531
-                ? ''
1532
-                : 'clone-icon ee-icon ee-icon-clone clickable',
1533
-        );
1534
-        $template_args['trash_hidden'] = count($all_tickets) === 1 && $template_args['trash_icon'] !== 'ee-lock-icon'
1535
-            ? ' style="display:none"'
1536
-            : '';
1537
-        //handle rows that should NOT be empty
1538
-        if (empty($template_args['TKT_start_date'])) {
1539
-            //if empty then the start date will be now.
1540
-            $template_args['TKT_start_date'] = date($this->_date_time_format,
1541
-                current_time('timestamp'));
1542
-            $template_args['tkt_status_class'] = ' tkt-status-' . EE_Ticket::onsale;
1543
-        }
1544
-        if (empty($template_args['TKT_end_date'])) {
1545
-            //get the earliest datetime (if present);
1546
-            $earliest_dtt = $this->_adminpage_obj->get_cpt_model_obj()->ID() > 0
1547
-                ? $this->_adminpage_obj->get_cpt_model_obj()->get_first_related(
1548
-                    'Datetime',
1549
-                    array('order_by' => array('DTT_EVT_start' => 'ASC'))
1550
-                )
1551
-                : null;
1552
-            if (! empty($earliest_dtt)) {
1553
-                $template_args['TKT_end_date'] = $earliest_dtt->get_datetime(
1554
-                    'DTT_EVT_start',
1555
-                    $this->_date_time_format
1556
-                );
1557
-            } else {
1558
-                //default so let's just use what's been set for the default date-time which is 30 days from now.
1559
-                $template_args['TKT_end_date'] = date(
1560
-                    $this->_date_time_format,
1561
-                    mktime(24, 0, 0, date('m'), date('d') + 29, date('Y')
1562
-                    )
1563
-                );
1564
-            }
1565
-            $template_args['tkt_status_class'] = ' tkt-status-' . EE_Ticket::onsale;
1566
-        }
1567
-        //generate ticket_datetime items
1568
-        if (! $default) {
1569
-            $datetime_row = 1;
1570
-            foreach ($all_datetimes as $datetime) {
1571
-                $template_args['ticket_datetimes_list'] .= $this->_get_ticket_datetime_list_item(
1572
-                    $datetime_row,
1573
-                    $ticket_row,
1574
-                    $datetime,
1575
-                    $ticket,
1576
-                    $ticket_datetimes,
1577
-                    $default
1578
-                );
1579
-                $datetime_row++;
1580
-            }
1581
-        }
1582
-        $price_row = 1;
1583
-        foreach ($prices as $price) {
1584
-            if (! $price instanceof EE_Price)  {
1585
-                continue;
1586
-            }
1587
-            if ($price->is_base_price()) {
1588
-                $price_row++;
1589
-                continue;
1590
-            }
1591
-            $show_trash = !((count($prices) > 1 && $price_row === 1) || count($prices) === 1);
1592
-            $show_create = !(count($prices) > 1 && count($prices) !== $price_row);
1593
-            $template_args['ticket_price_rows'] .= $this->_get_ticket_price_row(
1594
-                $ticket_row,
1595
-                $price_row,
1596
-                $price,
1597
-                $default,
1598
-                $ticket,
1599
-                $show_trash,
1600
-                $show_create
1601
-            );
1602
-            $price_row++;
1603
-        }
1604
-        //filter $template_args
1605
-        $template_args = apply_filters(
1606
-            'FHEE__espresso_events_Pricing_Hooks___get_ticket_row__template_args',
1607
-            $template_args,
1608
-            $ticket_row,
1609
-            $ticket,
1610
-            $ticket_datetimes,
1611
-            $all_datetimes,
1612
-            $default,
1613
-            $all_tickets,
1614
-            $this->_is_creating_event
1615
-        );
1616
-        return EEH_Template::display_template(
1617
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_ticket_row.template.php',
1618
-            $template_args,
1619
-            true
1620
-        );
1621
-    }
1622
-
1623
-
1624
-
1625
-    /**
1626
-     * @param int            $ticket_row
1627
-     * @param EE_Ticket|null $ticket
1628
-     * @return string
1629
-     * @throws DomainException
1630
-     * @throws EE_Error
1631
-     */
1632
-    protected function _get_tax_rows($ticket_row, $ticket)
1633
-    {
1634
-        $tax_rows = '';
1635
-        /** @var EE_Price[] $taxes */
1636
-        $taxes = empty($ticket) ? EE_Taxes::get_taxes_for_admin() : $ticket->get_ticket_taxes_for_admin();
1637
-        foreach ($taxes as $tax) {
1638
-            $tax_added = $this->_get_tax_added($tax, $ticket);
1639
-            $template_args = array(
1640
-                'display_tax'       => ! empty($ticket) && $ticket->get('TKT_taxable')
1641
-                    ? ''
1642
-                    : ' style="display:none;"',
1643
-                'tax_id'            => $tax->ID(),
1644
-                'tkt_row'           => $ticket_row,
1645
-                'tax_label'         => $tax->get('PRC_name'),
1646
-                'tax_added'         => $tax_added,
1647
-                'tax_added_display' => EEH_Template::format_currency($tax_added, false, false),
1648
-                'tax_amount'        => $tax->get('PRC_amount'),
1649
-            );
1650
-            $template_args = apply_filters(
1651
-                'FHEE__espresso_events_Pricing_Hooks___get_tax_rows__template_args',
1652
-                $template_args,
1653
-                $ticket_row,
1654
-                $ticket,
1655
-                $this->_is_creating_event
1656
-            );
1657
-            $tax_rows .= EEH_Template::display_template(
1658
-                PRICING_TEMPLATE_PATH . 'event_tickets_datetime_ticket_tax_row.template.php',
1659
-                $template_args,
1660
-                true
1661
-            );
1662
-        }
1663
-        return $tax_rows;
1664
-    }
1665
-
1666
-
1667
-
1668
-    /**
1669
-     * @param EE_Price       $tax
1670
-     * @param EE_Ticket|null $ticket
1671
-     * @return float|int
1672
-     * @throws EE_Error
1673
-     */
1674
-    protected function _get_tax_added(EE_Price $tax, $ticket)
1675
-    {
1676
-        $subtotal = empty($ticket) ? 0 : $ticket->get_ticket_subtotal();
1677
-        return $subtotal * $tax->get('PRC_amount') / 100;
1678
-    }
1679
-
1680
-
1681
-
1682
-    /**
1683
-     * @param int            $ticket_row
1684
-     * @param int            $price_row
1685
-     * @param EE_Price|null  $price
1686
-     * @param bool           $default
1687
-     * @param EE_Ticket|null $ticket
1688
-     * @param bool           $show_trash
1689
-     * @param bool           $show_create
1690
-     * @return mixed
1691
-     * @throws DomainException
1692
-     * @throws EE_Error
1693
-     */
1694
-    protected function _get_ticket_price_row(
1695
-        $ticket_row,
1696
-        $price_row,
1697
-        $price,
1698
-        $default,
1699
-        $ticket,
1700
-        $show_trash = true,
1701
-        $show_create = true
1702
-    ) {
1703
-        $send_disabled = ! empty($ticket) && $ticket->get('TKT_deleted');
1704
-        $template_args = array(
1705
-            'tkt_row'               => $default && empty($ticket)
1706
-                ? 'TICKETNUM'
1707
-                : $ticket_row,
1708
-            'PRC_order'             => $default && empty($price)
1709
-                ? 'PRICENUM'
1710
-                : $price_row,
1711
-            'edit_prices_name'      => $default && empty($price)
1712
-                ? 'PRICENAMEATTR'
1713
-                : 'edit_prices',
1714
-            'price_type_selector'   => $default && empty($price)
1715
-                ? $this->_get_base_price_template($ticket_row, $price_row, $price, $default)
1716
-                : $this->_get_price_type_selector($ticket_row, $price_row, $price, $default, $send_disabled),
1717
-            'PRC_ID'                => $default && empty($price)
1718
-                ? 0
1719
-                : $price->ID(),
1720
-            'PRC_is_default'        => $default && empty($price)
1721
-                ? 0
1722
-                : $price->get('PRC_is_default'),
1723
-            'PRC_name'              => $default && empty($price)
1724
-                ? ''
1725
-                : $price->get('PRC_name'),
1726
-            'price_currency_symbol' => EE_Registry::instance()->CFG->currency->sign,
1727
-            'show_plus_or_minus'    => $default && empty($price)
1728
-                ? ''
1729
-                : ' style="display:none;"',
1730
-            'show_plus'             => ($default && empty($price)) || ($price->is_discount() || $price->is_base_price())
1731
-                ? ' style="display:none;"'
1732
-                : '',
1733
-            'show_minus'            => ($default && empty($price)) || ! $price->is_discount()
1734
-                ? ' style="display:none;"'
1735
-                : '',
1736
-            'show_currency_symbol'  => ($default && empty($price)) || $price->is_percent()
1737
-                ? ' style="display:none"'
1738
-                : '',
1739
-            'PRC_amount'            => $default && empty($price)
1740
-                ? 0
1741
-                : $price->get_pretty('PRC_amount',
1742
-                    'localized_float'),
1743
-            'show_percentage'       => ($default && empty($price)) || ! $price->is_percent()
1744
-                ? ' style="display:none;"'
1745
-                : '',
1746
-            'show_trash_icon'       => $show_trash
1747
-                ? ''
1748
-                : ' style="display:none;"',
1749
-            'show_create_button'    => $show_create
1750
-                ? ''
1751
-                : ' style="display:none;"',
1752
-            'PRC_desc'              => $default && empty($price)
1753
-                ? ''
1754
-                : $price->get('PRC_desc'),
1755
-            'disabled'              => ! empty($ticket) && $ticket->get('TKT_deleted'),
1756
-        );
1757
-        $template_args = apply_filters(
1758
-            'FHEE__espresso_events_Pricing_Hooks___get_ticket_price_row__template_args',
1759
-            $template_args,
1760
-            $ticket_row,
1761
-            $price_row,
1762
-            $price,
1763
-            $default,
1764
-            $ticket,
1765
-            $show_trash,
1766
-            $show_create,
1767
-            $this->_is_creating_event
1768
-        );
1769
-        return EEH_Template::display_template(
1770
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_ticket_price_row.template.php',
1771
-            $template_args,
1772
-            true
1773
-        );
1774
-    }
1775
-
1776
-
1777
-
1778
-    /**
1779
-     * @param int      $ticket_row
1780
-     * @param int      $price_row
1781
-     * @param EE_Price $price
1782
-     * @param bool     $default
1783
-     * @param bool     $disabled
1784
-     * @return mixed
1785
-     * @throws DomainException
1786
-     * @throws EE_Error
1787
-     */
1788
-    protected function _get_price_type_selector($ticket_row, $price_row, $price, $default, $disabled = false)
1789
-    {
1790
-        if ($price->is_base_price()) {
1791
-            return $this->_get_base_price_template($ticket_row, $price_row, $price, $default);
1792
-        }
1793
-        return $this->_get_price_modifier_template($ticket_row, $price_row, $price, $default, $disabled);
1794
-    }
1795
-
1796
-
1797
-
1798
-    /**
1799
-     * @param int      $ticket_row
1800
-     * @param int      $price_row
1801
-     * @param EE_Price $price
1802
-     * @param bool     $default
1803
-     * @return mixed
1804
-     * @throws DomainException
1805
-     * @throws EE_Error
1806
-     */
1807
-    protected function _get_base_price_template($ticket_row, $price_row, $price, $default)
1808
-    {
1809
-        $template_args = array(
1810
-            'tkt_row'                   => $default ? 'TICKETNUM' : $ticket_row,
1811
-            'PRC_order'                 => $default && empty($price) ? 'PRICENUM' : $price_row,
1812
-            'PRT_ID'                    => $default && empty($price) ? 1 : $price->get('PRT_ID'),
1813
-            'PRT_name'                  => esc_html__('Price', 'event_espresso'),
1814
-            'price_selected_operator'   => '+',
1815
-            'price_selected_is_percent' => 0,
1816
-        );
1817
-        $template_args = apply_filters(
1818
-            'FHEE__espresso_events_Pricing_Hooks___get_base_price_template__template_args',
1819
-            $template_args,
1820
-            $ticket_row,
1821
-            $price_row,
1822
-            $price,
1823
-            $default,
1824
-            $this->_is_creating_event
1825
-        );
1826
-        return EEH_Template::display_template(
1827
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_price_type_base.template.php',
1828
-            $template_args,
1829
-            true
1830
-        );
1831
-    }
1832
-
1833
-
1834
-
1835
-    /**
1836
-     * @param int      $ticket_row
1837
-     * @param int      $price_row
1838
-     * @param EE_Price $price
1839
-     * @param bool     $default
1840
-     * @param bool     $disabled
1841
-     * @return mixed
1842
-     * @throws DomainException
1843
-     * @throws EE_Error
1844
-     */
1845
-    protected function _get_price_modifier_template(
1846
-        $ticket_row,
1847
-        $price_row,
1848
-        $price,
1849
-        $default,
1850
-        $disabled = false
1851
-    ) {
1852
-        $select_name = $default && ! $price instanceof EE_Price
1853
-            ? 'edit_prices[TICKETNUM][PRICENUM][PRT_ID]'
1854
-            : 'edit_prices[' . $ticket_row . '][' . $price_row . '][PRT_ID]';
1855
-        /** @var EEM_Price_Type $price_type_model */
1856
-        $price_type_model = EE_Registry::instance()->load_model('Price_Type');
1857
-        $price_types = $price_type_model->get_all(array(
1858
-            array(
1859
-                'OR' => array(
1860
-                    'PBT_ID'  => '2',
1861
-                    'PBT_ID*' => '3',
1862
-                ),
1863
-            ),
1864
-        ));
1865
-        $all_price_types = $default && ! $price instanceof EE_Price
1866
-            ? array(esc_html__('Select Modifier', 'event_espresso'))
1867
-            : array();
1868
-        $selected_price_type_id = $default && ! $price instanceof EE_Price ? 0 : $price->type();
1869
-        $price_option_spans = '';
1870
-        //setup price types for selector
1871
-        foreach ($price_types as $price_type) {
1872
-            if (! $price_type instanceof EE_Price_Type) {
1873
-                continue;
1874
-            }
1875
-            $all_price_types[$price_type->ID()] = $price_type->get('PRT_name');
1876
-            //while we're in the loop let's setup the option spans used by js
1877
-            $span_args = array(
1878
-                'PRT_ID'         => $price_type->ID(),
1879
-                'PRT_operator'   => $price_type->is_discount() ? '-' : '+',
1880
-                'PRT_is_percent' => $price_type->get('PRT_is_percent') ? 1 : 0,
1881
-            );
1882
-            $price_option_spans .= EEH_Template::display_template(
1883
-                PRICING_TEMPLATE_PATH . 'event_tickets_datetime_price_option_span.template.php',
1884
-                $span_args,
1885
-                true
1886
-            );
1887
-        }
1888
-        $select_name = $disabled ? 'archive_price[' . $ticket_row . '][' . $price_row . '][PRT_ID]' : $select_name;
1889
-        $select_input = new EE_Select_Input(
1890
-            $all_price_types,
1891
-            array(
1892
-                'default'               => $selected_price_type_id,
1893
-                'html_name'             => $select_name,
1894
-                'html_class'            => 'edit-price-PRT_ID',
1895
-                'html_other_attributes' => $disabled ? 'style="width:auto;" disabled' : 'style="width:auto;"',
1896
-            )
1897
-        );
1898
-        $price_selected_operator = $price instanceof EE_Price && $price->is_discount() ? '-' : '+';
1899
-        $price_selected_operator = $default && ! $price instanceof EE_Price ? '' : $price_selected_operator;
1900
-        $price_selected_is_percent = $price instanceof EE_Price && $price->is_percent() ? 1 : 0;
1901
-        $price_selected_is_percent = $default && ! $price instanceof EE_Price ? '' : $price_selected_is_percent;
1902
-        $template_args = array(
1903
-            'tkt_row'                   => $default ? 'TICKETNUM' : $ticket_row,
1904
-            'PRC_order'                 => $default && ! $price instanceof EE_Price ? 'PRICENUM' : $price_row,
1905
-            'price_modifier_selector'   => $select_input->get_html_for_input(),
1906
-            'main_name'                 => $select_name,
1907
-            'selected_price_type_id'    => $selected_price_type_id,
1908
-            'price_option_spans'        => $price_option_spans,
1909
-            'price_selected_operator'   => $price_selected_operator,
1910
-            'price_selected_is_percent' => $price_selected_is_percent,
1911
-            'disabled'                  => $disabled,
1912
-        );
1913
-        $template_args = apply_filters(
1914
-            'FHEE__espresso_events_Pricing_Hooks___get_price_modifier_template__template_args',
1915
-            $template_args,
1916
-            $ticket_row,
1917
-            $price_row,
1918
-            $price,
1919
-            $default,
1920
-            $disabled,
1921
-            $this->_is_creating_event
1922
-        );
1923
-        return EEH_Template::display_template(
1924
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_price_modifier_selector.template.php',
1925
-            $template_args,
1926
-            true
1927
-        );
1928
-    }
1929
-
1930
-
1931
-
1932
-    /**
1933
-     * @param int              $datetime_row
1934
-     * @param int              $ticket_row
1935
-     * @param EE_Datetime|null $datetime
1936
-     * @param EE_Ticket|null   $ticket
1937
-     * @param array            $ticket_datetimes
1938
-     * @param bool             $default
1939
-     * @return mixed
1940
-     * @throws DomainException
1941
-     * @throws EE_Error
1942
-     */
1943
-    protected function _get_ticket_datetime_list_item(
1944
-        $datetime_row,
1945
-        $ticket_row,
1946
-        $datetime,
1947
-        $ticket,
1948
-        $ticket_datetimes = array(),
1949
-        $default
1950
-    ) {
1951
-        $tkt_datetimes = $ticket instanceof EE_Ticket && isset($ticket_datetimes[$ticket->ID()])
1952
-            ? $ticket_datetimes[$ticket->ID()]
1953
-            : array();
1954
-        $template_args = array(
1955
-            'dtt_row'                  => $default && ! $datetime instanceof EE_Datetime
1956
-                ? 'DTTNUM'
1957
-                : $datetime_row,
1958
-            'tkt_row'                  => $default
1959
-                ? 'TICKETNUM'
1960
-                : $ticket_row,
1961
-            'ticket_datetime_selected' => in_array($datetime_row, $tkt_datetimes, true)
1962
-                ? ' ticket-selected'
1963
-                : '',
1964
-            'ticket_datetime_checked'  => in_array($datetime_row, $tkt_datetimes, true)
1965
-                ? ' checked="checked"'
1966
-                : '',
1967
-            'DTT_name'                 => $default && empty($datetime)
1968
-                ? 'DTTNAME'
1969
-                : $datetime->get_dtt_display_name(true),
1970
-            'tkt_status_class'         => '',
1971
-        );
1972
-        $template_args = apply_filters(
1973
-            'FHEE__espresso_events_Pricing_Hooks___get_ticket_datetime_list_item__template_args',
1974
-            $template_args,
1975
-            $datetime_row,
1976
-            $ticket_row,
1977
-            $datetime,
1978
-            $ticket,
1979
-            $ticket_datetimes,
1980
-            $default,
1981
-            $this->_is_creating_event
1982
-        );
1983
-        return EEH_Template::display_template(
1984
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_ticket_datetimes_list_item.template.php',
1985
-            $template_args,
1986
-            true
1987
-        );
1988
-    }
1989
-
1990
-
1991
-
1992
-    /**
1993
-     * @param array $all_datetimes
1994
-     * @param array $all_tickets
1995
-     * @return mixed
1996
-     * @throws DomainException
1997
-     * @throws EE_Error
1998
-     */
1999
-    protected function _get_ticket_js_structure($all_datetimes = array(), $all_tickets = array())
2000
-    {
2001
-        $template_args = array(
2002
-            'default_datetime_edit_row'                => $this->_get_dtt_edit_row(
2003
-                'DTTNUM',
2004
-                null,
2005
-                true,
2006
-                $all_datetimes
2007
-            ),
2008
-            'default_ticket_row'                       => $this->_get_ticket_row(
2009
-                'TICKETNUM',
2010
-                null,
2011
-                array(),
2012
-                array(),
2013
-                true
2014
-            ),
2015
-            'default_price_row'                        => $this->_get_ticket_price_row(
2016
-                'TICKETNUM',
2017
-                'PRICENUM',
2018
-                null,
2019
-                true,
2020
-                null
2021
-            ),
2022
-            'default_price_rows'                       => '',
2023
-            'default_base_price_amount'                => 0,
2024
-            'default_base_price_name'                  => '',
2025
-            'default_base_price_description'           => '',
2026
-            'default_price_modifier_selector_row'      => $this->_get_price_modifier_template(
2027
-                'TICKETNUM',
2028
-                'PRICENUM',
2029
-                null,
2030
-                true
2031
-            ),
2032
-            'default_available_tickets_for_datetime'   => $this->_get_dtt_attached_tickets_row(
2033
-                'DTTNUM',
2034
-                null,
2035
-                array(),
2036
-                array(),
2037
-                true
2038
-            ),
2039
-            'existing_available_datetime_tickets_list' => '',
2040
-            'existing_available_ticket_datetimes_list' => '',
2041
-            'new_available_datetime_ticket_list_item'  => $this->_get_datetime_tickets_list_item(
2042
-                'DTTNUM',
2043
-                'TICKETNUM',
2044
-                null,
2045
-                null,
2046
-                array(),
2047
-                true
2048
-            ),
2049
-            'new_available_ticket_datetime_list_item'  => $this->_get_ticket_datetime_list_item(
2050
-                'DTTNUM',
2051
-                'TICKETNUM',
2052
-                null,
2053
-                null,
2054
-                array(),
2055
-                true
2056
-            ),
2057
-        );
2058
-        $ticket_row = 1;
2059
-        foreach ($all_tickets as $ticket) {
2060
-            $template_args['existing_available_datetime_tickets_list'] .= $this->_get_datetime_tickets_list_item(
2061
-                'DTTNUM',
2062
-                $ticket_row,
2063
-                null,
2064
-                $ticket,
2065
-                array(),
2066
-                true
2067
-            );
2068
-            $ticket_row++;
2069
-        }
2070
-        $datetime_row = 1;
2071
-        foreach ($all_datetimes as $datetime) {
2072
-            $template_args['existing_available_ticket_datetimes_list'] .= $this->_get_ticket_datetime_list_item(
2073
-                $datetime_row,
2074
-                'TICKETNUM',
2075
-                $datetime,
2076
-                null,
2077
-                array(),
2078
-                true
2079
-            );
2080
-            $datetime_row++;
2081
-        }
2082
-        /** @var EEM_Price $price_model */
2083
-        $price_model = EE_Registry::instance()->load_model('Price');
2084
-        $default_prices = $price_model->get_all_default_prices();
2085
-        $price_row = 1;
2086
-        foreach ($default_prices as $price) {
2087
-            if (! $price instanceof EE_Price) {
2088
-                continue;
2089
-            }
2090
-            if ($price->is_base_price()) {
2091
-                $template_args['default_base_price_amount'] = $price->get_pretty(
2092
-                    'PRC_amount',
2093
-                    'localized_float'
2094
-                );
2095
-                $template_args['default_base_price_name'] = $price->get('PRC_name');
2096
-                $template_args['default_base_price_description'] = $price->get('PRC_desc');
2097
-                $price_row++;
2098
-                continue;
2099
-            }
2100
-            $show_trash = !((count($default_prices) > 1 && $price_row === 1) || count($default_prices) === 1);
2101
-            $show_create = !(count($default_prices) > 1 && count($default_prices) !== $price_row);
2102
-            $template_args['default_price_rows'] .= $this->_get_ticket_price_row(
2103
-                'TICKETNUM',
2104
-                $price_row,
2105
-                $price,
2106
-                true,
2107
-                null,
2108
-                $show_trash,
2109
-                $show_create
2110
-            );
2111
-            $price_row++;
2112
-        }
2113
-        $template_args = apply_filters(
2114
-            'FHEE__espresso_events_Pricing_Hooks___get_ticket_js_structure__template_args',
2115
-            $template_args,
2116
-            $all_datetimes,
2117
-            $all_tickets,
2118
-            $this->_is_creating_event
2119
-        );
2120
-        return EEH_Template::display_template(
2121
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_ticket_js_structure.template.php',
2122
-            $template_args,
2123
-            true
2124
-        );
2125
-    }
18
+	/**
19
+	 * This property is just used to hold the status of whether an event is currently being
20
+	 * created (true) or edited (false)
21
+	 *
22
+	 * @access protected
23
+	 * @var bool
24
+	 */
25
+	protected $_is_creating_event;
26
+
27
+
28
+	/**
29
+	 * Used to contain the format strings for date and time that will be used for php date and
30
+	 * time.
31
+	 * Is set in the _set_hooks_properties() method.
32
+	 *
33
+	 * @var array
34
+	 */
35
+	protected $_date_format_strings;
36
+
37
+
38
+	/**
39
+	 * @var string $_date_time_format
40
+	 */
41
+	protected $_date_time_format;
42
+
43
+
44
+
45
+	/**
46
+	 *
47
+	 */
48
+	protected function _set_hooks_properties()
49
+	{
50
+		$this->_name = 'pricing';
51
+		//capability check
52
+		if (! EE_Registry::instance()->CAP->current_user_can(
53
+			'ee_read_default_prices',
54
+			'advanced_ticket_datetime_metabox'
55
+		)) {
56
+			return;
57
+		}
58
+		$this->_setup_metaboxes();
59
+		$this->_set_date_time_formats();
60
+		$this->_validate_format_strings();
61
+		$this->_set_scripts_styles();
62
+		// commented out temporarily until logic is implemented in callback
63
+		// add_action(
64
+		//     'AHEE__EE_Admin_Page_CPT__do_extra_autosave_stuff__after_Extend_Events_Admin_Page',
65
+		//     array($this, 'autosave_handling')
66
+		// );
67
+		add_filter(
68
+			'FHEE__Events_Admin_Page___insert_update_cpt_item__event_update_callbacks',
69
+			array($this, 'caf_updates')
70
+		);
71
+	}
72
+
73
+
74
+
75
+	/**
76
+	 * @return void
77
+	 */
78
+	protected function _setup_metaboxes()
79
+	{
80
+		//if we were going to add our own metaboxes we'd use the below.
81
+		$this->_metaboxes = array(
82
+			0 => array(
83
+				'page_route' => array('edit', 'create_new'),
84
+				'func'       => 'pricing_metabox',
85
+				'label'      => esc_html__('Event Tickets & Datetimes', 'event_espresso'),
86
+				'priority'   => 'high',
87
+				'context'    => 'normal',
88
+			),
89
+		);
90
+		$this->_remove_metaboxes = array(
91
+			0 => array(
92
+				'page_route' => array('edit', 'create_new'),
93
+				'id'         => 'espresso_event_editor_tickets',
94
+				'context'    => 'normal',
95
+			),
96
+		);
97
+	}
98
+
99
+
100
+
101
+	/**
102
+	 * @return void
103
+	 */
104
+	protected function _set_date_time_formats()
105
+	{
106
+		/**
107
+		 * Format strings for date and time.  Defaults are existing behaviour from 4.1.
108
+		 * Note, that if you return null as the value for 'date', and 'time' in the array, then
109
+		 * EE will automatically use the set wp_options, 'date_format', and 'time_format'.
110
+		 *
111
+		 * @since 4.6.7
112
+		 * @var array  Expected an array returned with 'date' and 'time' keys.
113
+		 */
114
+		$this->_date_format_strings = apply_filters(
115
+			'FHEE__espresso_events_Pricing_Hooks___set_hooks_properties__date_format_strings',
116
+			array(
117
+				'date' => 'Y-m-d',
118
+				'time' => 'h:i a',
119
+			)
120
+		);
121
+		//validate
122
+		$this->_date_format_strings['date'] = isset($this->_date_format_strings['date'])
123
+			? $this->_date_format_strings['date']
124
+			: null;
125
+		$this->_date_format_strings['time'] = isset($this->_date_format_strings['time'])
126
+			? $this->_date_format_strings['time']
127
+			: null;
128
+		$this->_date_time_format = $this->_date_format_strings['date'] . ' ' . $this->_date_format_strings['time'];
129
+	}
130
+
131
+
132
+
133
+	/**
134
+	 * @return void
135
+	 */
136
+	protected function _validate_format_strings()
137
+	{
138
+		//validate format strings
139
+		$format_validation = EEH_DTT_Helper::validate_format_string(
140
+			$this->_date_time_format
141
+		);
142
+		if (is_array($format_validation)) {
143
+			$msg = '<p>';
144
+			$msg .= sprintf(
145
+				esc_html__(
146
+					'The format "%s" was likely added via a filter and is invalid for the following reasons:',
147
+					'event_espresso'
148
+				),
149
+				$this->_date_time_format
150
+			);
151
+			$msg .= '</p><ul>';
152
+			foreach ($format_validation as $error) {
153
+				$msg .= '<li>' . $error . '</li>';
154
+			}
155
+			$msg .= '</ul><p>';
156
+			$msg .= sprintf(
157
+				esc_html__(
158
+					'%sPlease note that your date and time formats have been reset to "Y-m-d" and "h:i a" respectively.%s',
159
+					'event_espresso'
160
+				),
161
+				'<span style="color:#D54E21;">',
162
+				'</span>'
163
+			);
164
+			$msg .= '</p>';
165
+			EE_Error::add_attention($msg, __FILE__, __FUNCTION__, __LINE__);
166
+			$this->_date_format_strings = array(
167
+				'date' => 'Y-m-d',
168
+				'time' => 'h:i a',
169
+			);
170
+		}
171
+	}
172
+
173
+
174
+
175
+	/**
176
+	 * @return void
177
+	 */
178
+	protected function _set_scripts_styles()
179
+	{
180
+		$this->_scripts_styles = array(
181
+			'registers'   => array(
182
+				'ee-tickets-datetimes-css' => array(
183
+					'url'  => PRICING_ASSETS_URL . 'event-tickets-datetimes.css',
184
+					'type' => 'css',
185
+				),
186
+				'ee-dtt-ticket-metabox'    => array(
187
+					'url'     => PRICING_ASSETS_URL . 'ee-datetime-ticket-metabox.js',
188
+					'depends' => array('ee-datepicker', 'ee-dialog', 'underscore'),
189
+				),
190
+			),
191
+			'deregisters' => array(
192
+				'event-editor-css'       => array('type' => 'css'),
193
+				'event-datetime-metabox' => array('type' => 'js'),
194
+			),
195
+			'enqueues'    => array(
196
+				'ee-tickets-datetimes-css' => array('edit', 'create_new'),
197
+				'ee-dtt-ticket-metabox'    => array('edit', 'create_new'),
198
+			),
199
+			'localize'    => array(
200
+				'ee-dtt-ticket-metabox' => array(
201
+					'DTT_TRASH_BLOCK'       => array(
202
+						'main_warning'            => esc_html__(
203
+							'The Datetime you are attempting to trash is the only datetime selected for the following ticket(s):',
204
+							'event_espresso'
205
+						),
206
+						'after_warning'           => esc_html__(
207
+							'In order to trash this datetime you must first make sure the above ticket(s) are assigned to other datetimes.',
208
+							'event_espresso'
209
+						),
210
+						'cancel_button'           => '<button class="button-secondary ee-modal-cancel">'
211
+													 . esc_html__('Cancel', 'event_espresso') . '</button>',
212
+						'close_button'            => '<button class="button-secondary ee-modal-cancel">'
213
+													 . esc_html__('Close', 'event_espresso') . '</button>',
214
+						'single_warning_from_tkt' => esc_html__(
215
+							'The Datetime you are attempting to unassign from this ticket is the only remaining datetime for this ticket. Tickets must always have at least one datetime assigned to them.',
216
+							'event_espresso'
217
+						),
218
+						'single_warning_from_dtt' => esc_html__(
219
+							'The ticket you are attempting to unassign from this datetime cannot be unassigned because the datetime is the only remaining datetime for the ticket.  Tickets must always have at least one datetime assigned to them.',
220
+							'event_espresso'
221
+						),
222
+						'dismiss_button'          => '<button class="button-secondary ee-modal-cancel">'
223
+													 . esc_html__('Dismiss', 'event_espresso') . '</button>',
224
+					),
225
+					'DTT_ERROR_MSG'         => array(
226
+						'no_ticket_name' => esc_html__('General Admission', 'event_espresso'),
227
+						'dismiss_button' => '<div class="save-cancel-button-container"><button class="button-secondary ee-modal-cancel">'
228
+											. esc_html__('Dismiss', 'event_espresso') . '</button></div>',
229
+					),
230
+					'DTT_OVERSELL_WARNING'  => array(
231
+						'datetime_ticket' => esc_html__(
232
+							'You cannot add this ticket to this datetime because it has a sold amount that is greater than the amount of spots remaining for this datetime.',
233
+							'event_espresso'
234
+						),
235
+						'ticket_datetime' => esc_html__(
236
+							'You cannot add this datetime to this ticket because the ticket has a sold amount that is greater than the amount of spots remaining on the datetime.',
237
+							'event_espresso'
238
+						),
239
+					),
240
+					'DTT_CONVERTED_FORMATS' => EEH_DTT_Helper::convert_php_to_js_and_moment_date_formats(
241
+						$this->_date_format_strings['date'],
242
+						$this->_date_format_strings['time']
243
+					),
244
+					'DTT_START_OF_WEEK'     => array('dayValue' => (int)get_option('start_of_week')),
245
+				),
246
+			),
247
+		);
248
+	}
249
+
250
+
251
+
252
+	/**
253
+	 * @param array $update_callbacks
254
+	 * @return array
255
+	 */
256
+	public function caf_updates(array $update_callbacks)
257
+	{
258
+		foreach ($update_callbacks as $key => $callback) {
259
+			if ($callback[1] === '_default_tickets_update') {
260
+				unset($update_callbacks[$key]);
261
+			}
262
+		}
263
+		$update_callbacks[] = array($this, 'datetime_and_tickets_caf_update');
264
+		return $update_callbacks;
265
+	}
266
+
267
+
268
+	/**
269
+	 * Handles saving everything related to Tickets (datetimes, tickets, prices)
270
+	 *
271
+	 * @param  EE_Event $event The Event object we're attaching data to
272
+	 * @param  array $data The request data from the form
273
+	 * @throws EE_Error
274
+	 * @throws InvalidArgumentException
275
+	 */
276
+	public function datetime_and_tickets_caf_update($event, $data)
277
+	{
278
+		//first we need to start with datetimes cause they are the "root" items attached to events.
279
+		$saved_datetimes = $this->_update_datetimes($event, $data);
280
+		//next tackle the tickets (and prices?)
281
+		$this->_update_tickets($event, $saved_datetimes, $data);
282
+	}
283
+
284
+
285
+	/**
286
+	 * update event_datetimes
287
+	 *
288
+	 * @param  EE_Event $event Event being updated
289
+	 * @param  array $data the request data from the form
290
+	 * @return EE_Datetime[]
291
+	 * @throws InvalidArgumentException
292
+	 * @throws EE_Error
293
+	 */
294
+	protected function _update_datetimes($event, $data)
295
+	{
296
+		$timezone = isset($data['timezone_string']) ? $data['timezone_string'] : null;
297
+		$saved_dtt_ids = array();
298
+		$saved_dtt_objs = array();
299
+		if (empty($data['edit_event_datetimes']) || !is_array($data['edit_event_datetimes'])) {
300
+			throw new InvalidArgumentException(
301
+				esc_html__(
302
+					'The "edit_event_datetimes" array is invalid therefore the event can not be updated.',
303
+					'event_espresso'
304
+				)
305
+			);
306
+		}
307
+		foreach ($data['edit_event_datetimes'] as $row => $datetime_data) {
308
+			//trim all values to ensure any excess whitespace is removed.
309
+			$datetime_data = array_map(
310
+				function ($datetime_data) {
311
+					return is_array($datetime_data) ? $datetime_data : trim($datetime_data);
312
+				},
313
+				$datetime_data
314
+			);
315
+			$datetime_data['DTT_EVT_end'] = isset($datetime_data['DTT_EVT_end'])
316
+											&& ! empty($datetime_data['DTT_EVT_end'])
317
+				? $datetime_data['DTT_EVT_end']
318
+				: $datetime_data['DTT_EVT_start'];
319
+			$datetime_values = array(
320
+				'DTT_ID'          => ! empty($datetime_data['DTT_ID'])
321
+					? $datetime_data['DTT_ID']
322
+					: null,
323
+				'DTT_name'        => ! empty($datetime_data['DTT_name'])
324
+					? $datetime_data['DTT_name']
325
+					: '',
326
+				'DTT_description' => ! empty($datetime_data['DTT_description'])
327
+					? $datetime_data['DTT_description']
328
+					: '',
329
+				'DTT_EVT_start'   => $datetime_data['DTT_EVT_start'],
330
+				'DTT_EVT_end'     => $datetime_data['DTT_EVT_end'],
331
+				'DTT_reg_limit'   => empty($datetime_data['DTT_reg_limit'])
332
+					? EE_INF
333
+					: $datetime_data['DTT_reg_limit'],
334
+				'DTT_order'       => ! isset($datetime_data['DTT_order'])
335
+					? $row
336
+					: $datetime_data['DTT_order'],
337
+			);
338
+			// if we have an id then let's get existing object first and then set the new values.
339
+			// Otherwise we instantiate a new object for save.
340
+			if (! empty($datetime_data['DTT_ID'])) {
341
+				$datetime = EE_Registry::instance()
342
+									   ->load_model('Datetime', array($timezone))
343
+									   ->get_one_by_ID($datetime_data['DTT_ID']);
344
+				//set date and time format according to what is set in this class.
345
+				$datetime->set_date_format($this->_date_format_strings['date']);
346
+				$datetime->set_time_format($this->_date_format_strings['time']);
347
+				foreach ($datetime_values as $field => $value) {
348
+					$datetime->set($field, $value);
349
+				}
350
+				// make sure the $dtt_id here is saved just in case
351
+				// after the add_relation_to() the autosave replaces it.
352
+				// We need to do this so we dont' TRASH the parent DTT.
353
+				// (save the ID for both key and value to avoid duplications)
354
+				$saved_dtt_ids[$datetime->ID()] = $datetime->ID();
355
+			} else {
356
+				$datetime = EE_Registry::instance()->load_class(
357
+					'Datetime',
358
+					array(
359
+						$datetime_values,
360
+						$timezone,
361
+						array($this->_date_format_strings['date'], $this->_date_format_strings['time']),
362
+					),
363
+					false,
364
+					false
365
+				);
366
+				foreach ($datetime_values as $field => $value) {
367
+					$datetime->set($field, $value);
368
+				}
369
+			}
370
+			$datetime->save();
371
+			$datetime = $event->_add_relation_to($datetime, 'Datetime');
372
+			// before going any further make sure our dates are setup correctly
373
+			// so that the end date is always equal or greater than the start date.
374
+			if ($datetime->get_raw('DTT_EVT_start') > $datetime->get_raw('DTT_EVT_end')) {
375
+				$datetime->set('DTT_EVT_end', $datetime->get('DTT_EVT_start'));
376
+				$datetime = EEH_DTT_Helper::date_time_add($datetime, 'DTT_EVT_end', 'days');
377
+				$datetime->save();
378
+			}
379
+			//	now we have to make sure we add the new DTT_ID to the $saved_dtt_ids array
380
+			// because it is possible there was a new one created for the autosave.
381
+			// (save the ID for both key and value to avoid duplications)
382
+			$DTT_ID = $datetime->ID();
383
+			$saved_dtt_ids[$DTT_ID] = $DTT_ID;
384
+			$saved_dtt_objs[$row] = $datetime;
385
+			//todo if ANY of these updates fail then we want the appropriate global error message.
386
+		}
387
+		$event->save();
388
+		// now we need to REMOVE any datetimes that got deleted.
389
+		// Keep in mind that this process will only kick in for datetimes that don't have any DTT_sold on them.
390
+		// So its safe to permanently delete at this point.
391
+		$old_datetimes = explode(',', $data['datetime_IDs']);
392
+		$old_datetimes = $old_datetimes[0] === '' ? array() : $old_datetimes;
393
+		if (is_array($old_datetimes)) {
394
+			$datetimes_to_delete = array_diff($old_datetimes, $saved_dtt_ids);
395
+			foreach ($datetimes_to_delete as $id) {
396
+				$id = absint($id);
397
+				if (empty($id)) {
398
+					continue;
399
+				}
400
+				$dtt_to_remove = EE_Registry::instance()->load_model('Datetime')->get_one_by_ID($id);
401
+				//remove tkt relationships.
402
+				$related_tickets = $dtt_to_remove->get_many_related('Ticket');
403
+				foreach ($related_tickets as $tkt) {
404
+					$dtt_to_remove->_remove_relation_to($tkt, 'Ticket');
405
+				}
406
+				$event->_remove_relation_to($id, 'Datetime');
407
+				$dtt_to_remove->refresh_cache_of_related_objects();
408
+			}
409
+		}
410
+		return $saved_dtt_objs;
411
+	}
412
+
413
+
414
+	/**
415
+	 * update tickets
416
+	 *
417
+	 * @param  EE_Event $event Event object being updated
418
+	 * @param  EE_Datetime[] $saved_datetimes an array of datetime ids being updated
419
+	 * @param  array $data incoming request data
420
+	 * @return EE_Ticket[]
421
+	 * @throws InvalidArgumentException
422
+	 * @throws EE_Error
423
+	 */
424
+	protected function _update_tickets($event, $saved_datetimes, $data)
425
+	{
426
+		$new_tkt = null;
427
+		$new_default = null;
428
+		//stripslashes because WP filtered the $_POST ($data) array to add slashes
429
+		$data = stripslashes_deep($data);
430
+		$timezone = isset($data['timezone_string']) ? $data['timezone_string'] : null;
431
+		$saved_tickets = $datetimes_on_existing = array();
432
+		$old_tickets = isset($data['ticket_IDs']) ? explode(',', $data['ticket_IDs']) : array();
433
+		if(empty($data['edit_tickets']) || ! is_array($data['edit_tickets'])){
434
+			throw new InvalidArgumentException(
435
+				esc_html__(
436
+					'The "edit_tickets" array is invalid therefore the event can not be updated.',
437
+					'event_espresso'
438
+				)
439
+			);
440
+		}
441
+		foreach ($data['edit_tickets'] as $row => $tkt) {
442
+			$update_prices = $create_new_TKT = false;
443
+			// figure out what datetimes were added to the ticket
444
+			// and what datetimes were removed from the ticket in the session.
445
+			$starting_tkt_dtt_rows = explode(',', $data['starting_ticket_datetime_rows'][$row]);
446
+			$tkt_dtt_rows = explode(',', $data['ticket_datetime_rows'][$row]);
447
+			$datetimes_added = array_diff($tkt_dtt_rows, $starting_tkt_dtt_rows);
448
+			$datetimes_removed = array_diff($starting_tkt_dtt_rows, $tkt_dtt_rows);
449
+			// trim inputs to ensure any excess whitespace is removed.
450
+			$tkt = array_map(
451
+				function ($ticket_data) {
452
+					return is_array($ticket_data) ? $ticket_data : trim($ticket_data);
453
+				},
454
+				$tkt
455
+			);
456
+			// note we are doing conversions to floats here instead of allowing EE_Money_Field to handle
457
+			// because we're doing calculations prior to using the models.
458
+			// note incoming ['TKT_price'] value is already in standard notation (via js).
459
+			$ticket_price = isset($tkt['TKT_price'])
460
+				? round((float)$tkt['TKT_price'], 3)
461
+				: 0;
462
+			//note incoming base price needs converted from localized value.
463
+			$base_price = isset($tkt['TKT_base_price'])
464
+				? EEH_Money::convert_to_float_from_localized_money($tkt['TKT_base_price'])
465
+				: 0;
466
+			//if ticket price == 0 and $base_price != 0 then ticket price == base_price
467
+			$ticket_price = $ticket_price === 0 && $base_price !== 0
468
+				? $base_price
469
+				: $ticket_price;
470
+			$base_price_id = isset($tkt['TKT_base_price_ID'])
471
+				? $tkt['TKT_base_price_ID']
472
+				: 0;
473
+			$price_rows = is_array($data['edit_prices']) && isset($data['edit_prices'][$row])
474
+				? $data['edit_prices'][$row]
475
+				: array();
476
+			$now = null;
477
+			if (empty($tkt['TKT_start_date'])) {
478
+				//lets' use now in the set timezone.
479
+				$now = new DateTime('now', new DateTimeZone($event->get_timezone()));
480
+				$tkt['TKT_start_date'] = $now->format($this->_date_time_format);
481
+			}
482
+			if (empty($tkt['TKT_end_date'])) {
483
+				/**
484
+				 * set the TKT_end_date to the first datetime attached to the ticket.
485
+				 */
486
+				$first_dtt = $saved_datetimes[reset($tkt_dtt_rows)];
487
+				$tkt['TKT_end_date'] = $first_dtt->start_date_and_time($this->_date_time_format);
488
+			}
489
+			$TKT_values = array(
490
+				'TKT_ID'          => ! empty($tkt['TKT_ID']) ? $tkt['TKT_ID'] : null,
491
+				'TTM_ID'          => ! empty($tkt['TTM_ID']) ? $tkt['TTM_ID'] : 0,
492
+				'TKT_name'        => ! empty($tkt['TKT_name']) ? $tkt['TKT_name'] : '',
493
+				'TKT_description' => ! empty($tkt['TKT_description'])
494
+									 && $tkt['TKT_description'] !== esc_html__(
495
+					'You can modify this description',
496
+					'event_espresso'
497
+				)
498
+					? $tkt['TKT_description']
499
+					: '',
500
+				'TKT_start_date'  => $tkt['TKT_start_date'],
501
+				'TKT_end_date'    => $tkt['TKT_end_date'],
502
+				'TKT_qty'         => ! isset($tkt['TKT_qty']) || $tkt['TKT_qty'] === ''
503
+					? EE_INF
504
+					: $tkt['TKT_qty'],
505
+				'TKT_uses'        => ! isset($tkt['TKT_uses']) || $tkt['TKT_uses'] === ''
506
+					? EE_INF
507
+					: $tkt['TKT_uses'],
508
+				'TKT_min'         => empty($tkt['TKT_min']) ? 0 : $tkt['TKT_min'],
509
+				'TKT_max'         => empty($tkt['TKT_max']) ? EE_INF : $tkt['TKT_max'],
510
+				'TKT_row'         => $row,
511
+				'TKT_order'       => isset($tkt['TKT_order']) ? $tkt['TKT_order'] : 0,
512
+				'TKT_taxable'     => ! empty($tkt['TKT_taxable']) ? 1 : 0,
513
+				'TKT_required'    => ! empty($tkt['TKT_required']) ? 1 : 0,
514
+				'TKT_price'       => $ticket_price,
515
+			);
516
+			// if this is a default TKT, then we need to set the TKT_ID to 0 and update accordingly,
517
+			// which means in turn that the prices will become new prices as well.
518
+			if (isset($tkt['TKT_is_default']) && $tkt['TKT_is_default']) {
519
+				$TKT_values['TKT_ID'] = 0;
520
+				$TKT_values['TKT_is_default'] = 0;
521
+				$update_prices = true;
522
+			}
523
+			// if we have a TKT_ID then we need to get that existing TKT_obj and update it
524
+			// we actually do our saves ahead of doing any add_relations to
525
+			// because its entirely possible that this ticket wasn't removed or added to any datetime in the session
526
+			// but DID have it's items modified.
527
+			// keep in mind that if the TKT has been sold (and we have changed pricing information),
528
+			// then we won't be updating the tkt but instead a new tkt will be created and the old one archived.
529
+			if (absint($TKT_values['TKT_ID'])) {
530
+				$ticket = EE_Registry::instance()
531
+									 ->load_model('Ticket', array($timezone))
532
+									 ->get_one_by_ID($tkt['TKT_ID']);
533
+				if ($ticket instanceof EE_Ticket) {
534
+					$ticket = $this->_update_ticket_datetimes(
535
+						$ticket,
536
+						$saved_datetimes,
537
+						$datetimes_added,
538
+						$datetimes_removed
539
+					);
540
+					// are there any registrations using this ticket ?
541
+					$tickets_sold = $ticket->count_related(
542
+						'Registration',
543
+						array(
544
+							array(
545
+								'STS_ID' => array('NOT IN', array(EEM_Registration::status_id_incomplete)),
546
+							),
547
+						)
548
+					);
549
+					//set ticket formats
550
+					$ticket->set_date_format($this->_date_format_strings['date']);
551
+					$ticket->set_time_format($this->_date_format_strings['time']);
552
+					// let's just check the total price for the existing ticket
553
+					// and determine if it matches the new total price.
554
+					// if they are different then we create a new ticket (if tickets sold)
555
+					// if they aren't different then we go ahead and modify existing ticket.
556
+					$create_new_TKT = $tickets_sold > 0 && $ticket_price !== $ticket->price() && ! $ticket->deleted();
557
+					//set new values
558
+					foreach ($TKT_values as $field => $value) {
559
+						if ($field === 'TKT_qty') {
560
+							$ticket->set_qty($value);
561
+						} else {
562
+							$ticket->set($field, $value);
563
+						}
564
+					}
565
+					// if $create_new_TKT is false then we can safely update the existing ticket.
566
+					// Otherwise we have to create a new ticket.
567
+					if ($create_new_TKT) {
568
+						$new_tkt = $this->_duplicate_ticket($ticket, $price_rows, $ticket_price, $base_price,
569
+							$base_price_id);
570
+					}
571
+				}
572
+			} else {
573
+				// no TKT_id so a new TKT
574
+				$ticket = EE_Ticket::new_instance(
575
+					$TKT_values,
576
+					$timezone,
577
+					array($this->_date_format_strings['date'], $this->_date_format_strings['time'])
578
+				);
579
+				if ($ticket instanceof EE_Ticket) {
580
+					// make sure ticket has an ID of setting relations won't work
581
+					$ticket->save();
582
+					$ticket = $this->_update_ticket_datetimes(
583
+						$ticket,
584
+						$saved_datetimes,
585
+						$datetimes_added,
586
+						$datetimes_removed
587
+					);
588
+					$update_prices = true;
589
+				}
590
+			}
591
+			//make sure any current values have been saved.
592
+			//$ticket->save();
593
+			// before going any further make sure our dates are setup correctly
594
+			// so that the end date is always equal or greater than the start date.
595
+			if ($ticket->get_raw('TKT_start_date') > $ticket->get_raw('TKT_end_date')) {
596
+				$ticket->set('TKT_end_date', $ticket->get('TKT_start_date'));
597
+				$ticket = EEH_DTT_Helper::date_time_add($ticket, 'TKT_end_date', 'days');
598
+			}
599
+			//let's make sure the base price is handled
600
+			$ticket = ! $create_new_TKT ? $this->_add_prices_to_ticket(array(), $ticket, $update_prices, $base_price,
601
+				$base_price_id) : $ticket;
602
+			//add/update price_modifiers
603
+			$ticket = ! $create_new_TKT ? $this->_add_prices_to_ticket($price_rows, $ticket, $update_prices) : $ticket;
604
+			//need to make sue that the TKT_price is accurate after saving the prices.
605
+			$ticket->ensure_TKT_Price_correct();
606
+			//handle CREATING a default tkt from the incoming tkt but ONLY if this isn't an autosave.
607
+			if (! defined('DOING_AUTOSAVE') && ! empty($tkt['TKT_is_default_selector'])) {
608
+				$update_prices = true;
609
+				$new_default = clone $ticket;
610
+				$new_default->set('TKT_ID', 0);
611
+				$new_default->set('TKT_is_default', 1);
612
+				$new_default->set('TKT_row', 1);
613
+				$new_default->set('TKT_price', $ticket_price);
614
+				// remove any dtt relations cause we DON'T want dtt relations attached
615
+				// (note this is just removing the cached relations in the object)
616
+				$new_default->_remove_relations('Datetime');
617
+				//todo we need to add the current attached prices as new prices to the new default ticket.
618
+				$new_default = $this->_add_prices_to_ticket($price_rows, $new_default, $update_prices);
619
+				//don't forget the base price!
620
+				$new_default = $this->_add_prices_to_ticket(
621
+					array(),
622
+					$new_default,
623
+					$update_prices,
624
+					$base_price,
625
+					$base_price_id
626
+				);
627
+				$new_default->save();
628
+				do_action(
629
+					'AHEE__espresso_events_Pricing_Hooks___update_tkts_new_default_ticket',
630
+					$new_default,
631
+					$row,
632
+					$ticket,
633
+					$data
634
+				);
635
+			}
636
+			// DO ALL dtt relationships for both current tickets and any archived tickets
637
+			// for the given dtt that are related to the current ticket.
638
+			// TODO... not sure exactly how we're going to do this considering we don't know
639
+			// what current ticket the archived tickets are related to
640
+			// (and TKT_parent is used for autosaves so that's not a field we can reliably use).
641
+			//let's assign any tickets that have been setup to the saved_tickets tracker
642
+			//save existing TKT
643
+			$ticket->save();
644
+			if ($create_new_TKT && $new_tkt instanceof EE_Ticket) {
645
+				//save new TKT
646
+				$new_tkt->save();
647
+				//add new ticket to array
648
+				$saved_tickets[$new_tkt->ID()] = $new_tkt;
649
+				do_action(
650
+					'AHEE__espresso_events_Pricing_Hooks___update_tkts_new_ticket',
651
+					$new_tkt,
652
+					$row,
653
+					$tkt,
654
+					$data
655
+				);
656
+			} else {
657
+				//add tkt to saved tkts
658
+				$saved_tickets[$ticket->ID()] = $ticket;
659
+				do_action(
660
+					'AHEE__espresso_events_Pricing_Hooks___update_tkts_update_ticket',
661
+					$ticket,
662
+					$row,
663
+					$tkt,
664
+					$data
665
+				);
666
+			}
667
+		}
668
+		// now we need to handle tickets actually "deleted permanently".
669
+		// There are cases where we'd want this to happen
670
+		// (i.e. autosaves are happening and then in between autosaves the user trashes a ticket).
671
+		// Or a draft event was saved and in the process of editing a ticket is trashed.
672
+		// No sense in keeping all the related data in the db!
673
+		$old_tickets = isset($old_tickets[0]) && $old_tickets[0] === '' ? array() : $old_tickets;
674
+		$tickets_removed = array_diff($old_tickets, array_keys($saved_tickets));
675
+		foreach ($tickets_removed as $id) {
676
+			$id = absint($id);
677
+			//get the ticket for this id
678
+			$tkt_to_remove = EE_Registry::instance()->load_model('Ticket')->get_one_by_ID($id);
679
+			//if this tkt is a default tkt we leave it alone cause it won't be attached to the datetime
680
+			if ($tkt_to_remove->get('TKT_is_default')) {
681
+				continue;
682
+			}
683
+			// if this tkt has any registrations attached so then we just ARCHIVE
684
+			// because we don't actually permanently delete these tickets.
685
+			if ($tkt_to_remove->count_related('Registration') > 0) {
686
+				$tkt_to_remove->delete();
687
+				continue;
688
+			}
689
+			// need to get all the related datetimes on this ticket and remove from every single one of them
690
+			// (remember this process can ONLY kick off if there are NO tkts_sold)
691
+			$datetimes = $tkt_to_remove->get_many_related('Datetime');
692
+			foreach ($datetimes as $datetime) {
693
+				$tkt_to_remove->_remove_relation_to($datetime, 'Datetime');
694
+			}
695
+			// need to do the same for prices (except these prices can also be deleted because again,
696
+			// tickets can only be trashed if they don't have any TKTs sold (otherwise they are just archived))
697
+			$tkt_to_remove->delete_related_permanently('Price');
698
+			do_action('AHEE__espresso_events_Pricing_Hooks___update_tkts_delete_ticket', $tkt_to_remove);
699
+			// finally let's delete this ticket
700
+			// (which should not be blocked at this point b/c we've removed all our relationships)
701
+			$tkt_to_remove->delete_permanently();
702
+		}
703
+		return $saved_tickets;
704
+	}
705
+
706
+
707
+
708
+	/**
709
+	 * @access  protected
710
+	 * @param \EE_Ticket     $ticket
711
+	 * @param \EE_Datetime[] $saved_datetimes
712
+	 * @param \EE_Datetime[] $added_datetimes
713
+	 * @param \EE_Datetime[] $removed_datetimes
714
+	 * @return \EE_Ticket
715
+	 * @throws \EE_Error
716
+	 */
717
+	protected function _update_ticket_datetimes(
718
+		EE_Ticket $ticket,
719
+		$saved_datetimes = array(),
720
+		$added_datetimes = array(),
721
+		$removed_datetimes = array()
722
+	) {
723
+		// to start we have to add the ticket to all the datetimes its supposed to be with,
724
+		// and removing the ticket from datetimes it got removed from.
725
+		// first let's add datetimes
726
+		if (! empty($added_datetimes) && is_array($added_datetimes)) {
727
+			foreach ($added_datetimes as $row_id) {
728
+				$row_id = (int)$row_id;
729
+				if (isset($saved_datetimes[$row_id]) && $saved_datetimes[$row_id] instanceof EE_Datetime) {
730
+					$ticket->_add_relation_to($saved_datetimes[$row_id], 'Datetime');
731
+					// Is this an existing ticket (has an ID) and does it have any sold?
732
+					// If so, then we need to add that to the DTT sold because this DTT is getting added.
733
+					if ($ticket->ID() && $ticket->sold() > 0) {
734
+						$saved_datetimes[$row_id]->increase_sold($ticket->sold());
735
+						$saved_datetimes[$row_id]->save();
736
+					}
737
+				}
738
+			}
739
+		}
740
+		// then remove datetimes
741
+		if (! empty($removed_datetimes) && is_array($removed_datetimes)) {
742
+			foreach ($removed_datetimes as $row_id) {
743
+				$row_id = (int)$row_id;
744
+				// its entirely possible that a datetime got deleted (instead of just removed from relationship.
745
+				// So make sure we skip over this if the dtt isn't in the $saved_datetimes array)
746
+				if (isset($saved_datetimes[$row_id]) && $saved_datetimes[$row_id] instanceof EE_Datetime) {
747
+					$ticket->_remove_relation_to($saved_datetimes[$row_id], 'Datetime');
748
+					// Is this an existing ticket (has an ID) and does it have any sold?
749
+					// If so, then we need to remove it's sold from the DTT_sold.
750
+					if ($ticket->ID() && $ticket->sold() > 0) {
751
+						$saved_datetimes[$row_id]->decrease_sold($ticket->sold());
752
+						$saved_datetimes[$row_id]->save();
753
+					}
754
+				}
755
+			}
756
+		}
757
+		// cap ticket qty by datetime reg limits
758
+		$ticket->set_qty(min($ticket->qty(), $ticket->qty('reg_limit')));
759
+		return $ticket;
760
+	}
761
+
762
+
763
+
764
+	/**
765
+	 * @access  protected
766
+	 * @param \EE_Ticket $ticket
767
+	 * @param array      $price_rows
768
+	 * @param int        $ticket_price
769
+	 * @param int        $base_price
770
+	 * @param int        $base_price_id
771
+	 * @return \EE_Ticket
772
+	 * @throws \EE_Error
773
+	 */
774
+	protected function _duplicate_ticket(
775
+		EE_Ticket $ticket,
776
+		$price_rows = array(),
777
+		$ticket_price = 0,
778
+		$base_price = 0,
779
+		$base_price_id = 0
780
+	) {
781
+		// create new ticket that's a copy of the existing
782
+		// except a new id of course (and not archived)
783
+		// AND has the new TKT_price associated with it.
784
+		$new_ticket = clone $ticket;
785
+		$new_ticket->set('TKT_ID', 0);
786
+		$new_ticket->set_deleted(0);
787
+		$new_ticket->set_price($ticket_price);
788
+		$new_ticket->set_sold(0);
789
+		// let's get a new ID for this ticket
790
+		$new_ticket->save();
791
+		// we also need to make sure this new ticket gets the same datetime attachments as the archived ticket
792
+		$datetimes_on_existing = $ticket->datetimes();
793
+		$new_ticket = $this->_update_ticket_datetimes(
794
+			$new_ticket,
795
+			$datetimes_on_existing,
796
+			array_keys($datetimes_on_existing)
797
+		);
798
+		// $ticket will get archived later b/c we are NOT adding it to the saved_tickets array.
799
+		// if existing $ticket has sold amount, then we need to adjust the qty for the new TKT to = the remaining
800
+		// available.
801
+		if ($ticket->sold() > 0) {
802
+			$new_qty = $ticket->qty() - $ticket->sold();
803
+			$new_ticket->set_qty($new_qty);
804
+		}
805
+		//now we update the prices just for this ticket
806
+		$new_ticket = $this->_add_prices_to_ticket($price_rows, $new_ticket, true);
807
+		//and we update the base price
808
+		$new_ticket = $this->_add_prices_to_ticket(array(), $new_ticket, true, $base_price, $base_price_id);
809
+		return $new_ticket;
810
+	}
811
+
812
+
813
+
814
+	/**
815
+	 * This attaches a list of given prices to a ticket.
816
+	 * Note we dont' have to worry about ever removing relationships (or archiving prices) because if there is a change
817
+	 * in price information on a ticket, a new ticket is created anyways so the archived ticket will retain the old
818
+	 * price info and prices are automatically "archived" via the ticket.
819
+	 *
820
+	 * @access  private
821
+	 * @param array     $prices        Array of prices from the form.
822
+	 * @param EE_Ticket $ticket        EE_Ticket object that prices are being attached to.
823
+	 * @param bool      $new_prices    Whether attach existing incoming prices or create new ones.
824
+	 * @param int|bool  $base_price    if FALSE then NOT doing a base price add.
825
+	 * @param int|bool  $base_price_id if present then this is the base_price_id being updated.
826
+	 * @return EE_Ticket
827
+	 * @throws EE_Error
828
+	 */
829
+	protected function _add_prices_to_ticket(
830
+		$prices = array(),
831
+		EE_Ticket $ticket,
832
+		$new_prices = false,
833
+		$base_price = false,
834
+		$base_price_id = false
835
+	) {
836
+		// let's just get any current prices that may exist on the given ticket
837
+		// so we can remove any prices that got trashed in this session.
838
+		$current_prices_on_ticket = $base_price !== false
839
+			? $ticket->base_price(true)
840
+			: $ticket->price_modifiers();
841
+		$updated_prices = array();
842
+		// if $base_price ! FALSE then updating a base price.
843
+		if ($base_price !== false) {
844
+			$prices[1] = array(
845
+				'PRC_ID'     => $new_prices || $base_price_id === 1 ? null : $base_price_id,
846
+				'PRT_ID'     => 1,
847
+				'PRC_amount' => $base_price,
848
+				'PRC_name'   => $ticket->get('TKT_name'),
849
+				'PRC_desc'   => $ticket->get('TKT_description'),
850
+			);
851
+		}
852
+		//possibly need to save tkt
853
+		if (! $ticket->ID()) {
854
+			$ticket->save();
855
+		}
856
+		foreach ($prices as $row => $prc) {
857
+			$prt_id = ! empty($prc['PRT_ID']) ? $prc['PRT_ID'] : null;
858
+			if (empty($prt_id)) {
859
+				continue;
860
+			} //prices MUST have a price type id.
861
+			$PRC_values = array(
862
+				'PRC_ID'         => ! empty($prc['PRC_ID']) ? $prc['PRC_ID'] : null,
863
+				'PRT_ID'         => $prt_id,
864
+				'PRC_amount'     => ! empty($prc['PRC_amount']) ? $prc['PRC_amount'] : 0,
865
+				'PRC_name'       => ! empty($prc['PRC_name']) ? $prc['PRC_name'] : '',
866
+				'PRC_desc'       => ! empty($prc['PRC_desc']) ? $prc['PRC_desc'] : '',
867
+				'PRC_is_default' => false,
868
+				//make sure we set PRC_is_default to false for all ticket saves from event_editor
869
+				'PRC_order'      => $row,
870
+			);
871
+			if ($new_prices || empty($PRC_values['PRC_ID'])) {
872
+				$PRC_values['PRC_ID'] = 0;
873
+				$price = EE_Registry::instance()->load_class(
874
+					'Price',
875
+					array($PRC_values),
876
+					false,
877
+					false
878
+				);
879
+			} else {
880
+				$price = EE_Registry::instance()->load_model('Price')->get_one_by_ID($prc['PRC_ID']);
881
+				//update this price with new values
882
+				foreach ($PRC_values as $field => $value) {
883
+					$price->set($field, $value);
884
+				}
885
+			}
886
+			$price->save();
887
+			$updated_prices[$price->ID()] = $price;
888
+			$ticket->_add_relation_to($price, 'Price');
889
+		}
890
+		//now let's remove any prices that got removed from the ticket
891
+		if (! empty ($current_prices_on_ticket)) {
892
+			$current = array_keys($current_prices_on_ticket);
893
+			$updated = array_keys($updated_prices);
894
+			$prices_to_remove = array_diff($current, $updated);
895
+			if (! empty($prices_to_remove)) {
896
+				foreach ($prices_to_remove as $prc_id) {
897
+					$p = $current_prices_on_ticket[$prc_id];
898
+					$ticket->_remove_relation_to($p, 'Price');
899
+					//delete permanently the price
900
+					$p->delete_permanently();
901
+				}
902
+			}
903
+		}
904
+		return $ticket;
905
+	}
906
+
907
+
908
+
909
+	/**
910
+	 * @param Events_Admin_Page $event_admin_obj
911
+	 * @return Events_Admin_Page
912
+	 */
913
+	public function autosave_handling( Events_Admin_Page $event_admin_obj)
914
+	{
915
+		return $event_admin_obj;
916
+		//doing nothing for the moment.
917
+		// todo when I get to this remember that I need to set the template args on the $event_admin_obj
918
+		// (use the set_template_args() method)
919
+		/**
920
+		 * need to remember to handle TICKET DEFAULT saves correctly:  I've got two input fields in the dom:
921
+		 * 1. TKT_is_default_selector (visible)
922
+		 * 2. TKT_is_default (hidden)
923
+		 * I think we'll use the TKT_is_default for recording whether the ticket displayed IS a default ticket
924
+		 * (on new event creations). Whereas the TKT_is_default_selector is for the user to indicate they want
925
+		 * this ticket to be saved as a default.
926
+		 * The tricky part is, on an initial display on create or edit (or after manually updating),
927
+		 * the TKT_is_default_selector will always be unselected and the TKT_is_default will only be true
928
+		 * if this is a create.  However, after an autosave, users will want some sort of indicator that
929
+		 * the TKT HAS been saved as a default..
930
+		 * in other words we don't want to remove the check on TKT_is_default_selector. So here's what I'm thinking.
931
+		 * On Autosave:
932
+		 * 1. If TKT_is_default is true: we create a new TKT, send back the new id and add id to related elements,
933
+		 * then set the TKT_is_default to false.
934
+		 * 2. If TKT_is_default_selector is true: we create/edit existing ticket (following conditions above as well).
935
+		 *  We do NOT create a new default ticket.  The checkbox stays selected after autosave.
936
+		 * 3. only on MANUAL update do we check for the selection and if selected create the new default ticket.
937
+		 */
938
+	}
939
+
940
+
941
+
942
+	/**
943
+	 * @throws DomainException
944
+	 * @throws EE_Error
945
+	 */
946
+	public function pricing_metabox()
947
+	{
948
+		$existing_datetime_ids = $existing_ticket_ids = $datetime_tickets = $ticket_datetimes = array();
949
+		$event = $this->_adminpage_obj->get_cpt_model_obj();
950
+		//set is_creating_event property.
951
+		$EVT_ID = $event->ID();
952
+		$this->_is_creating_event = absint($EVT_ID) === 0;
953
+		//default main template args
954
+		$main_template_args = array(
955
+			'event_datetime_help_link' => EEH_Template::get_help_tab_link(
956
+				'event_editor_event_datetimes_help_tab',
957
+				$this->_adminpage_obj->page_slug,
958
+				$this->_adminpage_obj->get_req_action(),
959
+				false,
960
+				false
961
+			),
962
+			// todo need to add a filter to the template for the help text
963
+			// in the Events_Admin_Page core file so we can add further help
964
+			'existing_datetime_ids'    => '',
965
+			'total_dtt_rows'           => 1,
966
+			'add_new_dtt_help_link'    => EEH_Template::get_help_tab_link(
967
+				'add_new_dtt_info',
968
+				$this->_adminpage_obj->page_slug,
969
+				$this->_adminpage_obj->get_req_action(),
970
+				false,
971
+				false
972
+			),
973
+			//todo need to add this help info id to the Events_Admin_Page core file so we can access it here.
974
+			'datetime_rows'            => '',
975
+			'show_tickets_container'   => '',
976
+			//$this->_adminpage_obj->get_cpt_model_obj()->ID() > 1 ? ' style="display:none;"' : '',
977
+			'ticket_rows'              => '',
978
+			'existing_ticket_ids'      => '',
979
+			'total_ticket_rows'        => 1,
980
+			'ticket_js_structure'      => '',
981
+			'ee_collapsible_status'    => ' ee-collapsible-open'
982
+			//$this->_adminpage_obj->get_cpt_model_obj()->ID() > 0 ? ' ee-collapsible-closed' : ' ee-collapsible-open'
983
+		);
984
+		$timezone = $event instanceof EE_Event ? $event->timezone_string() : null;
985
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
986
+		/**
987
+		 * 1. Start with retrieving Datetimes
988
+		 * 2. For each datetime get related tickets
989
+		 * 3. For each ticket get related prices
990
+		 */
991
+		/** @var EEM_Datetime $datetime_model */
992
+		$datetime_model = EE_Registry::instance()->load_model('Datetime', array($timezone));
993
+		$datetimes = $datetime_model->get_all_event_dates($EVT_ID);
994
+		$main_template_args['total_dtt_rows'] = count($datetimes);
995
+		/**
996
+		 * @see https://events.codebasehq.com/projects/event-espresso/tickets/9486
997
+		 * for why we are counting $datetime_row and then setting that on the Datetime object
998
+		 */
999
+		$datetime_row = 1;
1000
+		foreach ($datetimes as $datetime) {
1001
+			$DTT_ID = $datetime->get('DTT_ID');
1002
+			$datetime->set('DTT_order', $datetime_row);
1003
+			$existing_datetime_ids[] = $DTT_ID;
1004
+			//tickets attached
1005
+			$related_tickets = $datetime->ID() > 0
1006
+				? $datetime->get_many_related(
1007
+					'Ticket',
1008
+					array(
1009
+						array(
1010
+							'OR' => array('TKT_deleted' => 1, 'TKT_deleted*' => 0),
1011
+						),
1012
+						'default_where_conditions' => 'none',
1013
+						'order_by'                 => array('TKT_order' => 'ASC'),
1014
+					)
1015
+				)
1016
+				: array();
1017
+			//if there are no related tickets this is likely a new event OR autodraft
1018
+			// event so we need to generate the default tickets because datetimes
1019
+			// ALWAYS have at least one related ticket!!.  EXCEPT, we dont' do this if there is already more than one
1020
+			// datetime on the event.
1021
+			if (empty ($related_tickets) && count($datetimes) < 2) {
1022
+				/** @var EEM_Ticket $ticket_model */
1023
+				$ticket_model = EE_Registry::instance()->load_model('Ticket');
1024
+				$related_tickets = $ticket_model->get_all_default_tickets();
1025
+				// this should be ordered by TKT_ID, so let's grab the first default ticket
1026
+				// (which will be the main default) and ensure it has any default prices added to it (but do NOT save).
1027
+				$default_prices = EEM_Price::instance()->get_all_default_prices();
1028
+				$main_default_ticket = reset($related_tickets);
1029
+				if ($main_default_ticket instanceof EE_Ticket) {
1030
+					foreach ($default_prices as $default_price) {
1031
+						if ($default_price instanceof EE_Price && $default_price->is_base_price()) {
1032
+							continue;
1033
+						}
1034
+						$main_default_ticket->cache('Price', $default_price);
1035
+					}
1036
+				}
1037
+			}
1038
+			// we can't actually setup rows in this loop yet cause we don't know all
1039
+			// the unique tickets for this event yet (tickets are linked through all datetimes).
1040
+			// So we're going to temporarily cache some of that information.
1041
+			//loop through and setup the ticket rows and make sure the order is set.
1042
+			foreach ($related_tickets as $ticket) {
1043
+				$TKT_ID = $ticket->get('TKT_ID');
1044
+				$ticket_row = $ticket->get('TKT_row');
1045
+				//we only want unique tickets in our final display!!
1046
+				if (! in_array($TKT_ID, $existing_ticket_ids, true)) {
1047
+					$existing_ticket_ids[] = $TKT_ID;
1048
+					$all_tickets[] = $ticket;
1049
+				}
1050
+				//temporary cache of this ticket info for this datetime for later processing of datetime rows.
1051
+				$datetime_tickets[$DTT_ID][] = $ticket_row;
1052
+				//temporary cache of this datetime info for this ticket for later processing of ticket rows.
1053
+				if (
1054
+					! isset($ticket_datetimes[$TKT_ID])
1055
+					|| ! in_array($datetime_row, $ticket_datetimes[$TKT_ID], true)
1056
+				) {
1057
+					$ticket_datetimes[$TKT_ID][] = $datetime_row;
1058
+				}
1059
+			}
1060
+			$datetime_row++;
1061
+		}
1062
+		$main_template_args['total_ticket_rows'] = count($existing_ticket_ids);
1063
+		$main_template_args['existing_ticket_ids'] = implode(',', $existing_ticket_ids);
1064
+		$main_template_args['existing_datetime_ids'] = implode(',', $existing_datetime_ids);
1065
+		//sort $all_tickets by order
1066
+		usort(
1067
+			$all_tickets,
1068
+			function (EE_Ticket $a, EE_Ticket $b) {
1069
+				$a_order = (int)$a->get('TKT_order');
1070
+				$b_order = (int)$b->get('TKT_order');
1071
+				if ($a_order === $b_order) {
1072
+					return 0;
1073
+				}
1074
+				return ($a_order < $b_order) ? -1 : 1;
1075
+			}
1076
+		);
1077
+		// k NOW we have all the data we need for setting up the dtt rows
1078
+		// and ticket rows so we start our dtt loop again.
1079
+		$datetime_row = 1;
1080
+		foreach ($datetimes as $datetime) {
1081
+			$main_template_args['datetime_rows'] .= $this->_get_datetime_row(
1082
+				$datetime_row,
1083
+				$datetime,
1084
+				$datetime_tickets,
1085
+				$all_tickets,
1086
+				false,
1087
+				$datetimes
1088
+			);
1089
+			$datetime_row++;
1090
+		}
1091
+		//then loop through all tickets for the ticket rows.
1092
+		$ticket_row = 1;
1093
+		foreach ($all_tickets as $ticket) {
1094
+			$main_template_args['ticket_rows'] .= $this->_get_ticket_row(
1095
+				$ticket_row,
1096
+				$ticket,
1097
+				$ticket_datetimes,
1098
+				$datetimes,
1099
+				false,
1100
+				$all_tickets
1101
+			);
1102
+			$ticket_row++;
1103
+		}
1104
+		$main_template_args['ticket_js_structure'] = $this->_get_ticket_js_structure($datetimes, $all_tickets);
1105
+		EEH_Template::display_template(
1106
+			PRICING_TEMPLATE_PATH . 'event_tickets_metabox_main.template.php',
1107
+			$main_template_args
1108
+		);
1109
+	}
1110
+
1111
+
1112
+
1113
+	/**
1114
+	 * @param int         $datetime_row
1115
+	 * @param EE_Datetime $datetime
1116
+	 * @param array       $datetime_tickets
1117
+	 * @param array       $all_tickets
1118
+	 * @param bool        $default
1119
+	 * @param array       $all_datetimes
1120
+	 * @return mixed
1121
+	 * @throws DomainException
1122
+	 * @throws EE_Error
1123
+	 */
1124
+	protected function _get_datetime_row(
1125
+		$datetime_row,
1126
+		EE_Datetime $datetime,
1127
+		$datetime_tickets = array(),
1128
+		$all_tickets = array(),
1129
+		$default = false,
1130
+		$all_datetimes = array()
1131
+	) {
1132
+		$dtt_display_template_args = array(
1133
+			'dtt_edit_row'             => $this->_get_dtt_edit_row($datetime_row, $datetime, $default, $all_datetimes),
1134
+			'dtt_attached_tickets_row' => $this->_get_dtt_attached_tickets_row(
1135
+				$datetime_row,
1136
+				$datetime,
1137
+				$datetime_tickets,
1138
+				$all_tickets,
1139
+				$default
1140
+			),
1141
+			'dtt_row'                  => $default ? 'DTTNUM' : $datetime_row,
1142
+		);
1143
+		return EEH_Template::display_template(
1144
+			PRICING_TEMPLATE_PATH . 'event_tickets_datetime_row_wrapper.template.php',
1145
+			$dtt_display_template_args,
1146
+			true
1147
+		);
1148
+	}
1149
+
1150
+
1151
+
1152
+	/**
1153
+	 * This method is used to generate a dtt fields  edit row.
1154
+	 * The same row is used to generate a row with valid DTT objects
1155
+	 * and the default row that is used as the skeleton by the js.
1156
+	 *
1157
+	 * @param int           $datetime_row  The row number for the row being generated.
1158
+	 * @param EE_Datetime   $datetime
1159
+	 * @param bool          $default       Whether a default row is being generated or not.
1160
+	 * @param EE_Datetime[] $all_datetimes This is the array of all datetimes used in the editor.
1161
+	 * @return string
1162
+	 * @throws DomainException
1163
+	 * @throws EE_Error
1164
+	 */
1165
+	protected function _get_dtt_edit_row($datetime_row, $datetime, $default, $all_datetimes)
1166
+	{
1167
+		// if the incoming $datetime object is NOT an instance of EE_Datetime then force default to true.
1168
+		$default = ! $datetime instanceof EE_Datetime ? true : $default;
1169
+		$template_args = array(
1170
+			'dtt_row'              => $default ? 'DTTNUM' : $datetime_row,
1171
+			'event_datetimes_name' => $default ? 'DTTNAMEATTR' : 'edit_event_datetimes',
1172
+			'edit_dtt_expanded'    => '',
1173
+			'DTT_ID'               => $default ? '' : $datetime->ID(),
1174
+			'DTT_name'             => $default ? '' : $datetime->name(),
1175
+			'DTT_description'      => $default ? '' : $datetime->description(),
1176
+			'DTT_EVT_start'        => $default ? '' : $datetime->start_date($this->_date_time_format),
1177
+			'DTT_EVT_end'          => $default ? '' : $datetime->end_date($this->_date_time_format),
1178
+			'DTT_reg_limit'        => $default
1179
+				? ''
1180
+				: $datetime->get_pretty(
1181
+					'DTT_reg_limit',
1182
+					'input'
1183
+				),
1184
+			'DTT_order'            => $default ? 'DTTNUM' : $datetime_row,
1185
+			'dtt_sold'             => $default ? '0' : $datetime->get('DTT_sold'),
1186
+			'dtt_reserved'         => $default ? '0' : $datetime->reserved(),
1187
+			'clone_icon'           => ! empty($datetime) && $datetime->get('DTT_sold') > 0
1188
+				? ''
1189
+				: 'clone-icon ee-icon ee-icon-clone clickable',
1190
+			'trash_icon'           => ! empty($datetime) && $datetime->get('DTT_sold') > 0
1191
+				? 'ee-lock-icon'
1192
+				: 'trash-icon dashicons dashicons-post-trash clickable',
1193
+			'reg_list_url'         => $default || ! $datetime->event() instanceof \EE_Event
1194
+				? ''
1195
+				: EE_Admin_Page::add_query_args_and_nonce(
1196
+					array('event_id' => $datetime->event()->ID(), 'datetime_id' => $datetime->ID()),
1197
+					REG_ADMIN_URL
1198
+				),
1199
+		);
1200
+		$template_args['show_trash'] = count($all_datetimes) === 1 && $template_args['trash_icon'] !== 'ee-lock-icon'
1201
+			? ' style="display:none"'
1202
+			: '';
1203
+		//allow filtering of template args at this point.
1204
+		$template_args = apply_filters(
1205
+			'FHEE__espresso_events_Pricing_Hooks___get_dtt_edit_row__template_args',
1206
+			$template_args,
1207
+			$datetime_row,
1208
+			$datetime,
1209
+			$default,
1210
+			$all_datetimes,
1211
+			$this->_is_creating_event
1212
+		);
1213
+		return EEH_Template::display_template(
1214
+			PRICING_TEMPLATE_PATH . 'event_tickets_datetime_edit_row.template.php',
1215
+			$template_args,
1216
+			true
1217
+		);
1218
+	}
1219
+
1220
+
1221
+
1222
+	/**
1223
+	 * @param int         $datetime_row
1224
+	 * @param EE_Datetime $datetime
1225
+	 * @param array       $datetime_tickets
1226
+	 * @param array       $all_tickets
1227
+	 * @param bool        $default
1228
+	 * @return mixed
1229
+	 * @throws DomainException
1230
+	 * @throws EE_Error
1231
+	 */
1232
+	protected function _get_dtt_attached_tickets_row(
1233
+		$datetime_row,
1234
+		$datetime,
1235
+		$datetime_tickets = array(),
1236
+		$all_tickets = array(),
1237
+		$default
1238
+	) {
1239
+		$template_args = array(
1240
+			'dtt_row'                           => $default ? 'DTTNUM' : $datetime_row,
1241
+			'event_datetimes_name'              => $default ? 'DTTNAMEATTR' : 'edit_event_datetimes',
1242
+			'DTT_description'                   => $default ? '' : $datetime->description(),
1243
+			'datetime_tickets_list'             => $default ? '<li class="hidden"></li>' : '',
1244
+			'show_tickets_row'                  => ' style="display:none;"',
1245
+			'add_new_datetime_ticket_help_link' => EEH_Template::get_help_tab_link(
1246
+				'add_new_ticket_via_datetime',
1247
+				$this->_adminpage_obj->page_slug,
1248
+				$this->_adminpage_obj->get_req_action(),
1249
+				false,
1250
+				false
1251
+			),
1252
+			//todo need to add this help info id to the Events_Admin_Page core file so we can access it here.
1253
+			'DTT_ID'                            => $default ? '' : $datetime->ID(),
1254
+		);
1255
+		//need to setup the list items (but only if this isn't a default skeleton setup)
1256
+		if (! $default) {
1257
+			$ticket_row = 1;
1258
+			foreach ($all_tickets as $ticket) {
1259
+				$template_args['datetime_tickets_list'] .= $this->_get_datetime_tickets_list_item(
1260
+					$datetime_row,
1261
+					$ticket_row,
1262
+					$datetime,
1263
+					$ticket,
1264
+					$datetime_tickets,
1265
+					$default
1266
+				);
1267
+				$ticket_row++;
1268
+			}
1269
+		}
1270
+		//filter template args at this point
1271
+		$template_args = apply_filters(
1272
+			'FHEE__espresso_events_Pricing_Hooks___get_dtt_attached_ticket_row__template_args',
1273
+			$template_args,
1274
+			$datetime_row,
1275
+			$datetime,
1276
+			$datetime_tickets,
1277
+			$all_tickets,
1278
+			$default,
1279
+			$this->_is_creating_event
1280
+		);
1281
+		return EEH_Template::display_template(
1282
+			PRICING_TEMPLATE_PATH . 'event_tickets_datetime_attached_tickets_row.template.php',
1283
+			$template_args,
1284
+			true
1285
+		);
1286
+	}
1287
+
1288
+
1289
+
1290
+	/**
1291
+	 * @param int         $datetime_row
1292
+	 * @param int         $ticket_row
1293
+	 * @param EE_Datetime $datetime
1294
+	 * @param EE_Ticket   $ticket
1295
+	 * @param array       $datetime_tickets
1296
+	 * @param bool        $default
1297
+	 * @return mixed
1298
+	 * @throws DomainException
1299
+	 * @throws EE_Error
1300
+	 */
1301
+	protected function _get_datetime_tickets_list_item(
1302
+		$datetime_row,
1303
+		$ticket_row,
1304
+		$datetime,
1305
+		$ticket,
1306
+		$datetime_tickets = array(),
1307
+		$default
1308
+	) {
1309
+		$dtt_tkts = $datetime instanceof EE_Datetime && isset($datetime_tickets[$datetime->ID()])
1310
+			? $datetime_tickets[$datetime->ID()]
1311
+			: array();
1312
+		$display_row = $ticket instanceof EE_Ticket ? $ticket->get('TKT_row') : 0;
1313
+		$no_ticket = $default && empty($ticket);
1314
+		$template_args = array(
1315
+			'dtt_row'                 => $default
1316
+				? 'DTTNUM'
1317
+				: $datetime_row,
1318
+			'tkt_row'                 => $no_ticket
1319
+				? 'TICKETNUM'
1320
+				: $ticket_row,
1321
+			'datetime_ticket_checked' => in_array($display_row, $dtt_tkts, true)
1322
+				? ' checked="checked"'
1323
+				: '',
1324
+			'ticket_selected'         => in_array($display_row, $dtt_tkts, true)
1325
+				? ' ticket-selected'
1326
+				: '',
1327
+			'TKT_name'                => $no_ticket
1328
+				? 'TKTNAME'
1329
+				: $ticket->get('TKT_name'),
1330
+			'tkt_status_class'        => $no_ticket || $this->_is_creating_event
1331
+				? ' tkt-status-' . EE_Ticket::onsale
1332
+				: ' tkt-status-' . $ticket->ticket_status(),
1333
+		);
1334
+		//filter template args
1335
+		$template_args = apply_filters(
1336
+			'FHEE__espresso_events_Pricing_Hooks___get_datetime_tickets_list_item__template_args',
1337
+			$template_args,
1338
+			$datetime_row,
1339
+			$ticket_row,
1340
+			$datetime,
1341
+			$ticket,
1342
+			$datetime_tickets,
1343
+			$default,
1344
+			$this->_is_creating_event
1345
+		);
1346
+		return EEH_Template::display_template(
1347
+			PRICING_TEMPLATE_PATH . 'event_tickets_datetime_dtt_tickets_list.template.php',
1348
+			$template_args,
1349
+			true
1350
+		);
1351
+	}
1352
+
1353
+
1354
+
1355
+	/**
1356
+	 * This generates the ticket row for tickets.
1357
+	 * This same method is used to generate both the actual rows and the js skeleton row
1358
+	 * (when default === true)
1359
+	 *
1360
+	 * @param int           $ticket_row       Represents the row number being generated.
1361
+	 * @param               $ticket
1362
+	 * @param EE_Datetime[] $ticket_datetimes Either an array of all datetimes on all tickets indexed by each ticket
1363
+	 *                                        or empty for default
1364
+	 * @param EE_Datetime[] $all_datetimes    All Datetimes on the event or empty for default.
1365
+	 * @param bool          $default          Whether default row being generated or not.
1366
+	 * @param EE_Ticket[]   $all_tickets      This is an array of all tickets attached to the event
1367
+	 *                                        (or empty in the case of defaults)
1368
+	 * @return mixed
1369
+	 * @throws DomainException
1370
+	 * @throws EE_Error
1371
+	 */
1372
+	protected function _get_ticket_row(
1373
+		$ticket_row,
1374
+		$ticket,
1375
+		$ticket_datetimes,
1376
+		$all_datetimes,
1377
+		$default = false,
1378
+		$all_tickets = array()
1379
+	) {
1380
+		// if $ticket is not an instance of EE_Ticket then force default to true.
1381
+		$default = ! $ticket instanceof EE_Ticket ? true : $default;
1382
+		$prices = ! empty($ticket) && ! $default ? $ticket->get_many_related('Price',
1383
+			array('default_where_conditions' => 'none', 'order_by' => array('PRC_order' => 'ASC'))) : array();
1384
+		// if there is only one price (which would be the base price)
1385
+		// or NO prices and this ticket is a default ticket,
1386
+		// let's just make sure there are no cached default prices on the object.
1387
+		// This is done by not including any query_params.
1388
+		if ($ticket instanceof EE_Ticket && $ticket->is_default() && (count($prices) === 1 || empty($prices))) {
1389
+			$prices = $ticket->prices();
1390
+		}
1391
+		// check if we're dealing with a default ticket in which case
1392
+		// we don't want any starting_ticket_datetime_row values set
1393
+		// (otherwise there won't be any new relationships created for tickets based off of the default ticket).
1394
+		// This will future proof in case there is ever any behaviour change between what the primary_key defaults to.
1395
+		$default_dtt = $default || ($ticket instanceof EE_Ticket && $ticket->is_default());
1396
+		$tkt_datetimes = $ticket instanceof EE_Ticket && isset($ticket_datetimes[$ticket->ID()])
1397
+			? $ticket_datetimes[$ticket->ID()]
1398
+			: array();
1399
+		$ticket_subtotal = $default ? 0 : $ticket->get_ticket_subtotal();
1400
+		$base_price = $default ? null : $ticket->base_price();
1401
+		$count_price_mods = EEM_Price::instance()->get_all_default_prices(true);
1402
+		//breaking out complicated condition for ticket_status
1403
+		if ($default) {
1404
+			$ticket_status_class = ' tkt-status-' . EE_Ticket::onsale;
1405
+		} else {
1406
+			$ticket_status_class = $ticket->is_default()
1407
+				? ' tkt-status-' . EE_Ticket::onsale
1408
+				: ' tkt-status-' . $ticket->ticket_status();
1409
+		}
1410
+		//breaking out complicated condition for TKT_taxable
1411
+		if ($default) {
1412
+			$TKT_taxable = '';
1413
+		} else {
1414
+			$TKT_taxable = $ticket->taxable()
1415
+				? ' checked="checked"'
1416
+				: '';
1417
+		}
1418
+		if ($default) {
1419
+			$TKT_status = EEH_Template::pretty_status(EE_Ticket::onsale, false, 'sentence');
1420
+		} elseif ($ticket->is_default()) {
1421
+			$TKT_status = EEH_Template::pretty_status(EE_Ticket::onsale, false, 'sentence');
1422
+		} else {
1423
+			$TKT_status = $ticket->ticket_status(true);
1424
+		}
1425
+		if ($default) {
1426
+			$TKT_min = '';
1427
+		} else {
1428
+			$TKT_min = $ticket->min();
1429
+			if ($TKT_min === -1 || $TKT_min === 0) {
1430
+				$TKT_min = '';
1431
+			}
1432
+		}
1433
+		$template_args = array(
1434
+			'tkt_row'                       => $default ? 'TICKETNUM' : $ticket_row,
1435
+			'TKT_order'                     => $default ? 'TICKETNUM' : $ticket_row,
1436
+			//on initial page load this will always be the correct order.
1437
+			'tkt_status_class'              => $ticket_status_class,
1438
+			'display_edit_tkt_row'          => ' style="display:none;"',
1439
+			'edit_tkt_expanded'             => '',
1440
+			'edit_tickets_name'             => $default ? 'TICKETNAMEATTR' : 'edit_tickets',
1441
+			'TKT_name'                      => $default ? '' : $ticket->name(),
1442
+			'TKT_start_date'                => $default
1443
+				? ''
1444
+				: $ticket->get_date('TKT_start_date', $this->_date_time_format),
1445
+			'TKT_end_date'                  => $default
1446
+				? ''
1447
+				: $ticket->get_date('TKT_end_date', $this->_date_time_format),
1448
+			'TKT_status'                    => $TKT_status,
1449
+			'TKT_price'                     => $default
1450
+				? ''
1451
+				: EEH_Template::format_currency(
1452
+					$ticket->get_ticket_total_with_taxes(),
1453
+					false,
1454
+					false
1455
+				),
1456
+			'TKT_price_code'                => EE_Registry::instance()->CFG->currency->code,
1457
+			'TKT_price_amount'              => $default ? 0 : $ticket_subtotal,
1458
+			'TKT_qty'                       => $default
1459
+				? ''
1460
+				: $ticket->get_pretty('TKT_qty', 'symbol'),
1461
+			'TKT_qty_for_input'             => $default
1462
+				? ''
1463
+				: $ticket->get_pretty('TKT_qty', 'input'),
1464
+			'TKT_uses'                      => $default
1465
+				? ''
1466
+				: $ticket->get_pretty('TKT_uses', 'input'),
1467
+			'TKT_min'                       => $TKT_min,
1468
+			'TKT_max'                       => $default
1469
+				? ''
1470
+				: $ticket->get_pretty('TKT_max', 'input'),
1471
+			'TKT_sold'                      => $default ? 0 : $ticket->tickets_sold('ticket'),
1472
+			'TKT_reserved'                  => $default ? 0 : $ticket->reserved(),
1473
+			'TKT_registrations'             => $default
1474
+				? 0
1475
+				: $ticket->count_registrations(
1476
+					array(
1477
+						array(
1478
+							'STS_ID' => array(
1479
+								'!=',
1480
+								EEM_Registration::status_id_incomplete,
1481
+							),
1482
+						),
1483
+					)
1484
+				),
1485
+			'TKT_ID'                        => $default ? 0 : $ticket->ID(),
1486
+			'TKT_description'               => $default ? '' : $ticket->description(),
1487
+			'TKT_is_default'                => $default ? 0 : $ticket->is_default(),
1488
+			'TKT_required'                  => $default ? 0 : $ticket->required(),
1489
+			'TKT_is_default_selector'       => '',
1490
+			'ticket_price_rows'             => '',
1491
+			'TKT_base_price'                => $default || ! $base_price instanceof EE_Price
1492
+				? ''
1493
+				: $base_price->get_pretty('PRC_amount', 'localized_float'),
1494
+			'TKT_base_price_ID'             => $default || ! $base_price instanceof EE_Price ? 0 : $base_price->ID(),
1495
+			'show_price_modifier'           => count($prices) > 1 || ($default && $count_price_mods > 0)
1496
+				? ''
1497
+				: ' style="display:none;"',
1498
+			'show_price_mod_button'         => count($prices) > 1
1499
+											   || ($default && $count_price_mods > 0)
1500
+											   || (! $default && $ticket->deleted())
1501
+				? ' style="display:none;"'
1502
+				: '',
1503
+			'total_price_rows'              => count($prices) > 1 ? count($prices) : 1,
1504
+			'ticket_datetimes_list'         => $default ? '<li class="hidden"></li>' : '',
1505
+			'starting_ticket_datetime_rows' => $default || $default_dtt ? '' : implode(',', $tkt_datetimes),
1506
+			'ticket_datetime_rows'          => $default ? '' : implode(',', $tkt_datetimes),
1507
+			'existing_ticket_price_ids'     => $default ? '' : implode(',', array_keys($prices)),
1508
+			'ticket_template_id'            => $default ? 0 : $ticket->get('TTM_ID'),
1509
+			'TKT_taxable'                   => $TKT_taxable,
1510
+			'display_subtotal'              => $ticket instanceof EE_Ticket && $ticket->taxable()
1511
+				? ''
1512
+				: ' style="display:none"',
1513
+			'price_currency_symbol'         => EE_Registry::instance()->CFG->currency->sign,
1514
+			'TKT_subtotal_amount_display'   => EEH_Template::format_currency(
1515
+				$ticket_subtotal,
1516
+				false,
1517
+				false
1518
+			),
1519
+			'TKT_subtotal_amount'           => $ticket_subtotal,
1520
+			'tax_rows'                      => $this->_get_tax_rows($ticket_row, $ticket),
1521
+			'disabled'                      => $ticket instanceof EE_Ticket && $ticket->deleted(),
1522
+			'ticket_archive_class'          => $ticket instanceof EE_Ticket && $ticket->deleted()
1523
+				? ' ticket-archived'
1524
+				: '',
1525
+			'trash_icon'                    => $ticket instanceof EE_Ticket
1526
+											   && $ticket->deleted()
1527
+											   && ! $ticket->is_permanently_deleteable()
1528
+				? 'ee-lock-icon '
1529
+				: 'trash-icon dashicons dashicons-post-trash clickable',
1530
+			'clone_icon'                    => $ticket instanceof EE_Ticket && $ticket->deleted()
1531
+				? ''
1532
+				: 'clone-icon ee-icon ee-icon-clone clickable',
1533
+		);
1534
+		$template_args['trash_hidden'] = count($all_tickets) === 1 && $template_args['trash_icon'] !== 'ee-lock-icon'
1535
+			? ' style="display:none"'
1536
+			: '';
1537
+		//handle rows that should NOT be empty
1538
+		if (empty($template_args['TKT_start_date'])) {
1539
+			//if empty then the start date will be now.
1540
+			$template_args['TKT_start_date'] = date($this->_date_time_format,
1541
+				current_time('timestamp'));
1542
+			$template_args['tkt_status_class'] = ' tkt-status-' . EE_Ticket::onsale;
1543
+		}
1544
+		if (empty($template_args['TKT_end_date'])) {
1545
+			//get the earliest datetime (if present);
1546
+			$earliest_dtt = $this->_adminpage_obj->get_cpt_model_obj()->ID() > 0
1547
+				? $this->_adminpage_obj->get_cpt_model_obj()->get_first_related(
1548
+					'Datetime',
1549
+					array('order_by' => array('DTT_EVT_start' => 'ASC'))
1550
+				)
1551
+				: null;
1552
+			if (! empty($earliest_dtt)) {
1553
+				$template_args['TKT_end_date'] = $earliest_dtt->get_datetime(
1554
+					'DTT_EVT_start',
1555
+					$this->_date_time_format
1556
+				);
1557
+			} else {
1558
+				//default so let's just use what's been set for the default date-time which is 30 days from now.
1559
+				$template_args['TKT_end_date'] = date(
1560
+					$this->_date_time_format,
1561
+					mktime(24, 0, 0, date('m'), date('d') + 29, date('Y')
1562
+					)
1563
+				);
1564
+			}
1565
+			$template_args['tkt_status_class'] = ' tkt-status-' . EE_Ticket::onsale;
1566
+		}
1567
+		//generate ticket_datetime items
1568
+		if (! $default) {
1569
+			$datetime_row = 1;
1570
+			foreach ($all_datetimes as $datetime) {
1571
+				$template_args['ticket_datetimes_list'] .= $this->_get_ticket_datetime_list_item(
1572
+					$datetime_row,
1573
+					$ticket_row,
1574
+					$datetime,
1575
+					$ticket,
1576
+					$ticket_datetimes,
1577
+					$default
1578
+				);
1579
+				$datetime_row++;
1580
+			}
1581
+		}
1582
+		$price_row = 1;
1583
+		foreach ($prices as $price) {
1584
+			if (! $price instanceof EE_Price)  {
1585
+				continue;
1586
+			}
1587
+			if ($price->is_base_price()) {
1588
+				$price_row++;
1589
+				continue;
1590
+			}
1591
+			$show_trash = !((count($prices) > 1 && $price_row === 1) || count($prices) === 1);
1592
+			$show_create = !(count($prices) > 1 && count($prices) !== $price_row);
1593
+			$template_args['ticket_price_rows'] .= $this->_get_ticket_price_row(
1594
+				$ticket_row,
1595
+				$price_row,
1596
+				$price,
1597
+				$default,
1598
+				$ticket,
1599
+				$show_trash,
1600
+				$show_create
1601
+			);
1602
+			$price_row++;
1603
+		}
1604
+		//filter $template_args
1605
+		$template_args = apply_filters(
1606
+			'FHEE__espresso_events_Pricing_Hooks___get_ticket_row__template_args',
1607
+			$template_args,
1608
+			$ticket_row,
1609
+			$ticket,
1610
+			$ticket_datetimes,
1611
+			$all_datetimes,
1612
+			$default,
1613
+			$all_tickets,
1614
+			$this->_is_creating_event
1615
+		);
1616
+		return EEH_Template::display_template(
1617
+			PRICING_TEMPLATE_PATH . 'event_tickets_datetime_ticket_row.template.php',
1618
+			$template_args,
1619
+			true
1620
+		);
1621
+	}
1622
+
1623
+
1624
+
1625
+	/**
1626
+	 * @param int            $ticket_row
1627
+	 * @param EE_Ticket|null $ticket
1628
+	 * @return string
1629
+	 * @throws DomainException
1630
+	 * @throws EE_Error
1631
+	 */
1632
+	protected function _get_tax_rows($ticket_row, $ticket)
1633
+	{
1634
+		$tax_rows = '';
1635
+		/** @var EE_Price[] $taxes */
1636
+		$taxes = empty($ticket) ? EE_Taxes::get_taxes_for_admin() : $ticket->get_ticket_taxes_for_admin();
1637
+		foreach ($taxes as $tax) {
1638
+			$tax_added = $this->_get_tax_added($tax, $ticket);
1639
+			$template_args = array(
1640
+				'display_tax'       => ! empty($ticket) && $ticket->get('TKT_taxable')
1641
+					? ''
1642
+					: ' style="display:none;"',
1643
+				'tax_id'            => $tax->ID(),
1644
+				'tkt_row'           => $ticket_row,
1645
+				'tax_label'         => $tax->get('PRC_name'),
1646
+				'tax_added'         => $tax_added,
1647
+				'tax_added_display' => EEH_Template::format_currency($tax_added, false, false),
1648
+				'tax_amount'        => $tax->get('PRC_amount'),
1649
+			);
1650
+			$template_args = apply_filters(
1651
+				'FHEE__espresso_events_Pricing_Hooks___get_tax_rows__template_args',
1652
+				$template_args,
1653
+				$ticket_row,
1654
+				$ticket,
1655
+				$this->_is_creating_event
1656
+			);
1657
+			$tax_rows .= EEH_Template::display_template(
1658
+				PRICING_TEMPLATE_PATH . 'event_tickets_datetime_ticket_tax_row.template.php',
1659
+				$template_args,
1660
+				true
1661
+			);
1662
+		}
1663
+		return $tax_rows;
1664
+	}
1665
+
1666
+
1667
+
1668
+	/**
1669
+	 * @param EE_Price       $tax
1670
+	 * @param EE_Ticket|null $ticket
1671
+	 * @return float|int
1672
+	 * @throws EE_Error
1673
+	 */
1674
+	protected function _get_tax_added(EE_Price $tax, $ticket)
1675
+	{
1676
+		$subtotal = empty($ticket) ? 0 : $ticket->get_ticket_subtotal();
1677
+		return $subtotal * $tax->get('PRC_amount') / 100;
1678
+	}
1679
+
1680
+
1681
+
1682
+	/**
1683
+	 * @param int            $ticket_row
1684
+	 * @param int            $price_row
1685
+	 * @param EE_Price|null  $price
1686
+	 * @param bool           $default
1687
+	 * @param EE_Ticket|null $ticket
1688
+	 * @param bool           $show_trash
1689
+	 * @param bool           $show_create
1690
+	 * @return mixed
1691
+	 * @throws DomainException
1692
+	 * @throws EE_Error
1693
+	 */
1694
+	protected function _get_ticket_price_row(
1695
+		$ticket_row,
1696
+		$price_row,
1697
+		$price,
1698
+		$default,
1699
+		$ticket,
1700
+		$show_trash = true,
1701
+		$show_create = true
1702
+	) {
1703
+		$send_disabled = ! empty($ticket) && $ticket->get('TKT_deleted');
1704
+		$template_args = array(
1705
+			'tkt_row'               => $default && empty($ticket)
1706
+				? 'TICKETNUM'
1707
+				: $ticket_row,
1708
+			'PRC_order'             => $default && empty($price)
1709
+				? 'PRICENUM'
1710
+				: $price_row,
1711
+			'edit_prices_name'      => $default && empty($price)
1712
+				? 'PRICENAMEATTR'
1713
+				: 'edit_prices',
1714
+			'price_type_selector'   => $default && empty($price)
1715
+				? $this->_get_base_price_template($ticket_row, $price_row, $price, $default)
1716
+				: $this->_get_price_type_selector($ticket_row, $price_row, $price, $default, $send_disabled),
1717
+			'PRC_ID'                => $default && empty($price)
1718
+				? 0
1719
+				: $price->ID(),
1720
+			'PRC_is_default'        => $default && empty($price)
1721
+				? 0
1722
+				: $price->get('PRC_is_default'),
1723
+			'PRC_name'              => $default && empty($price)
1724
+				? ''
1725
+				: $price->get('PRC_name'),
1726
+			'price_currency_symbol' => EE_Registry::instance()->CFG->currency->sign,
1727
+			'show_plus_or_minus'    => $default && empty($price)
1728
+				? ''
1729
+				: ' style="display:none;"',
1730
+			'show_plus'             => ($default && empty($price)) || ($price->is_discount() || $price->is_base_price())
1731
+				? ' style="display:none;"'
1732
+				: '',
1733
+			'show_minus'            => ($default && empty($price)) || ! $price->is_discount()
1734
+				? ' style="display:none;"'
1735
+				: '',
1736
+			'show_currency_symbol'  => ($default && empty($price)) || $price->is_percent()
1737
+				? ' style="display:none"'
1738
+				: '',
1739
+			'PRC_amount'            => $default && empty($price)
1740
+				? 0
1741
+				: $price->get_pretty('PRC_amount',
1742
+					'localized_float'),
1743
+			'show_percentage'       => ($default && empty($price)) || ! $price->is_percent()
1744
+				? ' style="display:none;"'
1745
+				: '',
1746
+			'show_trash_icon'       => $show_trash
1747
+				? ''
1748
+				: ' style="display:none;"',
1749
+			'show_create_button'    => $show_create
1750
+				? ''
1751
+				: ' style="display:none;"',
1752
+			'PRC_desc'              => $default && empty($price)
1753
+				? ''
1754
+				: $price->get('PRC_desc'),
1755
+			'disabled'              => ! empty($ticket) && $ticket->get('TKT_deleted'),
1756
+		);
1757
+		$template_args = apply_filters(
1758
+			'FHEE__espresso_events_Pricing_Hooks___get_ticket_price_row__template_args',
1759
+			$template_args,
1760
+			$ticket_row,
1761
+			$price_row,
1762
+			$price,
1763
+			$default,
1764
+			$ticket,
1765
+			$show_trash,
1766
+			$show_create,
1767
+			$this->_is_creating_event
1768
+		);
1769
+		return EEH_Template::display_template(
1770
+			PRICING_TEMPLATE_PATH . 'event_tickets_datetime_ticket_price_row.template.php',
1771
+			$template_args,
1772
+			true
1773
+		);
1774
+	}
1775
+
1776
+
1777
+
1778
+	/**
1779
+	 * @param int      $ticket_row
1780
+	 * @param int      $price_row
1781
+	 * @param EE_Price $price
1782
+	 * @param bool     $default
1783
+	 * @param bool     $disabled
1784
+	 * @return mixed
1785
+	 * @throws DomainException
1786
+	 * @throws EE_Error
1787
+	 */
1788
+	protected function _get_price_type_selector($ticket_row, $price_row, $price, $default, $disabled = false)
1789
+	{
1790
+		if ($price->is_base_price()) {
1791
+			return $this->_get_base_price_template($ticket_row, $price_row, $price, $default);
1792
+		}
1793
+		return $this->_get_price_modifier_template($ticket_row, $price_row, $price, $default, $disabled);
1794
+	}
1795
+
1796
+
1797
+
1798
+	/**
1799
+	 * @param int      $ticket_row
1800
+	 * @param int      $price_row
1801
+	 * @param EE_Price $price
1802
+	 * @param bool     $default
1803
+	 * @return mixed
1804
+	 * @throws DomainException
1805
+	 * @throws EE_Error
1806
+	 */
1807
+	protected function _get_base_price_template($ticket_row, $price_row, $price, $default)
1808
+	{
1809
+		$template_args = array(
1810
+			'tkt_row'                   => $default ? 'TICKETNUM' : $ticket_row,
1811
+			'PRC_order'                 => $default && empty($price) ? 'PRICENUM' : $price_row,
1812
+			'PRT_ID'                    => $default && empty($price) ? 1 : $price->get('PRT_ID'),
1813
+			'PRT_name'                  => esc_html__('Price', 'event_espresso'),
1814
+			'price_selected_operator'   => '+',
1815
+			'price_selected_is_percent' => 0,
1816
+		);
1817
+		$template_args = apply_filters(
1818
+			'FHEE__espresso_events_Pricing_Hooks___get_base_price_template__template_args',
1819
+			$template_args,
1820
+			$ticket_row,
1821
+			$price_row,
1822
+			$price,
1823
+			$default,
1824
+			$this->_is_creating_event
1825
+		);
1826
+		return EEH_Template::display_template(
1827
+			PRICING_TEMPLATE_PATH . 'event_tickets_datetime_price_type_base.template.php',
1828
+			$template_args,
1829
+			true
1830
+		);
1831
+	}
1832
+
1833
+
1834
+
1835
+	/**
1836
+	 * @param int      $ticket_row
1837
+	 * @param int      $price_row
1838
+	 * @param EE_Price $price
1839
+	 * @param bool     $default
1840
+	 * @param bool     $disabled
1841
+	 * @return mixed
1842
+	 * @throws DomainException
1843
+	 * @throws EE_Error
1844
+	 */
1845
+	protected function _get_price_modifier_template(
1846
+		$ticket_row,
1847
+		$price_row,
1848
+		$price,
1849
+		$default,
1850
+		$disabled = false
1851
+	) {
1852
+		$select_name = $default && ! $price instanceof EE_Price
1853
+			? 'edit_prices[TICKETNUM][PRICENUM][PRT_ID]'
1854
+			: 'edit_prices[' . $ticket_row . '][' . $price_row . '][PRT_ID]';
1855
+		/** @var EEM_Price_Type $price_type_model */
1856
+		$price_type_model = EE_Registry::instance()->load_model('Price_Type');
1857
+		$price_types = $price_type_model->get_all(array(
1858
+			array(
1859
+				'OR' => array(
1860
+					'PBT_ID'  => '2',
1861
+					'PBT_ID*' => '3',
1862
+				),
1863
+			),
1864
+		));
1865
+		$all_price_types = $default && ! $price instanceof EE_Price
1866
+			? array(esc_html__('Select Modifier', 'event_espresso'))
1867
+			: array();
1868
+		$selected_price_type_id = $default && ! $price instanceof EE_Price ? 0 : $price->type();
1869
+		$price_option_spans = '';
1870
+		//setup price types for selector
1871
+		foreach ($price_types as $price_type) {
1872
+			if (! $price_type instanceof EE_Price_Type) {
1873
+				continue;
1874
+			}
1875
+			$all_price_types[$price_type->ID()] = $price_type->get('PRT_name');
1876
+			//while we're in the loop let's setup the option spans used by js
1877
+			$span_args = array(
1878
+				'PRT_ID'         => $price_type->ID(),
1879
+				'PRT_operator'   => $price_type->is_discount() ? '-' : '+',
1880
+				'PRT_is_percent' => $price_type->get('PRT_is_percent') ? 1 : 0,
1881
+			);
1882
+			$price_option_spans .= EEH_Template::display_template(
1883
+				PRICING_TEMPLATE_PATH . 'event_tickets_datetime_price_option_span.template.php',
1884
+				$span_args,
1885
+				true
1886
+			);
1887
+		}
1888
+		$select_name = $disabled ? 'archive_price[' . $ticket_row . '][' . $price_row . '][PRT_ID]' : $select_name;
1889
+		$select_input = new EE_Select_Input(
1890
+			$all_price_types,
1891
+			array(
1892
+				'default'               => $selected_price_type_id,
1893
+				'html_name'             => $select_name,
1894
+				'html_class'            => 'edit-price-PRT_ID',
1895
+				'html_other_attributes' => $disabled ? 'style="width:auto;" disabled' : 'style="width:auto;"',
1896
+			)
1897
+		);
1898
+		$price_selected_operator = $price instanceof EE_Price && $price->is_discount() ? '-' : '+';
1899
+		$price_selected_operator = $default && ! $price instanceof EE_Price ? '' : $price_selected_operator;
1900
+		$price_selected_is_percent = $price instanceof EE_Price && $price->is_percent() ? 1 : 0;
1901
+		$price_selected_is_percent = $default && ! $price instanceof EE_Price ? '' : $price_selected_is_percent;
1902
+		$template_args = array(
1903
+			'tkt_row'                   => $default ? 'TICKETNUM' : $ticket_row,
1904
+			'PRC_order'                 => $default && ! $price instanceof EE_Price ? 'PRICENUM' : $price_row,
1905
+			'price_modifier_selector'   => $select_input->get_html_for_input(),
1906
+			'main_name'                 => $select_name,
1907
+			'selected_price_type_id'    => $selected_price_type_id,
1908
+			'price_option_spans'        => $price_option_spans,
1909
+			'price_selected_operator'   => $price_selected_operator,
1910
+			'price_selected_is_percent' => $price_selected_is_percent,
1911
+			'disabled'                  => $disabled,
1912
+		);
1913
+		$template_args = apply_filters(
1914
+			'FHEE__espresso_events_Pricing_Hooks___get_price_modifier_template__template_args',
1915
+			$template_args,
1916
+			$ticket_row,
1917
+			$price_row,
1918
+			$price,
1919
+			$default,
1920
+			$disabled,
1921
+			$this->_is_creating_event
1922
+		);
1923
+		return EEH_Template::display_template(
1924
+			PRICING_TEMPLATE_PATH . 'event_tickets_datetime_price_modifier_selector.template.php',
1925
+			$template_args,
1926
+			true
1927
+		);
1928
+	}
1929
+
1930
+
1931
+
1932
+	/**
1933
+	 * @param int              $datetime_row
1934
+	 * @param int              $ticket_row
1935
+	 * @param EE_Datetime|null $datetime
1936
+	 * @param EE_Ticket|null   $ticket
1937
+	 * @param array            $ticket_datetimes
1938
+	 * @param bool             $default
1939
+	 * @return mixed
1940
+	 * @throws DomainException
1941
+	 * @throws EE_Error
1942
+	 */
1943
+	protected function _get_ticket_datetime_list_item(
1944
+		$datetime_row,
1945
+		$ticket_row,
1946
+		$datetime,
1947
+		$ticket,
1948
+		$ticket_datetimes = array(),
1949
+		$default
1950
+	) {
1951
+		$tkt_datetimes = $ticket instanceof EE_Ticket && isset($ticket_datetimes[$ticket->ID()])
1952
+			? $ticket_datetimes[$ticket->ID()]
1953
+			: array();
1954
+		$template_args = array(
1955
+			'dtt_row'                  => $default && ! $datetime instanceof EE_Datetime
1956
+				? 'DTTNUM'
1957
+				: $datetime_row,
1958
+			'tkt_row'                  => $default
1959
+				? 'TICKETNUM'
1960
+				: $ticket_row,
1961
+			'ticket_datetime_selected' => in_array($datetime_row, $tkt_datetimes, true)
1962
+				? ' ticket-selected'
1963
+				: '',
1964
+			'ticket_datetime_checked'  => in_array($datetime_row, $tkt_datetimes, true)
1965
+				? ' checked="checked"'
1966
+				: '',
1967
+			'DTT_name'                 => $default && empty($datetime)
1968
+				? 'DTTNAME'
1969
+				: $datetime->get_dtt_display_name(true),
1970
+			'tkt_status_class'         => '',
1971
+		);
1972
+		$template_args = apply_filters(
1973
+			'FHEE__espresso_events_Pricing_Hooks___get_ticket_datetime_list_item__template_args',
1974
+			$template_args,
1975
+			$datetime_row,
1976
+			$ticket_row,
1977
+			$datetime,
1978
+			$ticket,
1979
+			$ticket_datetimes,
1980
+			$default,
1981
+			$this->_is_creating_event
1982
+		);
1983
+		return EEH_Template::display_template(
1984
+			PRICING_TEMPLATE_PATH . 'event_tickets_datetime_ticket_datetimes_list_item.template.php',
1985
+			$template_args,
1986
+			true
1987
+		);
1988
+	}
1989
+
1990
+
1991
+
1992
+	/**
1993
+	 * @param array $all_datetimes
1994
+	 * @param array $all_tickets
1995
+	 * @return mixed
1996
+	 * @throws DomainException
1997
+	 * @throws EE_Error
1998
+	 */
1999
+	protected function _get_ticket_js_structure($all_datetimes = array(), $all_tickets = array())
2000
+	{
2001
+		$template_args = array(
2002
+			'default_datetime_edit_row'                => $this->_get_dtt_edit_row(
2003
+				'DTTNUM',
2004
+				null,
2005
+				true,
2006
+				$all_datetimes
2007
+			),
2008
+			'default_ticket_row'                       => $this->_get_ticket_row(
2009
+				'TICKETNUM',
2010
+				null,
2011
+				array(),
2012
+				array(),
2013
+				true
2014
+			),
2015
+			'default_price_row'                        => $this->_get_ticket_price_row(
2016
+				'TICKETNUM',
2017
+				'PRICENUM',
2018
+				null,
2019
+				true,
2020
+				null
2021
+			),
2022
+			'default_price_rows'                       => '',
2023
+			'default_base_price_amount'                => 0,
2024
+			'default_base_price_name'                  => '',
2025
+			'default_base_price_description'           => '',
2026
+			'default_price_modifier_selector_row'      => $this->_get_price_modifier_template(
2027
+				'TICKETNUM',
2028
+				'PRICENUM',
2029
+				null,
2030
+				true
2031
+			),
2032
+			'default_available_tickets_for_datetime'   => $this->_get_dtt_attached_tickets_row(
2033
+				'DTTNUM',
2034
+				null,
2035
+				array(),
2036
+				array(),
2037
+				true
2038
+			),
2039
+			'existing_available_datetime_tickets_list' => '',
2040
+			'existing_available_ticket_datetimes_list' => '',
2041
+			'new_available_datetime_ticket_list_item'  => $this->_get_datetime_tickets_list_item(
2042
+				'DTTNUM',
2043
+				'TICKETNUM',
2044
+				null,
2045
+				null,
2046
+				array(),
2047
+				true
2048
+			),
2049
+			'new_available_ticket_datetime_list_item'  => $this->_get_ticket_datetime_list_item(
2050
+				'DTTNUM',
2051
+				'TICKETNUM',
2052
+				null,
2053
+				null,
2054
+				array(),
2055
+				true
2056
+			),
2057
+		);
2058
+		$ticket_row = 1;
2059
+		foreach ($all_tickets as $ticket) {
2060
+			$template_args['existing_available_datetime_tickets_list'] .= $this->_get_datetime_tickets_list_item(
2061
+				'DTTNUM',
2062
+				$ticket_row,
2063
+				null,
2064
+				$ticket,
2065
+				array(),
2066
+				true
2067
+			);
2068
+			$ticket_row++;
2069
+		}
2070
+		$datetime_row = 1;
2071
+		foreach ($all_datetimes as $datetime) {
2072
+			$template_args['existing_available_ticket_datetimes_list'] .= $this->_get_ticket_datetime_list_item(
2073
+				$datetime_row,
2074
+				'TICKETNUM',
2075
+				$datetime,
2076
+				null,
2077
+				array(),
2078
+				true
2079
+			);
2080
+			$datetime_row++;
2081
+		}
2082
+		/** @var EEM_Price $price_model */
2083
+		$price_model = EE_Registry::instance()->load_model('Price');
2084
+		$default_prices = $price_model->get_all_default_prices();
2085
+		$price_row = 1;
2086
+		foreach ($default_prices as $price) {
2087
+			if (! $price instanceof EE_Price) {
2088
+				continue;
2089
+			}
2090
+			if ($price->is_base_price()) {
2091
+				$template_args['default_base_price_amount'] = $price->get_pretty(
2092
+					'PRC_amount',
2093
+					'localized_float'
2094
+				);
2095
+				$template_args['default_base_price_name'] = $price->get('PRC_name');
2096
+				$template_args['default_base_price_description'] = $price->get('PRC_desc');
2097
+				$price_row++;
2098
+				continue;
2099
+			}
2100
+			$show_trash = !((count($default_prices) > 1 && $price_row === 1) || count($default_prices) === 1);
2101
+			$show_create = !(count($default_prices) > 1 && count($default_prices) !== $price_row);
2102
+			$template_args['default_price_rows'] .= $this->_get_ticket_price_row(
2103
+				'TICKETNUM',
2104
+				$price_row,
2105
+				$price,
2106
+				true,
2107
+				null,
2108
+				$show_trash,
2109
+				$show_create
2110
+			);
2111
+			$price_row++;
2112
+		}
2113
+		$template_args = apply_filters(
2114
+			'FHEE__espresso_events_Pricing_Hooks___get_ticket_js_structure__template_args',
2115
+			$template_args,
2116
+			$all_datetimes,
2117
+			$all_tickets,
2118
+			$this->_is_creating_event
2119
+		);
2120
+		return EEH_Template::display_template(
2121
+			PRICING_TEMPLATE_PATH . 'event_tickets_datetime_ticket_js_structure.template.php',
2122
+			$template_args,
2123
+			true
2124
+		);
2125
+	}
2126 2126
 
2127 2127
 
2128 2128
 } //end class espresso_events_Pricing_Hooks
Please login to merge, or discard this patch.
Spacing   +62 added lines, -62 removed lines patch added patch discarded remove patch
@@ -49,7 +49,7 @@  discard block
 block discarded – undo
49 49
     {
50 50
         $this->_name = 'pricing';
51 51
         //capability check
52
-        if (! EE_Registry::instance()->CAP->current_user_can(
52
+        if ( ! EE_Registry::instance()->CAP->current_user_can(
53 53
             'ee_read_default_prices',
54 54
             'advanced_ticket_datetime_metabox'
55 55
         )) {
@@ -125,7 +125,7 @@  discard block
 block discarded – undo
125 125
         $this->_date_format_strings['time'] = isset($this->_date_format_strings['time'])
126 126
             ? $this->_date_format_strings['time']
127 127
             : null;
128
-        $this->_date_time_format = $this->_date_format_strings['date'] . ' ' . $this->_date_format_strings['time'];
128
+        $this->_date_time_format = $this->_date_format_strings['date'].' '.$this->_date_format_strings['time'];
129 129
     }
130 130
 
131 131
 
@@ -150,7 +150,7 @@  discard block
 block discarded – undo
150 150
             );
151 151
             $msg .= '</p><ul>';
152 152
             foreach ($format_validation as $error) {
153
-                $msg .= '<li>' . $error . '</li>';
153
+                $msg .= '<li>'.$error.'</li>';
154 154
             }
155 155
             $msg .= '</ul><p>';
156 156
             $msg .= sprintf(
@@ -180,11 +180,11 @@  discard block
 block discarded – undo
180 180
         $this->_scripts_styles = array(
181 181
             'registers'   => array(
182 182
                 'ee-tickets-datetimes-css' => array(
183
-                    'url'  => PRICING_ASSETS_URL . 'event-tickets-datetimes.css',
183
+                    'url'  => PRICING_ASSETS_URL.'event-tickets-datetimes.css',
184 184
                     'type' => 'css',
185 185
                 ),
186 186
                 'ee-dtt-ticket-metabox'    => array(
187
-                    'url'     => PRICING_ASSETS_URL . 'ee-datetime-ticket-metabox.js',
187
+                    'url'     => PRICING_ASSETS_URL.'ee-datetime-ticket-metabox.js',
188 188
                     'depends' => array('ee-datepicker', 'ee-dialog', 'underscore'),
189 189
                 ),
190 190
             ),
@@ -208,9 +208,9 @@  discard block
 block discarded – undo
208 208
                             'event_espresso'
209 209
                         ),
210 210
                         'cancel_button'           => '<button class="button-secondary ee-modal-cancel">'
211
-                                                     . esc_html__('Cancel', 'event_espresso') . '</button>',
211
+                                                     . esc_html__('Cancel', 'event_espresso').'</button>',
212 212
                         'close_button'            => '<button class="button-secondary ee-modal-cancel">'
213
-                                                     . esc_html__('Close', 'event_espresso') . '</button>',
213
+                                                     . esc_html__('Close', 'event_espresso').'</button>',
214 214
                         'single_warning_from_tkt' => esc_html__(
215 215
                             'The Datetime you are attempting to unassign from this ticket is the only remaining datetime for this ticket. Tickets must always have at least one datetime assigned to them.',
216 216
                             'event_espresso'
@@ -220,12 +220,12 @@  discard block
 block discarded – undo
220 220
                             'event_espresso'
221 221
                         ),
222 222
                         'dismiss_button'          => '<button class="button-secondary ee-modal-cancel">'
223
-                                                     . esc_html__('Dismiss', 'event_espresso') . '</button>',
223
+                                                     . esc_html__('Dismiss', 'event_espresso').'</button>',
224 224
                     ),
225 225
                     'DTT_ERROR_MSG'         => array(
226 226
                         'no_ticket_name' => esc_html__('General Admission', 'event_espresso'),
227 227
                         'dismiss_button' => '<div class="save-cancel-button-container"><button class="button-secondary ee-modal-cancel">'
228
-                                            . esc_html__('Dismiss', 'event_espresso') . '</button></div>',
228
+                                            . esc_html__('Dismiss', 'event_espresso').'</button></div>',
229 229
                     ),
230 230
                     'DTT_OVERSELL_WARNING'  => array(
231 231
                         'datetime_ticket' => esc_html__(
@@ -241,7 +241,7 @@  discard block
 block discarded – undo
241 241
                         $this->_date_format_strings['date'],
242 242
                         $this->_date_format_strings['time']
243 243
                     ),
244
-                    'DTT_START_OF_WEEK'     => array('dayValue' => (int)get_option('start_of_week')),
244
+                    'DTT_START_OF_WEEK'     => array('dayValue' => (int) get_option('start_of_week')),
245 245
                 ),
246 246
             ),
247 247
         );
@@ -296,7 +296,7 @@  discard block
 block discarded – undo
296 296
         $timezone = isset($data['timezone_string']) ? $data['timezone_string'] : null;
297 297
         $saved_dtt_ids = array();
298 298
         $saved_dtt_objs = array();
299
-        if (empty($data['edit_event_datetimes']) || !is_array($data['edit_event_datetimes'])) {
299
+        if (empty($data['edit_event_datetimes']) || ! is_array($data['edit_event_datetimes'])) {
300 300
             throw new InvalidArgumentException(
301 301
                 esc_html__(
302 302
                     'The "edit_event_datetimes" array is invalid therefore the event can not be updated.',
@@ -307,7 +307,7 @@  discard block
 block discarded – undo
307 307
         foreach ($data['edit_event_datetimes'] as $row => $datetime_data) {
308 308
             //trim all values to ensure any excess whitespace is removed.
309 309
             $datetime_data = array_map(
310
-                function ($datetime_data) {
310
+                function($datetime_data) {
311 311
                     return is_array($datetime_data) ? $datetime_data : trim($datetime_data);
312 312
                 },
313 313
                 $datetime_data
@@ -337,7 +337,7 @@  discard block
 block discarded – undo
337 337
             );
338 338
             // if we have an id then let's get existing object first and then set the new values.
339 339
             // Otherwise we instantiate a new object for save.
340
-            if (! empty($datetime_data['DTT_ID'])) {
340
+            if ( ! empty($datetime_data['DTT_ID'])) {
341 341
                 $datetime = EE_Registry::instance()
342 342
                                        ->load_model('Datetime', array($timezone))
343 343
                                        ->get_one_by_ID($datetime_data['DTT_ID']);
@@ -430,7 +430,7 @@  discard block
 block discarded – undo
430 430
         $timezone = isset($data['timezone_string']) ? $data['timezone_string'] : null;
431 431
         $saved_tickets = $datetimes_on_existing = array();
432 432
         $old_tickets = isset($data['ticket_IDs']) ? explode(',', $data['ticket_IDs']) : array();
433
-        if(empty($data['edit_tickets']) || ! is_array($data['edit_tickets'])){
433
+        if (empty($data['edit_tickets']) || ! is_array($data['edit_tickets'])) {
434 434
             throw new InvalidArgumentException(
435 435
                 esc_html__(
436 436
                     'The "edit_tickets" array is invalid therefore the event can not be updated.',
@@ -448,7 +448,7 @@  discard block
 block discarded – undo
448 448
             $datetimes_removed = array_diff($starting_tkt_dtt_rows, $tkt_dtt_rows);
449 449
             // trim inputs to ensure any excess whitespace is removed.
450 450
             $tkt = array_map(
451
-                function ($ticket_data) {
451
+                function($ticket_data) {
452 452
                     return is_array($ticket_data) ? $ticket_data : trim($ticket_data);
453 453
                 },
454 454
                 $tkt
@@ -457,7 +457,7 @@  discard block
 block discarded – undo
457 457
             // because we're doing calculations prior to using the models.
458 458
             // note incoming ['TKT_price'] value is already in standard notation (via js).
459 459
             $ticket_price = isset($tkt['TKT_price'])
460
-                ? round((float)$tkt['TKT_price'], 3)
460
+                ? round((float) $tkt['TKT_price'], 3)
461 461
                 : 0;
462 462
             //note incoming base price needs converted from localized value.
463 463
             $base_price = isset($tkt['TKT_base_price'])
@@ -604,7 +604,7 @@  discard block
 block discarded – undo
604 604
             //need to make sue that the TKT_price is accurate after saving the prices.
605 605
             $ticket->ensure_TKT_Price_correct();
606 606
             //handle CREATING a default tkt from the incoming tkt but ONLY if this isn't an autosave.
607
-            if (! defined('DOING_AUTOSAVE') && ! empty($tkt['TKT_is_default_selector'])) {
607
+            if ( ! defined('DOING_AUTOSAVE') && ! empty($tkt['TKT_is_default_selector'])) {
608 608
                 $update_prices = true;
609 609
                 $new_default = clone $ticket;
610 610
                 $new_default->set('TKT_ID', 0);
@@ -723,9 +723,9 @@  discard block
 block discarded – undo
723 723
         // to start we have to add the ticket to all the datetimes its supposed to be with,
724 724
         // and removing the ticket from datetimes it got removed from.
725 725
         // first let's add datetimes
726
-        if (! empty($added_datetimes) && is_array($added_datetimes)) {
726
+        if ( ! empty($added_datetimes) && is_array($added_datetimes)) {
727 727
             foreach ($added_datetimes as $row_id) {
728
-                $row_id = (int)$row_id;
728
+                $row_id = (int) $row_id;
729 729
                 if (isset($saved_datetimes[$row_id]) && $saved_datetimes[$row_id] instanceof EE_Datetime) {
730 730
                     $ticket->_add_relation_to($saved_datetimes[$row_id], 'Datetime');
731 731
                     // Is this an existing ticket (has an ID) and does it have any sold?
@@ -738,9 +738,9 @@  discard block
 block discarded – undo
738 738
             }
739 739
         }
740 740
         // then remove datetimes
741
-        if (! empty($removed_datetimes) && is_array($removed_datetimes)) {
741
+        if ( ! empty($removed_datetimes) && is_array($removed_datetimes)) {
742 742
             foreach ($removed_datetimes as $row_id) {
743
-                $row_id = (int)$row_id;
743
+                $row_id = (int) $row_id;
744 744
                 // its entirely possible that a datetime got deleted (instead of just removed from relationship.
745 745
                 // So make sure we skip over this if the dtt isn't in the $saved_datetimes array)
746 746
                 if (isset($saved_datetimes[$row_id]) && $saved_datetimes[$row_id] instanceof EE_Datetime) {
@@ -850,7 +850,7 @@  discard block
 block discarded – undo
850 850
             );
851 851
         }
852 852
         //possibly need to save tkt
853
-        if (! $ticket->ID()) {
853
+        if ( ! $ticket->ID()) {
854 854
             $ticket->save();
855 855
         }
856 856
         foreach ($prices as $row => $prc) {
@@ -888,11 +888,11 @@  discard block
 block discarded – undo
888 888
             $ticket->_add_relation_to($price, 'Price');
889 889
         }
890 890
         //now let's remove any prices that got removed from the ticket
891
-        if (! empty ($current_prices_on_ticket)) {
891
+        if ( ! empty ($current_prices_on_ticket)) {
892 892
             $current = array_keys($current_prices_on_ticket);
893 893
             $updated = array_keys($updated_prices);
894 894
             $prices_to_remove = array_diff($current, $updated);
895
-            if (! empty($prices_to_remove)) {
895
+            if ( ! empty($prices_to_remove)) {
896 896
                 foreach ($prices_to_remove as $prc_id) {
897 897
                     $p = $current_prices_on_ticket[$prc_id];
898 898
                     $ticket->_remove_relation_to($p, 'Price');
@@ -910,7 +910,7 @@  discard block
 block discarded – undo
910 910
      * @param Events_Admin_Page $event_admin_obj
911 911
      * @return Events_Admin_Page
912 912
      */
913
-    public function autosave_handling( Events_Admin_Page $event_admin_obj)
913
+    public function autosave_handling(Events_Admin_Page $event_admin_obj)
914 914
     {
915 915
         return $event_admin_obj;
916 916
         //doing nothing for the moment.
@@ -1043,7 +1043,7 @@  discard block
 block discarded – undo
1043 1043
                 $TKT_ID = $ticket->get('TKT_ID');
1044 1044
                 $ticket_row = $ticket->get('TKT_row');
1045 1045
                 //we only want unique tickets in our final display!!
1046
-                if (! in_array($TKT_ID, $existing_ticket_ids, true)) {
1046
+                if ( ! in_array($TKT_ID, $existing_ticket_ids, true)) {
1047 1047
                     $existing_ticket_ids[] = $TKT_ID;
1048 1048
                     $all_tickets[] = $ticket;
1049 1049
                 }
@@ -1065,9 +1065,9 @@  discard block
 block discarded – undo
1065 1065
         //sort $all_tickets by order
1066 1066
         usort(
1067 1067
             $all_tickets,
1068
-            function (EE_Ticket $a, EE_Ticket $b) {
1069
-                $a_order = (int)$a->get('TKT_order');
1070
-                $b_order = (int)$b->get('TKT_order');
1068
+            function(EE_Ticket $a, EE_Ticket $b) {
1069
+                $a_order = (int) $a->get('TKT_order');
1070
+                $b_order = (int) $b->get('TKT_order');
1071 1071
                 if ($a_order === $b_order) {
1072 1072
                     return 0;
1073 1073
                 }
@@ -1103,7 +1103,7 @@  discard block
 block discarded – undo
1103 1103
         }
1104 1104
         $main_template_args['ticket_js_structure'] = $this->_get_ticket_js_structure($datetimes, $all_tickets);
1105 1105
         EEH_Template::display_template(
1106
-            PRICING_TEMPLATE_PATH . 'event_tickets_metabox_main.template.php',
1106
+            PRICING_TEMPLATE_PATH.'event_tickets_metabox_main.template.php',
1107 1107
             $main_template_args
1108 1108
         );
1109 1109
     }
@@ -1141,7 +1141,7 @@  discard block
 block discarded – undo
1141 1141
             'dtt_row'                  => $default ? 'DTTNUM' : $datetime_row,
1142 1142
         );
1143 1143
         return EEH_Template::display_template(
1144
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_row_wrapper.template.php',
1144
+            PRICING_TEMPLATE_PATH.'event_tickets_datetime_row_wrapper.template.php',
1145 1145
             $dtt_display_template_args,
1146 1146
             true
1147 1147
         );
@@ -1211,7 +1211,7 @@  discard block
 block discarded – undo
1211 1211
             $this->_is_creating_event
1212 1212
         );
1213 1213
         return EEH_Template::display_template(
1214
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_edit_row.template.php',
1214
+            PRICING_TEMPLATE_PATH.'event_tickets_datetime_edit_row.template.php',
1215 1215
             $template_args,
1216 1216
             true
1217 1217
         );
@@ -1253,7 +1253,7 @@  discard block
 block discarded – undo
1253 1253
             'DTT_ID'                            => $default ? '' : $datetime->ID(),
1254 1254
         );
1255 1255
         //need to setup the list items (but only if this isn't a default skeleton setup)
1256
-        if (! $default) {
1256
+        if ( ! $default) {
1257 1257
             $ticket_row = 1;
1258 1258
             foreach ($all_tickets as $ticket) {
1259 1259
                 $template_args['datetime_tickets_list'] .= $this->_get_datetime_tickets_list_item(
@@ -1279,7 +1279,7 @@  discard block
 block discarded – undo
1279 1279
             $this->_is_creating_event
1280 1280
         );
1281 1281
         return EEH_Template::display_template(
1282
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_attached_tickets_row.template.php',
1282
+            PRICING_TEMPLATE_PATH.'event_tickets_datetime_attached_tickets_row.template.php',
1283 1283
             $template_args,
1284 1284
             true
1285 1285
         );
@@ -1328,8 +1328,8 @@  discard block
 block discarded – undo
1328 1328
                 ? 'TKTNAME'
1329 1329
                 : $ticket->get('TKT_name'),
1330 1330
             'tkt_status_class'        => $no_ticket || $this->_is_creating_event
1331
-                ? ' tkt-status-' . EE_Ticket::onsale
1332
-                : ' tkt-status-' . $ticket->ticket_status(),
1331
+                ? ' tkt-status-'.EE_Ticket::onsale
1332
+                : ' tkt-status-'.$ticket->ticket_status(),
1333 1333
         );
1334 1334
         //filter template args
1335 1335
         $template_args = apply_filters(
@@ -1344,7 +1344,7 @@  discard block
 block discarded – undo
1344 1344
             $this->_is_creating_event
1345 1345
         );
1346 1346
         return EEH_Template::display_template(
1347
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_dtt_tickets_list.template.php',
1347
+            PRICING_TEMPLATE_PATH.'event_tickets_datetime_dtt_tickets_list.template.php',
1348 1348
             $template_args,
1349 1349
             true
1350 1350
         );
@@ -1401,11 +1401,11 @@  discard block
 block discarded – undo
1401 1401
         $count_price_mods = EEM_Price::instance()->get_all_default_prices(true);
1402 1402
         //breaking out complicated condition for ticket_status
1403 1403
         if ($default) {
1404
-            $ticket_status_class = ' tkt-status-' . EE_Ticket::onsale;
1404
+            $ticket_status_class = ' tkt-status-'.EE_Ticket::onsale;
1405 1405
         } else {
1406 1406
             $ticket_status_class = $ticket->is_default()
1407
-                ? ' tkt-status-' . EE_Ticket::onsale
1408
-                : ' tkt-status-' . $ticket->ticket_status();
1407
+                ? ' tkt-status-'.EE_Ticket::onsale
1408
+                : ' tkt-status-'.$ticket->ticket_status();
1409 1409
         }
1410 1410
         //breaking out complicated condition for TKT_taxable
1411 1411
         if ($default) {
@@ -1497,7 +1497,7 @@  discard block
 block discarded – undo
1497 1497
                 : ' style="display:none;"',
1498 1498
             'show_price_mod_button'         => count($prices) > 1
1499 1499
                                                || ($default && $count_price_mods > 0)
1500
-                                               || (! $default && $ticket->deleted())
1500
+                                               || ( ! $default && $ticket->deleted())
1501 1501
                 ? ' style="display:none;"'
1502 1502
                 : '',
1503 1503
             'total_price_rows'              => count($prices) > 1 ? count($prices) : 1,
@@ -1539,7 +1539,7 @@  discard block
 block discarded – undo
1539 1539
             //if empty then the start date will be now.
1540 1540
             $template_args['TKT_start_date'] = date($this->_date_time_format,
1541 1541
                 current_time('timestamp'));
1542
-            $template_args['tkt_status_class'] = ' tkt-status-' . EE_Ticket::onsale;
1542
+            $template_args['tkt_status_class'] = ' tkt-status-'.EE_Ticket::onsale;
1543 1543
         }
1544 1544
         if (empty($template_args['TKT_end_date'])) {
1545 1545
             //get the earliest datetime (if present);
@@ -1549,7 +1549,7 @@  discard block
 block discarded – undo
1549 1549
                     array('order_by' => array('DTT_EVT_start' => 'ASC'))
1550 1550
                 )
1551 1551
                 : null;
1552
-            if (! empty($earliest_dtt)) {
1552
+            if ( ! empty($earliest_dtt)) {
1553 1553
                 $template_args['TKT_end_date'] = $earliest_dtt->get_datetime(
1554 1554
                     'DTT_EVT_start',
1555 1555
                     $this->_date_time_format
@@ -1562,10 +1562,10 @@  discard block
 block discarded – undo
1562 1562
                     )
1563 1563
                 );
1564 1564
             }
1565
-            $template_args['tkt_status_class'] = ' tkt-status-' . EE_Ticket::onsale;
1565
+            $template_args['tkt_status_class'] = ' tkt-status-'.EE_Ticket::onsale;
1566 1566
         }
1567 1567
         //generate ticket_datetime items
1568
-        if (! $default) {
1568
+        if ( ! $default) {
1569 1569
             $datetime_row = 1;
1570 1570
             foreach ($all_datetimes as $datetime) {
1571 1571
                 $template_args['ticket_datetimes_list'] .= $this->_get_ticket_datetime_list_item(
@@ -1581,15 +1581,15 @@  discard block
 block discarded – undo
1581 1581
         }
1582 1582
         $price_row = 1;
1583 1583
         foreach ($prices as $price) {
1584
-            if (! $price instanceof EE_Price)  {
1584
+            if ( ! $price instanceof EE_Price) {
1585 1585
                 continue;
1586 1586
             }
1587 1587
             if ($price->is_base_price()) {
1588 1588
                 $price_row++;
1589 1589
                 continue;
1590 1590
             }
1591
-            $show_trash = !((count($prices) > 1 && $price_row === 1) || count($prices) === 1);
1592
-            $show_create = !(count($prices) > 1 && count($prices) !== $price_row);
1591
+            $show_trash = ! ((count($prices) > 1 && $price_row === 1) || count($prices) === 1);
1592
+            $show_create = ! (count($prices) > 1 && count($prices) !== $price_row);
1593 1593
             $template_args['ticket_price_rows'] .= $this->_get_ticket_price_row(
1594 1594
                 $ticket_row,
1595 1595
                 $price_row,
@@ -1614,7 +1614,7 @@  discard block
 block discarded – undo
1614 1614
             $this->_is_creating_event
1615 1615
         );
1616 1616
         return EEH_Template::display_template(
1617
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_ticket_row.template.php',
1617
+            PRICING_TEMPLATE_PATH.'event_tickets_datetime_ticket_row.template.php',
1618 1618
             $template_args,
1619 1619
             true
1620 1620
         );
@@ -1655,7 +1655,7 @@  discard block
 block discarded – undo
1655 1655
                 $this->_is_creating_event
1656 1656
             );
1657 1657
             $tax_rows .= EEH_Template::display_template(
1658
-                PRICING_TEMPLATE_PATH . 'event_tickets_datetime_ticket_tax_row.template.php',
1658
+                PRICING_TEMPLATE_PATH.'event_tickets_datetime_ticket_tax_row.template.php',
1659 1659
                 $template_args,
1660 1660
                 true
1661 1661
             );
@@ -1767,7 +1767,7 @@  discard block
 block discarded – undo
1767 1767
             $this->_is_creating_event
1768 1768
         );
1769 1769
         return EEH_Template::display_template(
1770
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_ticket_price_row.template.php',
1770
+            PRICING_TEMPLATE_PATH.'event_tickets_datetime_ticket_price_row.template.php',
1771 1771
             $template_args,
1772 1772
             true
1773 1773
         );
@@ -1824,7 +1824,7 @@  discard block
 block discarded – undo
1824 1824
             $this->_is_creating_event
1825 1825
         );
1826 1826
         return EEH_Template::display_template(
1827
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_price_type_base.template.php',
1827
+            PRICING_TEMPLATE_PATH.'event_tickets_datetime_price_type_base.template.php',
1828 1828
             $template_args,
1829 1829
             true
1830 1830
         );
@@ -1851,7 +1851,7 @@  discard block
 block discarded – undo
1851 1851
     ) {
1852 1852
         $select_name = $default && ! $price instanceof EE_Price
1853 1853
             ? 'edit_prices[TICKETNUM][PRICENUM][PRT_ID]'
1854
-            : 'edit_prices[' . $ticket_row . '][' . $price_row . '][PRT_ID]';
1854
+            : 'edit_prices['.$ticket_row.']['.$price_row.'][PRT_ID]';
1855 1855
         /** @var EEM_Price_Type $price_type_model */
1856 1856
         $price_type_model = EE_Registry::instance()->load_model('Price_Type');
1857 1857
         $price_types = $price_type_model->get_all(array(
@@ -1869,7 +1869,7 @@  discard block
 block discarded – undo
1869 1869
         $price_option_spans = '';
1870 1870
         //setup price types for selector
1871 1871
         foreach ($price_types as $price_type) {
1872
-            if (! $price_type instanceof EE_Price_Type) {
1872
+            if ( ! $price_type instanceof EE_Price_Type) {
1873 1873
                 continue;
1874 1874
             }
1875 1875
             $all_price_types[$price_type->ID()] = $price_type->get('PRT_name');
@@ -1880,12 +1880,12 @@  discard block
 block discarded – undo
1880 1880
                 'PRT_is_percent' => $price_type->get('PRT_is_percent') ? 1 : 0,
1881 1881
             );
1882 1882
             $price_option_spans .= EEH_Template::display_template(
1883
-                PRICING_TEMPLATE_PATH . 'event_tickets_datetime_price_option_span.template.php',
1883
+                PRICING_TEMPLATE_PATH.'event_tickets_datetime_price_option_span.template.php',
1884 1884
                 $span_args,
1885 1885
                 true
1886 1886
             );
1887 1887
         }
1888
-        $select_name = $disabled ? 'archive_price[' . $ticket_row . '][' . $price_row . '][PRT_ID]' : $select_name;
1888
+        $select_name = $disabled ? 'archive_price['.$ticket_row.']['.$price_row.'][PRT_ID]' : $select_name;
1889 1889
         $select_input = new EE_Select_Input(
1890 1890
             $all_price_types,
1891 1891
             array(
@@ -1921,7 +1921,7 @@  discard block
 block discarded – undo
1921 1921
             $this->_is_creating_event
1922 1922
         );
1923 1923
         return EEH_Template::display_template(
1924
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_price_modifier_selector.template.php',
1924
+            PRICING_TEMPLATE_PATH.'event_tickets_datetime_price_modifier_selector.template.php',
1925 1925
             $template_args,
1926 1926
             true
1927 1927
         );
@@ -1981,7 +1981,7 @@  discard block
 block discarded – undo
1981 1981
             $this->_is_creating_event
1982 1982
         );
1983 1983
         return EEH_Template::display_template(
1984
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_ticket_datetimes_list_item.template.php',
1984
+            PRICING_TEMPLATE_PATH.'event_tickets_datetime_ticket_datetimes_list_item.template.php',
1985 1985
             $template_args,
1986 1986
             true
1987 1987
         );
@@ -2084,7 +2084,7 @@  discard block
 block discarded – undo
2084 2084
         $default_prices = $price_model->get_all_default_prices();
2085 2085
         $price_row = 1;
2086 2086
         foreach ($default_prices as $price) {
2087
-            if (! $price instanceof EE_Price) {
2087
+            if ( ! $price instanceof EE_Price) {
2088 2088
                 continue;
2089 2089
             }
2090 2090
             if ($price->is_base_price()) {
@@ -2097,8 +2097,8 @@  discard block
 block discarded – undo
2097 2097
                 $price_row++;
2098 2098
                 continue;
2099 2099
             }
2100
-            $show_trash = !((count($default_prices) > 1 && $price_row === 1) || count($default_prices) === 1);
2101
-            $show_create = !(count($default_prices) > 1 && count($default_prices) !== $price_row);
2100
+            $show_trash = ! ((count($default_prices) > 1 && $price_row === 1) || count($default_prices) === 1);
2101
+            $show_create = ! (count($default_prices) > 1 && count($default_prices) !== $price_row);
2102 2102
             $template_args['default_price_rows'] .= $this->_get_ticket_price_row(
2103 2103
                 'TICKETNUM',
2104 2104
                 $price_row,
@@ -2118,7 +2118,7 @@  discard block
 block discarded – undo
2118 2118
             $this->_is_creating_event
2119 2119
         );
2120 2120
         return EEH_Template::display_template(
2121
-            PRICING_TEMPLATE_PATH . 'event_tickets_datetime_ticket_js_structure.template.php',
2121
+            PRICING_TEMPLATE_PATH.'event_tickets_datetime_ticket_js_structure.template.php',
2122 2122
             $template_args,
2123 2123
             true
2124 2124
         );
Please login to merge, or discard this patch.
caffeinated/admin/extend/events/Extend_Events_Admin_Page.core.php 1 patch
Indentation   +1245 added lines, -1245 removed lines patch added patch discarded remove patch
@@ -14,1249 +14,1249 @@
 block discarded – undo
14 14
 {
15 15
 
16 16
 
17
-    /**
18
-     * Extend_Events_Admin_Page constructor.
19
-     *
20
-     * @param bool $routing
21
-     */
22
-    public function __construct($routing = true)
23
-    {
24
-        parent::__construct($routing);
25
-        if (! defined('EVENTS_CAF_TEMPLATE_PATH')) {
26
-            define('EVENTS_CAF_TEMPLATE_PATH', EE_CORE_CAF_ADMIN_EXTEND . 'events/templates/');
27
-            define('EVENTS_CAF_ASSETS', EE_CORE_CAF_ADMIN_EXTEND . 'events/assets/');
28
-            define('EVENTS_CAF_ASSETS_URL', EE_CORE_CAF_ADMIN_EXTEND_URL . 'events/assets/');
29
-        }
30
-    }
31
-
32
-
33
-    /**
34
-     * Sets routes.
35
-     */
36
-    protected function _extend_page_config()
37
-    {
38
-        $this->_admin_base_path = EE_CORE_CAF_ADMIN_EXTEND . 'events';
39
-        //is there a evt_id in the request?
40
-        $evt_id = ! empty($this->_req_data['EVT_ID']) && ! is_array($this->_req_data['EVT_ID'])
41
-            ? $this->_req_data['EVT_ID']
42
-            : 0;
43
-        $evt_id = ! empty($this->_req_data['post']) ? $this->_req_data['post'] : $evt_id;
44
-        //tkt_id?
45
-        $tkt_id             = ! empty($this->_req_data['TKT_ID']) && ! is_array($this->_req_data['TKT_ID'])
46
-            ? $this->_req_data['TKT_ID']
47
-            : 0;
48
-        $new_page_routes    = array(
49
-            'duplicate_event'          => array(
50
-                'func'       => '_duplicate_event',
51
-                'capability' => 'ee_edit_event',
52
-                'obj_id'     => $evt_id,
53
-                'noheader'   => true,
54
-            ),
55
-            'ticket_list_table'        => array(
56
-                'func'       => '_tickets_overview_list_table',
57
-                'capability' => 'ee_read_default_tickets',
58
-            ),
59
-            'trash_ticket'             => array(
60
-                'func'       => '_trash_or_restore_ticket',
61
-                'capability' => 'ee_delete_default_ticket',
62
-                'obj_id'     => $tkt_id,
63
-                'noheader'   => true,
64
-                'args'       => array('trash' => true),
65
-            ),
66
-            'trash_tickets'            => array(
67
-                'func'       => '_trash_or_restore_ticket',
68
-                'capability' => 'ee_delete_default_tickets',
69
-                'noheader'   => true,
70
-                'args'       => array('trash' => true),
71
-            ),
72
-            'restore_ticket'           => array(
73
-                'func'       => '_trash_or_restore_ticket',
74
-                'capability' => 'ee_delete_default_ticket',
75
-                'obj_id'     => $tkt_id,
76
-                'noheader'   => true,
77
-            ),
78
-            'restore_tickets'          => array(
79
-                'func'       => '_trash_or_restore_ticket',
80
-                'capability' => 'ee_delete_default_tickets',
81
-                'noheader'   => true,
82
-            ),
83
-            'delete_ticket'            => array(
84
-                'func'       => '_delete_ticket',
85
-                'capability' => 'ee_delete_default_ticket',
86
-                'obj_id'     => $tkt_id,
87
-                'noheader'   => true,
88
-            ),
89
-            'delete_tickets'           => array(
90
-                'func'       => '_delete_ticket',
91
-                'capability' => 'ee_delete_default_tickets',
92
-                'noheader'   => true,
93
-            ),
94
-            'import_page'              => array(
95
-                'func'       => '_import_page',
96
-                'capability' => 'import',
97
-            ),
98
-            'import'                   => array(
99
-                'func'       => '_import_events',
100
-                'capability' => 'import',
101
-                'noheader'   => true,
102
-            ),
103
-            'import_events'            => array(
104
-                'func'       => '_import_events',
105
-                'capability' => 'import',
106
-                'noheader'   => true,
107
-            ),
108
-            'export_events'            => array(
109
-                'func'       => '_events_export',
110
-                'capability' => 'export',
111
-                'noheader'   => true,
112
-            ),
113
-            'export_categories'        => array(
114
-                'func'       => '_categories_export',
115
-                'capability' => 'export',
116
-                'noheader'   => true,
117
-            ),
118
-            'sample_export_file'       => array(
119
-                'func'       => '_sample_export_file',
120
-                'capability' => 'export',
121
-                'noheader'   => true,
122
-            ),
123
-            'update_template_settings' => array(
124
-                'func'       => '_update_template_settings',
125
-                'capability' => 'manage_options',
126
-                'noheader'   => true,
127
-            ),
128
-        );
129
-        $this->_page_routes = array_merge($this->_page_routes, $new_page_routes);
130
-        //partial route/config override
131
-        $this->_page_config['import_events']['metaboxes'] = $this->_default_espresso_metaboxes;
132
-        $this->_page_config['create_new']['metaboxes'][]  = '_premium_event_editor_meta_boxes';
133
-        $this->_page_config['create_new']['qtips'][]      = 'EE_Event_Editor_Tips';
134
-        $this->_page_config['edit']['qtips'][]            = 'EE_Event_Editor_Tips';
135
-        $this->_page_config['edit']['metaboxes'][]        = '_premium_event_editor_meta_boxes';
136
-        $this->_page_config['default']['list_table']      = 'Extend_Events_Admin_List_Table';
137
-        //add tickets tab but only if there are more than one default ticket!
138
-        $tkt_count = EEM_Ticket::instance()->count_deleted_and_undeleted(
139
-            array(array('TKT_is_default' => 1)),
140
-            'TKT_ID',
141
-            true
142
-        );
143
-        if ($tkt_count > 1) {
144
-            $new_page_config = array(
145
-                'ticket_list_table' => array(
146
-                    'nav'           => array(
147
-                        'label' => esc_html__('Default Tickets', 'event_espresso'),
148
-                        'order' => 60,
149
-                    ),
150
-                    'list_table'    => 'Tickets_List_Table',
151
-                    'require_nonce' => false,
152
-                ),
153
-            );
154
-        }
155
-        //template settings
156
-        $new_page_config['template_settings'] = array(
157
-            'nav'           => array(
158
-                'label' => esc_html__('Templates', 'event_espresso'),
159
-                'order' => 30,
160
-            ),
161
-            'metaboxes'     => array_merge($this->_default_espresso_metaboxes, array('_publish_post_box')),
162
-            'help_tabs'     => array(
163
-                'general_settings_templates_help_tab' => array(
164
-                    'title'    => esc_html__('Templates', 'event_espresso'),
165
-                    'filename' => 'general_settings_templates',
166
-                ),
167
-            ),
168
-            'help_tour'     => array('Templates_Help_Tour'),
169
-            'require_nonce' => false,
170
-        );
171
-        $this->_page_config                   = array_merge($this->_page_config, $new_page_config);
172
-        //add filters and actions
173
-        //modifying _views
174
-        add_filter(
175
-            'FHEE_event_datetime_metabox_add_additional_date_time_template',
176
-            array($this, 'add_additional_datetime_button'),
177
-            10,
178
-            2
179
-        );
180
-        add_filter(
181
-            'FHEE_event_datetime_metabox_clone_button_template',
182
-            array($this, 'add_datetime_clone_button'),
183
-            10,
184
-            2
185
-        );
186
-        add_filter(
187
-            'FHEE_event_datetime_metabox_timezones_template',
188
-            array($this, 'datetime_timezones_template'),
189
-            10,
190
-            2
191
-        );
192
-        //filters for event list table
193
-        add_filter('FHEE__Extend_Events_Admin_List_Table__filters', array($this, 'list_table_filters'), 10, 2);
194
-        add_filter(
195
-            'FHEE__Events_Admin_List_Table__column_actions__action_links',
196
-            array($this, 'extra_list_table_actions'),
197
-            10,
198
-            2
199
-        );
200
-        //legend item
201
-        add_filter('FHEE__Events_Admin_Page___event_legend_items__items', array($this, 'additional_legend_items'));
202
-        add_action('admin_init', array($this, 'admin_init'));
203
-        //heartbeat stuff
204
-        add_filter('heartbeat_received', array($this, 'heartbeat_response'), 10, 2);
205
-    }
206
-
207
-
208
-    /**
209
-     * admin_init
210
-     */
211
-    public function admin_init()
212
-    {
213
-        EE_Registry::$i18n_js_strings = array_merge(
214
-            EE_Registry::$i18n_js_strings,
215
-            array(
216
-                'image_confirm'          => esc_html__(
217
-                    'Do you really want to delete this image? Please remember to update your event to complete the removal.',
218
-                    'event_espresso'
219
-                ),
220
-                'event_starts_on'        => esc_html__('Event Starts on', 'event_espresso'),
221
-                'event_ends_on'          => esc_html__('Event Ends on', 'event_espresso'),
222
-                'event_datetime_actions' => esc_html__('Actions', 'event_espresso'),
223
-                'event_clone_dt_msg'     => esc_html__('Clone this Event Date and Time', 'event_espresso'),
224
-                'remove_event_dt_msg'    => esc_html__('Remove this Event Time', 'event_espresso'),
225
-            )
226
-        );
227
-    }
228
-
229
-
230
-    /**
231
-     * This will be used to listen for any heartbeat data packages coming via the WordPress heartbeat API and handle
232
-     * accordingly.
233
-     *
234
-     * @param array $response The existing heartbeat response array.
235
-     * @param array $data     The incoming data package.
236
-     * @return array  possibly appended response.
237
-     */
238
-    public function heartbeat_response($response, $data)
239
-    {
240
-        /**
241
-         * check whether count of tickets is approaching the potential
242
-         * limits for the server.
243
-         */
244
-        if (! empty($data['input_count'])) {
245
-            $response['max_input_vars_check'] = EE_Registry::instance()->CFG->environment->max_input_vars_limit_check(
246
-                $data['input_count']
247
-            );
248
-        }
249
-        return $response;
250
-    }
251
-
252
-
253
-    /**
254
-     * Add per page screen options to the default ticket list table view.
255
-     */
256
-    protected function _add_screen_options_ticket_list_table()
257
-    {
258
-        $this->_per_page_screen_option();
259
-    }
260
-
261
-
262
-    /**
263
-     * @param string $return
264
-     * @param int    $id
265
-     * @param string $new_title
266
-     * @param string $new_slug
267
-     * @return string
268
-     */
269
-    public function extra_permalink_field_buttons($return, $id, $new_title, $new_slug)
270
-    {
271
-        $return = parent::extra_permalink_field_buttons($return, $id, $new_title, $new_slug);
272
-        //make sure this is only when editing
273
-        if (! empty($id)) {
274
-            $href   = EE_Admin_Page::add_query_args_and_nonce(
275
-                array('action' => 'duplicate_event', 'EVT_ID' => $id),
276
-                $this->_admin_base_url
277
-            );
278
-            $title  = esc_attr__('Duplicate Event', 'event_espresso');
279
-            $return .= '<a href="'
280
-                       . $href
281
-                       . '" title="'
282
-                       . $title
283
-                       . '" id="ee-duplicate-event-button" class="button button-small"  value="duplicate_event">'
284
-                       . $title
285
-                       . '</button>';
286
-        }
287
-        return $return;
288
-    }
289
-
290
-
291
-    /**
292
-     * Set the list table views for the default ticket list table view.
293
-     */
294
-    public function _set_list_table_views_ticket_list_table()
295
-    {
296
-        $this->_views = array(
297
-            'all'     => array(
298
-                'slug'        => 'all',
299
-                'label'       => esc_html__('All', 'event_espresso'),
300
-                'count'       => 0,
301
-                'bulk_action' => array(
302
-                    'trash_tickets' => esc_html__('Move to Trash', 'event_espresso'),
303
-                ),
304
-            ),
305
-            'trashed' => array(
306
-                'slug'        => 'trashed',
307
-                'label'       => esc_html__('Trash', 'event_espresso'),
308
-                'count'       => 0,
309
-                'bulk_action' => array(
310
-                    'restore_tickets' => esc_html__('Restore from Trash', 'event_espresso'),
311
-                    'delete_tickets'  => esc_html__('Delete Permanently', 'event_espresso'),
312
-                ),
313
-            ),
314
-        );
315
-    }
316
-
317
-
318
-    /**
319
-     * Enqueue scripts and styles for the event editor.
320
-     */
321
-    public function load_scripts_styles_edit()
322
-    {
323
-        wp_register_script(
324
-            'ee-event-editor-heartbeat',
325
-            EVENTS_CAF_ASSETS_URL . 'event-editor-heartbeat.js',
326
-            array('ee_admin_js', 'heartbeat'),
327
-            EVENT_ESPRESSO_VERSION,
328
-            true
329
-        );
330
-        wp_enqueue_script('ee-accounting');
331
-        //styles
332
-        wp_enqueue_style('espresso-ui-theme');
333
-        wp_enqueue_script('event_editor_js');
334
-        wp_enqueue_script('ee-event-editor-heartbeat');
335
-    }
336
-
337
-
338
-    /**
339
-     * Returns template for the additional datetime.
340
-     * @param $template
341
-     * @param $template_args
342
-     * @return mixed
343
-     * @throws DomainException
344
-     */
345
-    public function add_additional_datetime_button($template, $template_args)
346
-    {
347
-        return EEH_Template::display_template(
348
-            EVENTS_CAF_TEMPLATE_PATH . 'event_datetime_add_additional_time.template.php',
349
-            $template_args,
350
-            true
351
-        );
352
-    }
353
-
354
-
355
-    /**
356
-     * Returns the template for cloning a datetime.
357
-     * @param $template
358
-     * @param $template_args
359
-     * @return mixed
360
-     * @throws DomainException
361
-     */
362
-    public function add_datetime_clone_button($template, $template_args)
363
-    {
364
-        return EEH_Template::display_template(
365
-            EVENTS_CAF_TEMPLATE_PATH . 'event_datetime_metabox_clone_button.template.php',
366
-            $template_args,
367
-            true
368
-        );
369
-    }
370
-
371
-
372
-    /**
373
-     * Returns the template for datetime timezones.
374
-     * @param $template
375
-     * @param $template_args
376
-     * @return mixed
377
-     * @throws DomainException
378
-     */
379
-    public function datetime_timezones_template($template, $template_args)
380
-    {
381
-        return EEH_Template::display_template(
382
-            EVENTS_CAF_TEMPLATE_PATH . 'event_datetime_timezones.template.php',
383
-            $template_args,
384
-            true
385
-        );
386
-    }
387
-
388
-
389
-    /**
390
-     * Sets the views for the default list table view.
391
-     */
392
-    protected function _set_list_table_views_default()
393
-    {
394
-        parent::_set_list_table_views_default();
395
-        $new_views    = array(
396
-            'today' => array(
397
-                'slug'        => 'today',
398
-                'label'       => esc_html__('Today', 'event_espresso'),
399
-                'count'       => $this->total_events_today(),
400
-                'bulk_action' => array(
401
-                    'trash_events' => esc_html__('Move to Trash', 'event_espresso'),
402
-                ),
403
-            ),
404
-            'month' => array(
405
-                'slug'        => 'month',
406
-                'label'       => esc_html__('This Month', 'event_espresso'),
407
-                'count'       => $this->total_events_this_month(),
408
-                'bulk_action' => array(
409
-                    'trash_events' => esc_html__('Move to Trash', 'event_espresso'),
410
-                ),
411
-            ),
412
-        );
413
-        $this->_views = array_merge($this->_views, $new_views);
414
-    }
415
-
416
-
417
-    /**
418
-     * Returns the extra action links for the default list table view.
419
-     * @param array     $action_links
420
-     * @param \EE_Event $event
421
-     * @return array
422
-     * @throws EE_Error
423
-     */
424
-    public function extra_list_table_actions(array $action_links, \EE_Event $event)
425
-    {
426
-        if (EE_Registry::instance()->CAP->current_user_can(
427
-            'ee_read_registrations',
428
-            'espresso_registrations_reports',
429
-            $event->ID()
430
-        )
431
-        ) {
432
-            $reports_query_args = array(
433
-                'action' => 'reports',
434
-                'EVT_ID' => $event->ID(),
435
-            );
436
-            $reports_link       = EE_Admin_Page::add_query_args_and_nonce($reports_query_args, REG_ADMIN_URL);
437
-            $action_links[]     = '<a href="'
438
-                                  . $reports_link
439
-                                  . '" title="'
440
-                                  . esc_attr__('View Report', 'event_espresso')
441
-                                  . '"><div class="dashicons dashicons-chart-bar"></div></a>'
442
-                                  . "\n\t";
443
-        }
444
-        if (EE_Registry::instance()->CAP->current_user_can('ee_read_global_messages', 'view_filtered_messages')) {
445
-            EE_Registry::instance()->load_helper('MSG_Template');
446
-            $action_links[] = EEH_MSG_Template::get_message_action_link(
447
-                'see_notifications_for',
448
-                null,
449
-                array('EVT_ID' => $event->ID())
450
-            );
451
-        }
452
-        return $action_links;
453
-    }
454
-
455
-
456
-    /**
457
-     * @param $items
458
-     * @return mixed
459
-     */
460
-    public function additional_legend_items($items)
461
-    {
462
-        if (EE_Registry::instance()->CAP->current_user_can(
463
-            'ee_read_registrations',
464
-            'espresso_registrations_reports'
465
-        )
466
-        ) {
467
-            $items['reports'] = array(
468
-                'class' => 'dashicons dashicons-chart-bar',
469
-                'desc'  => esc_html__('Event Reports', 'event_espresso'),
470
-            );
471
-        }
472
-        if (EE_Registry::instance()->CAP->current_user_can('ee_read_global_messages', 'view_filtered_messages')) {
473
-            $related_for_icon = EEH_MSG_Template::get_message_action_icon('see_notifications_for');
474
-            if (isset($related_for_icon['css_class']) && isset($related_for_icon['label'])) {
475
-                $items['view_related_messages'] = array(
476
-                    'class' => $related_for_icon['css_class'],
477
-                    'desc'  => $related_for_icon['label'],
478
-                );
479
-            }
480
-        }
481
-        return $items;
482
-    }
483
-
484
-
485
-    /**
486
-     * This is the callback method for the duplicate event route
487
-     * Method looks for 'EVT_ID' in the request and retrieves that event and its details and duplicates them
488
-     * into a new event.  We add a hook so that any plugins that add extra event details can hook into this
489
-     * action.  Note that the dupe will have **DUPLICATE** as its title and slug.
490
-     * After duplication the redirect is to the new event edit page.
491
-     *
492
-     * @return void
493
-     * @access protected
494
-     * @throws EE_Error If EE_Event is not available with given ID
495
-     */
496
-    protected function _duplicate_event()
497
-    {
498
-        // first make sure the ID for the event is in the request.
499
-        //  If it isn't then we need to bail and redirect back to overview list table (cause how did we get here?)
500
-        if (! isset($this->_req_data['EVT_ID'])) {
501
-            EE_Error::add_error(
502
-                esc_html__(
503
-                    'In order to duplicate an event an Event ID is required.  None was given.',
504
-                    'event_espresso'
505
-                ),
506
-                __FILE__,
507
-                __FUNCTION__,
508
-                __LINE__
509
-            );
510
-            $this->_redirect_after_action(false, '', '', array(), true);
511
-            return;
512
-        }
513
-        //k we've got EVT_ID so let's use that to get the event we'll duplicate
514
-        $orig_event = EEM_Event::instance()->get_one_by_ID($this->_req_data['EVT_ID']);
515
-        if (! $orig_event instanceof EE_Event) {
516
-            throw new EE_Error(
517
-                sprintf(
518
-                    esc_html__('An EE_Event object could not be retrieved for the given ID (%s)', 'event_espresso'),
519
-                    $this->_req_data['EVT_ID']
520
-                )
521
-            );
522
-        }
523
-        //k now let's clone the $orig_event before getting relations
524
-        $new_event = clone $orig_event;
525
-        //original datetimes
526
-        $orig_datetimes = $orig_event->get_many_related('Datetime');
527
-        //other original relations
528
-        $orig_ven = $orig_event->get_many_related('Venue');
529
-        //reset the ID and modify other details to make it clear this is a dupe
530
-        $new_event->set('EVT_ID', 0);
531
-        $new_name = $new_event->name() . ' ' . esc_html__('**DUPLICATE**', 'event_espresso');
532
-        $new_event->set('EVT_name', $new_name);
533
-        $new_event->set(
534
-            'EVT_slug',
535
-            wp_unique_post_slug(
536
-                sanitize_title($orig_event->name()),
537
-                0,
538
-                'publish',
539
-                'espresso_events',
540
-                0
541
-            )
542
-        );
543
-        $new_event->set('status', 'draft');
544
-        //duplicate discussion settings
545
-        $new_event->set('comment_status', $orig_event->get('comment_status'));
546
-        $new_event->set('ping_status', $orig_event->get('ping_status'));
547
-        //save the new event
548
-        $new_event->save();
549
-        //venues
550
-        foreach ($orig_ven as $ven) {
551
-            $new_event->_add_relation_to($ven, 'Venue');
552
-        }
553
-        $new_event->save();
554
-        //now we need to get the question group relations and handle that
555
-        //first primary question groups
556
-        $orig_primary_qgs = $orig_event->get_many_related(
557
-            'Question_Group',
558
-            array(array('Event_Question_Group.EQG_primary' => 1))
559
-        );
560
-        if (! empty($orig_primary_qgs)) {
561
-            foreach ($orig_primary_qgs as $id => $obj) {
562
-                if ($obj instanceof EE_Question_Group) {
563
-                    $new_event->_add_relation_to($obj, 'Question_Group', array('EQG_primary' => 1));
564
-                }
565
-            }
566
-        }
567
-        //next additional attendee question groups
568
-        $orig_additional_qgs = $orig_event->get_many_related(
569
-            'Question_Group',
570
-            array(array('Event_Question_Group.EQG_primary' => 0))
571
-        );
572
-        if (! empty($orig_additional_qgs)) {
573
-            foreach ($orig_additional_qgs as $id => $obj) {
574
-                if ($obj instanceof EE_Question_Group) {
575
-                    $new_event->_add_relation_to($obj, 'Question_Group', array('EQG_primary' => 0));
576
-                }
577
-            }
578
-        }
579
-        //now save
580
-        $new_event->save();
581
-        //k now that we have the new event saved we can loop through the datetimes and start adding relations.
582
-        $cloned_tickets = array();
583
-        foreach ($orig_datetimes as $orig_dtt) {
584
-            if (! $orig_dtt instanceof EE_Datetime) {
585
-                continue;
586
-            }
587
-            $new_dtt   = clone $orig_dtt;
588
-            $orig_tkts = $orig_dtt->tickets();
589
-            //save new dtt then add to event
590
-            $new_dtt->set('DTT_ID', 0);
591
-            $new_dtt->set('DTT_sold', 0);
592
-            $new_dtt->set_reserved(0);
593
-            $new_dtt->save();
594
-            $new_event->_add_relation_to($new_dtt, 'Datetime');
595
-            $new_event->save();
596
-            //now let's get the ticket relations setup.
597
-            foreach ((array)$orig_tkts as $orig_tkt) {
598
-                //it's possible a datetime will have no tickets so let's verify we HAVE a ticket first.
599
-                if (! $orig_tkt instanceof EE_Ticket) {
600
-                    continue;
601
-                }
602
-                //is this ticket archived?  If it is then let's skip
603
-                if ($orig_tkt->get('TKT_deleted')) {
604
-                    continue;
605
-                }
606
-                // does this original ticket already exist in the clone_tickets cache?
607
-                //  If so we'll just use the new ticket from it.
608
-                if (isset($cloned_tickets[$orig_tkt->ID()])) {
609
-                    $new_tkt = $cloned_tickets[$orig_tkt->ID()];
610
-                } else {
611
-                    $new_tkt = clone $orig_tkt;
612
-                    //get relations on the $orig_tkt that we need to setup.
613
-                    $orig_prices = $orig_tkt->prices();
614
-                    $new_tkt->set('TKT_ID', 0);
615
-                    $new_tkt->set('TKT_sold', 0);
616
-                    $new_tkt->set('TKT_reserved', 0);
617
-                    $new_tkt->save(); //make sure new ticket has ID.
618
-                    //price relations on new ticket need to be setup.
619
-                    foreach ($orig_prices as $orig_price) {
620
-                        $new_price = clone $orig_price;
621
-                        $new_price->set('PRC_ID', 0);
622
-                        $new_price->save();
623
-                        $new_tkt->_add_relation_to($new_price, 'Price');
624
-                        $new_tkt->save();
625
-                    }
626
-
627
-                    do_action(
628
-                        'AHEE__Extend_Events_Admin_Page___duplicate_event__duplicate_ticket__after',
629
-                        $orig_tkt,
630
-                        $new_tkt,
631
-                        $orig_prices,
632
-                        $orig_event,
633
-                        $orig_dtt,
634
-                        $new_dtt
635
-                    );
636
-                }
637
-                // k now we can add the new ticket as a relation to the new datetime
638
-                // and make sure its added to our cached $cloned_tickets array
639
-                // for use with later datetimes that have the same ticket.
640
-                $new_dtt->_add_relation_to($new_tkt, 'Ticket');
641
-                $new_dtt->save();
642
-                $cloned_tickets[$orig_tkt->ID()] = $new_tkt;
643
-            }
644
-        }
645
-        //clone taxonomy information
646
-        $taxonomies_to_clone_with = apply_filters(
647
-            'FHEE__Extend_Events_Admin_Page___duplicate_event__taxonomies_to_clone',
648
-            array('espresso_event_categories', 'espresso_event_type', 'post_tag')
649
-        );
650
-        //get terms for original event (notice)
651
-        $orig_terms = wp_get_object_terms($orig_event->ID(), $taxonomies_to_clone_with);
652
-        //loop through terms and add them to new event.
653
-        foreach ($orig_terms as $term) {
654
-            wp_set_object_terms($new_event->ID(), $term->term_id, $term->taxonomy, true);
655
-        }
656
-        do_action('AHEE__Extend_Events_Admin_Page___duplicate_event__after', $new_event, $orig_event);
657
-        //now let's redirect to the edit page for this duplicated event if we have a new event id.
658
-        if ($new_event->ID()) {
659
-            $redirect_args = array(
660
-                'post'   => $new_event->ID(),
661
-                'action' => 'edit',
662
-            );
663
-            EE_Error::add_success(
664
-                esc_html__(
665
-                    'Event successfully duplicated.  Please review the details below and make any necessary edits',
666
-                    'event_espresso'
667
-                )
668
-            );
669
-        } else {
670
-            $redirect_args = array(
671
-                'action' => 'default',
672
-            );
673
-            EE_Error::add_error(
674
-                esc_html__('Not able to duplicate event.  Something went wrong.', 'event_espresso'),
675
-                __FILE__,
676
-                __FUNCTION__,
677
-                __LINE__
678
-            );
679
-        }
680
-        $this->_redirect_after_action(false, '', '', $redirect_args, true);
681
-    }
682
-
683
-
684
-    /**
685
-     * Generates output for the import page.
686
-     * @throws DomainException
687
-     */
688
-    protected function _import_page()
689
-    {
690
-        $title                                      = esc_html__('Import', 'event_espresso');
691
-        $intro                                      = esc_html__(
692
-            'If you have a previously exported Event Espresso 4 information in a Comma Separated Value (CSV) file format, you can upload the file here: ',
693
-            'event_espresso'
694
-        );
695
-        $form_url                                   = EVENTS_ADMIN_URL;
696
-        $action                                     = 'import_events';
697
-        $type                                       = 'csv';
698
-        $this->_template_args['form']               = EE_Import::instance()->upload_form(
699
-            $title, $intro, $form_url, $action, $type
700
-        );
701
-        $this->_template_args['sample_file_link']   = EE_Admin_Page::add_query_args_and_nonce(
702
-            array('action' => 'sample_export_file'),
703
-            $this->_admin_base_url
704
-        );
705
-        $content                                    = EEH_Template::display_template(
706
-            EVENTS_CAF_TEMPLATE_PATH . 'import_page.template.php',
707
-            $this->_template_args,
708
-            true
709
-        );
710
-        $this->_template_args['admin_page_content'] = $content;
711
-        $this->display_admin_page_with_sidebar();
712
-    }
713
-
714
-
715
-    /**
716
-     * _import_events
717
-     * This handles displaying the screen and running imports for importing events.
718
-     *
719
-     * @return void
720
-     */
721
-    protected function _import_events()
722
-    {
723
-        require_once(EE_CLASSES . 'EE_Import.class.php');
724
-        $success = EE_Import::instance()->import();
725
-        $this->_redirect_after_action($success, 'Import File', 'ran', array('action' => 'import_page'), true);
726
-    }
727
-
728
-
729
-    /**
730
-     * _events_export
731
-     * Will export all (or just the given event) to a Excel compatible file.
732
-     *
733
-     * @access protected
734
-     * @return void
735
-     */
736
-    protected function _events_export()
737
-    {
738
-        if (isset($this->_req_data['EVT_ID'])) {
739
-            $event_ids = $this->_req_data['EVT_ID'];
740
-        } elseif (isset($this->_req_data['EVT_IDs'])) {
741
-            $event_ids = $this->_req_data['EVT_IDs'];
742
-        } else {
743
-            $event_ids = null;
744
-        }
745
-        //todo: I don't like doing this but it'll do until we modify EE_Export Class.
746
-        $new_request_args = array(
747
-            'export' => 'report',
748
-            'action' => 'all_event_data',
749
-            'EVT_ID' => $event_ids,
750
-        );
751
-        $this->_req_data  = array_merge($this->_req_data, $new_request_args);
752
-        if (is_readable(EE_CLASSES . 'EE_Export.class.php')) {
753
-            require_once(EE_CLASSES . 'EE_Export.class.php');
754
-            $EE_Export = EE_Export::instance($this->_req_data);
755
-            $EE_Export->export();
756
-        }
757
-    }
758
-
759
-
760
-    /**
761
-     * handle category exports()
762
-     *
763
-     * @return void
764
-     */
765
-    protected function _categories_export()
766
-    {
767
-        //todo: I don't like doing this but it'll do until we modify EE_Export Class.
768
-        $new_request_args = array(
769
-            'export'       => 'report',
770
-            'action'       => 'categories',
771
-            'category_ids' => $this->_req_data['EVT_CAT_ID'],
772
-        );
773
-        $this->_req_data  = array_merge($this->_req_data, $new_request_args);
774
-        if (is_readable(EE_CLASSES . 'EE_Export.class.php')) {
775
-            require_once(EE_CLASSES . 'EE_Export.class.php');
776
-            $EE_Export = EE_Export::instance($this->_req_data);
777
-            $EE_Export->export();
778
-        }
779
-    }
780
-
781
-
782
-    /**
783
-     * Creates a sample CSV file for importing
784
-     */
785
-    protected function _sample_export_file()
786
-    {
787
-        //		require_once(EE_CLASSES . 'EE_Export.class.php');
788
-        EE_Export::instance()->export_sample();
789
-    }
790
-
791
-
792
-    /*************        Template Settings        *************/
793
-    /**
794
-     * Generates template settings page output
795
-     * @throws DomainException
796
-     * @throws EE_Error
797
-     */
798
-    protected function _template_settings()
799
-    {
800
-        $this->_template_args['values'] = $this->_yes_no_values;
801
-        /**
802
-         * Note leaving this filter in for backward compatibility this was moved in 4.6.x
803
-         * from General_Settings_Admin_Page to here.
804
-         */
805
-        $this->_template_args = apply_filters(
806
-            'FHEE__General_Settings_Admin_Page__template_settings__template_args',
807
-            $this->_template_args
808
-        );
809
-        $this->_set_add_edit_form_tags('update_template_settings');
810
-        $this->_set_publish_post_box_vars(null, false, false, null, false);
811
-        $this->_template_args['admin_page_content'] = EEH_Template::display_template(
812
-            EVENTS_CAF_TEMPLATE_PATH . 'template_settings.template.php',
813
-            $this->_template_args,
814
-            true
815
-        );
816
-        $this->display_admin_page_with_sidebar();
817
-    }
818
-
819
-
820
-    /**
821
-     * Handler for updating template settings.
822
-     */
823
-    protected function _update_template_settings()
824
-    {
825
-        /**
826
-         * Note leaving this filter in for backward compatibility this was moved in 4.6.x
827
-         * from General_Settings_Admin_Page to here.
828
-         */
829
-        EE_Registry::instance()->CFG->template_settings = apply_filters(
830
-            'FHEE__General_Settings_Admin_Page__update_template_settings__data',
831
-            EE_Registry::instance()->CFG->template_settings,
832
-            $this->_req_data
833
-        );
834
-        //update custom post type slugs and detect if we need to flush rewrite rules
835
-        $old_slug                                          = EE_Registry::instance()->CFG->core->event_cpt_slug;
836
-        EE_Registry::instance()->CFG->core->event_cpt_slug = empty($this->_req_data['event_cpt_slug'])
837
-            ? EE_Registry::instance()->CFG->core->event_cpt_slug
838
-            : sanitize_title_with_dashes($this->_req_data['event_cpt_slug']);
839
-        $what                                              = 'Template Settings';
840
-        $success                                           = $this->_update_espresso_configuration(
841
-            $what,
842
-            EE_Registry::instance()->CFG->template_settings,
843
-            __FILE__,
844
-            __FUNCTION__,
845
-            __LINE__
846
-        );
847
-        if (EE_Registry::instance()->CFG->core->event_cpt_slug != $old_slug) {
848
-            update_option('ee_flush_rewrite_rules', true);
849
-        }
850
-        $this->_redirect_after_action($success, $what, 'updated', array('action' => 'template_settings'));
851
-    }
852
-
853
-
854
-    /**
855
-     * _premium_event_editor_meta_boxes
856
-     * add all metaboxes related to the event_editor
857
-     *
858
-     * @access protected
859
-     * @return void
860
-     * @throws EE_Error
861
-     */
862
-    protected function _premium_event_editor_meta_boxes()
863
-    {
864
-        $this->verify_cpt_object();
865
-        add_meta_box(
866
-            'espresso_event_editor_event_options',
867
-            esc_html__('Event Registration Options', 'event_espresso'),
868
-            array($this, 'registration_options_meta_box'),
869
-            $this->page_slug,
870
-            'side',
871
-            'core'
872
-        );
873
-    }
874
-
875
-
876
-    /**
877
-     * override caf metabox
878
-     *
879
-     * @return void
880
-     * @throws DomainException
881
-     */
882
-    public function registration_options_meta_box()
883
-    {
884
-        $yes_no_values                                    = array(
885
-            array('id' => true, 'text' => esc_html__('Yes', 'event_espresso')),
886
-            array('id' => false, 'text' => esc_html__('No', 'event_espresso')),
887
-        );
888
-        $default_reg_status_values                        = EEM_Registration::reg_status_array(
889
-            array(
890
-                EEM_Registration::status_id_cancelled,
891
-                EEM_Registration::status_id_declined,
892
-                EEM_Registration::status_id_incomplete,
893
-                EEM_Registration::status_id_wait_list,
894
-            ),
895
-            true
896
-        );
897
-        $template_args['active_status']                   = $this->_cpt_model_obj->pretty_active_status(false);
898
-        $template_args['_event']                          = $this->_cpt_model_obj;
899
-        $template_args['additional_limit']                = $this->_cpt_model_obj->additional_limit();
900
-        $template_args['default_registration_status']     = EEH_Form_Fields::select_input(
901
-            'default_reg_status',
902
-            $default_reg_status_values,
903
-            $this->_cpt_model_obj->default_registration_status()
904
-        );
905
-        $template_args['display_description']             = EEH_Form_Fields::select_input(
906
-            'display_desc',
907
-            $yes_no_values,
908
-            $this->_cpt_model_obj->display_description()
909
-        );
910
-        $template_args['display_ticket_selector']         = EEH_Form_Fields::select_input(
911
-            'display_ticket_selector',
912
-            $yes_no_values,
913
-            $this->_cpt_model_obj->display_ticket_selector(),
914
-            '',
915
-            '',
916
-            false
917
-        );
918
-        $template_args['EVT_default_registration_status'] = EEH_Form_Fields::select_input(
919
-            'EVT_default_registration_status',
920
-            $default_reg_status_values,
921
-            $this->_cpt_model_obj->default_registration_status()
922
-        );
923
-        $template_args['additional_registration_options'] = apply_filters(
924
-            'FHEE__Events_Admin_Page__registration_options_meta_box__additional_registration_options',
925
-            '',
926
-            $template_args,
927
-            $yes_no_values,
928
-            $default_reg_status_values
929
-        );
930
-        EEH_Template::display_template(
931
-            EVENTS_CAF_TEMPLATE_PATH . 'event_registration_options.template.php',
932
-            $template_args
933
-        );
934
-    }
935
-
936
-
937
-
938
-    /**
939
-     * wp_list_table_mods for caf
940
-     * ============================
941
-     */
942
-    /**
943
-     * hook into list table filters and provide filters for caffeinated list table
944
-     *
945
-     * @param  array $old_filters    any existing filters present
946
-     * @param  array $list_table_obj the list table object
947
-     * @return array                  new filters
948
-     */
949
-    public function list_table_filters($old_filters, $list_table_obj)
950
-    {
951
-        $filters = array();
952
-        //first month/year filters
953
-        $filters[] = $this->espresso_event_months_dropdown();
954
-        $status    = isset($this->_req_data['status']) ? $this->_req_data['status'] : null;
955
-        //active status dropdown
956
-        if ($status !== 'draft') {
957
-            $filters[] = $this->active_status_dropdown(
958
-                isset($this->_req_data['active_status']) ? $this->_req_data['active_status'] : ''
959
-            );
960
-        }
961
-        //category filter
962
-        $filters[] = $this->category_dropdown();
963
-        return array_merge($old_filters, $filters);
964
-    }
965
-
966
-
967
-    /**
968
-     * espresso_event_months_dropdown
969
-     *
970
-     * @access public
971
-     * @return string                dropdown listing month/year selections for events.
972
-     */
973
-    public function espresso_event_months_dropdown()
974
-    {
975
-        // what we need to do is get all PRIMARY datetimes for all events to filter on.
976
-        // Note we need to include any other filters that are set!
977
-        $status = isset($this->_req_data['status']) ? $this->_req_data['status'] : null;
978
-        //categories?
979
-        $category = isset($this->_req_data['EVT_CAT']) && $this->_req_data['EVT_CAT'] > 0
980
-            ? $this->_req_data['EVT_CAT']
981
-            : null;
982
-        //active status?
983
-        $active_status = isset($this->_req_data['active_status']) ? $this->_req_data['active_status'] : null;
984
-        $cur_date      = isset($this->_req_data['month_range']) ? $this->_req_data['month_range'] : '';
985
-        return EEH_Form_Fields::generate_event_months_dropdown($cur_date, $status, $category, $active_status);
986
-    }
987
-
988
-
989
-    /**
990
-     * returns a list of "active" statuses on the event
991
-     *
992
-     * @param  string $current_value whatever the current active status is
993
-     * @return string
994
-     */
995
-    public function active_status_dropdown($current_value = '')
996
-    {
997
-        $select_name = 'active_status';
998
-        $values      = array(
999
-            'none'     => esc_html__('Show Active/Inactive', 'event_espresso'),
1000
-            'active'   => esc_html__('Active', 'event_espresso'),
1001
-            'upcoming' => esc_html__('Upcoming', 'event_espresso'),
1002
-            'expired'  => esc_html__('Expired', 'event_espresso'),
1003
-            'inactive' => esc_html__('Inactive', 'event_espresso'),
1004
-        );
1005
-        $id          = 'id="espresso-active-status-dropdown-filter"';
1006
-        $class       = 'wide';
1007
-        return EEH_Form_Fields::select_input($select_name, $values, $current_value, $id, $class);
1008
-    }
1009
-
1010
-
1011
-    /**
1012
-     * output a dropdown of the categories for the category filter on the event admin list table
1013
-     *
1014
-     * @access  public
1015
-     * @return string html
1016
-     */
1017
-    public function category_dropdown()
1018
-    {
1019
-        $cur_cat = isset($this->_req_data['EVT_CAT']) ? $this->_req_data['EVT_CAT'] : -1;
1020
-        return EEH_Form_Fields::generate_event_category_dropdown($cur_cat);
1021
-    }
1022
-
1023
-
1024
-    /**
1025
-     * get total number of events today
1026
-     *
1027
-     * @access public
1028
-     * @return int
1029
-     * @throws EE_Error
1030
-     */
1031
-    public function total_events_today()
1032
-    {
1033
-        $start = EEM_Datetime::instance()->convert_datetime_for_query(
1034
-            'DTT_EVT_start',
1035
-            date('Y-m-d') . ' 00:00:00',
1036
-            'Y-m-d H:i:s',
1037
-            'UTC'
1038
-        );
1039
-        $end   = EEM_Datetime::instance()->convert_datetime_for_query(
1040
-            'DTT_EVT_start',
1041
-            date('Y-m-d') . ' 23:59:59',
1042
-            'Y-m-d H:i:s',
1043
-            'UTC'
1044
-        );
1045
-        $where = array(
1046
-            'Datetime.DTT_EVT_start' => array('BETWEEN', array($start, $end)),
1047
-        );
1048
-        $count = EEM_Event::instance()->count(array($where, 'caps' => 'read_admin'), 'EVT_ID', true);
1049
-        return $count;
1050
-    }
1051
-
1052
-
1053
-    /**
1054
-     * get total number of events this month
1055
-     *
1056
-     * @access public
1057
-     * @return int
1058
-     * @throws EE_Error
1059
-     */
1060
-    public function total_events_this_month()
1061
-    {
1062
-        //Dates
1063
-        $this_year_r     = date('Y');
1064
-        $this_month_r    = date('m');
1065
-        $days_this_month = date('t');
1066
-        $start           = EEM_Datetime::instance()->convert_datetime_for_query(
1067
-            'DTT_EVT_start',
1068
-            $this_year_r . '-' . $this_month_r . '-01 00:00:00',
1069
-            'Y-m-d H:i:s',
1070
-            'UTC'
1071
-        );
1072
-        $end             = EEM_Datetime::instance()->convert_datetime_for_query(
1073
-            'DTT_EVT_start',
1074
-            $this_year_r . '-' . $this_month_r . '-' . $days_this_month . ' 23:59:59',
1075
-            'Y-m-d H:i:s',
1076
-            'UTC'
1077
-        );
1078
-        $where           = array(
1079
-            'Datetime.DTT_EVT_start' => array('BETWEEN', array($start, $end)),
1080
-        );
1081
-        $count           = EEM_Event::instance()->count(array($where, 'caps' => 'read_admin'), 'EVT_ID', true);
1082
-        return $count;
1083
-    }
1084
-
1085
-
1086
-    /** DEFAULT TICKETS STUFF **/
1087
-
1088
-    /**
1089
-     * Output default tickets list table view.
1090
-     */
1091
-    public function _tickets_overview_list_table()
1092
-    {
1093
-        $this->_search_btn_label = esc_html__('Tickets', 'event_espresso');
1094
-        $this->display_admin_list_table_page_with_no_sidebar();
1095
-    }
1096
-
1097
-
1098
-    /**
1099
-     * @param int  $per_page
1100
-     * @param bool $count
1101
-     * @param bool $trashed
1102
-     * @return \EE_Soft_Delete_Base_Class[]|int
1103
-     */
1104
-    public function get_default_tickets($per_page = 10, $count = false, $trashed = false)
1105
-    {
1106
-        $orderby = empty($this->_req_data['orderby']) ? 'TKT_name' : $this->_req_data['orderby'];
1107
-        $order   = empty($this->_req_data['order']) ? 'ASC' : $this->_req_data['order'];
1108
-        switch ($orderby) {
1109
-            case 'TKT_name':
1110
-                $orderby = array('TKT_name' => $order);
1111
-                break;
1112
-            case 'TKT_price':
1113
-                $orderby = array('TKT_price' => $order);
1114
-                break;
1115
-            case 'TKT_uses':
1116
-                $orderby = array('TKT_uses' => $order);
1117
-                break;
1118
-            case 'TKT_min':
1119
-                $orderby = array('TKT_min' => $order);
1120
-                break;
1121
-            case 'TKT_max':
1122
-                $orderby = array('TKT_max' => $order);
1123
-                break;
1124
-            case 'TKT_qty':
1125
-                $orderby = array('TKT_qty' => $order);
1126
-                break;
1127
-        }
1128
-        $current_page = isset($this->_req_data['paged']) && ! empty($this->_req_data['paged'])
1129
-            ? $this->_req_data['paged']
1130
-            : 1;
1131
-        $per_page     = isset($this->_req_data['perpage']) && ! empty($this->_req_data['perpage'])
1132
-            ? $this->_req_data['perpage']
1133
-            : $per_page;
1134
-        $_where       = array(
1135
-            'TKT_is_default' => 1,
1136
-            'TKT_deleted'    => $trashed,
1137
-        );
1138
-        $offset       = ($current_page - 1) * $per_page;
1139
-        $limit        = array($offset, $per_page);
1140
-        if (isset($this->_req_data['s'])) {
1141
-            $sstr         = '%' . $this->_req_data['s'] . '%';
1142
-            $_where['OR'] = array(
1143
-                'TKT_name'        => array('LIKE', $sstr),
1144
-                'TKT_description' => array('LIKE', $sstr),
1145
-            );
1146
-        }
1147
-        $query_params = array(
1148
-            $_where,
1149
-            'order_by' => $orderby,
1150
-            'limit'    => $limit,
1151
-            'group_by' => 'TKT_ID',
1152
-        );
1153
-        if ($count) {
1154
-            return EEM_Ticket::instance()->count_deleted_and_undeleted(array($_where));
1155
-        } else {
1156
-            return EEM_Ticket::instance()->get_all_deleted_and_undeleted($query_params);
1157
-        }
1158
-    }
1159
-
1160
-
1161
-    /**
1162
-     * @param bool $trash
1163
-     * @throws EE_Error
1164
-     */
1165
-    protected function _trash_or_restore_ticket($trash = false)
1166
-    {
1167
-        $success = 1;
1168
-        $TKT     = EEM_Ticket::instance();
1169
-        //checkboxes?
1170
-        if (! empty($this->_req_data['checkbox']) && is_array($this->_req_data['checkbox'])) {
1171
-            //if array has more than one element then success message should be plural
1172
-            $success = count($this->_req_data['checkbox']) > 1 ? 2 : 1;
1173
-            //cycle thru the boxes
1174
-            while (list($TKT_ID, $value) = each($this->_req_data['checkbox'])) {
1175
-                if ($trash) {
1176
-                    if (! $TKT->delete_by_ID($TKT_ID)) {
1177
-                        $success = 0;
1178
-                    }
1179
-                } else {
1180
-                    if (! $TKT->restore_by_ID($TKT_ID)) {
1181
-                        $success = 0;
1182
-                    }
1183
-                }
1184
-            }
1185
-        } else {
1186
-            //grab single id and trash
1187
-            $TKT_ID = absint($this->_req_data['TKT_ID']);
1188
-            if ($trash) {
1189
-                if (! $TKT->delete_by_ID($TKT_ID)) {
1190
-                    $success = 0;
1191
-                }
1192
-            } else {
1193
-                if (! $TKT->restore_by_ID($TKT_ID)) {
1194
-                    $success = 0;
1195
-                }
1196
-            }
1197
-        }
1198
-        $action_desc = $trash ? 'moved to the trash' : 'restored';
1199
-        $query_args  = array(
1200
-            'action' => 'ticket_list_table',
1201
-            'status' => $trash ? '' : 'trashed',
1202
-        );
1203
-        $this->_redirect_after_action($success, 'Tickets', $action_desc, $query_args);
1204
-    }
1205
-
1206
-
1207
-    /**
1208
-     * Handles trashing default ticket.
1209
-     */
1210
-    protected function _delete_ticket()
1211
-    {
1212
-        $success = 1;
1213
-        //checkboxes?
1214
-        if (! empty($this->_req_data['checkbox']) && is_array($this->_req_data['checkbox'])) {
1215
-            //if array has more than one element then success message should be plural
1216
-            $success = count($this->_req_data['checkbox']) > 1 ? 2 : 1;
1217
-            //cycle thru the boxes
1218
-            while (list($TKT_ID, $value) = each($this->_req_data['checkbox'])) {
1219
-                //delete
1220
-                if (! $this->_delete_the_ticket($TKT_ID)) {
1221
-                    $success = 0;
1222
-                }
1223
-            }
1224
-        } else {
1225
-            //grab single id and trash
1226
-            $TKT_ID = absint($this->_req_data['TKT_ID']);
1227
-            if (! $this->_delete_the_ticket($TKT_ID)) {
1228
-                $success = 0;
1229
-            }
1230
-        }
1231
-        $action_desc = 'deleted';
1232
-        $query_args  = array(
1233
-            'action' => 'ticket_list_table',
1234
-            'status' => 'trashed',
1235
-        );
1236
-        //fail safe.  If the default ticket count === 1 then we need to redirect to event overview.
1237
-        if (EEM_Ticket::instance()->count_deleted_and_undeleted(
1238
-            array(array('TKT_is_default' => 1)),
1239
-            'TKT_ID',
1240
-            true
1241
-        )
1242
-        ) {
1243
-            $query_args = array();
1244
-        }
1245
-        $this->_redirect_after_action($success, 'Tickets', $action_desc, $query_args);
1246
-    }
1247
-
1248
-
1249
-    /**
1250
-     * @param int $TKT_ID
1251
-     * @return bool|int
1252
-     * @throws EE_Error
1253
-     */
1254
-    protected function _delete_the_ticket($TKT_ID)
1255
-    {
1256
-        $tkt = EEM_Ticket::instance()->get_one_by_ID($TKT_ID);
1257
-        $tkt->_remove_relations('Datetime');
1258
-        //delete all related prices first
1259
-        $tkt->delete_related_permanently('Price');
1260
-        return $tkt->delete_permanently();
1261
-    }
17
+	/**
18
+	 * Extend_Events_Admin_Page constructor.
19
+	 *
20
+	 * @param bool $routing
21
+	 */
22
+	public function __construct($routing = true)
23
+	{
24
+		parent::__construct($routing);
25
+		if (! defined('EVENTS_CAF_TEMPLATE_PATH')) {
26
+			define('EVENTS_CAF_TEMPLATE_PATH', EE_CORE_CAF_ADMIN_EXTEND . 'events/templates/');
27
+			define('EVENTS_CAF_ASSETS', EE_CORE_CAF_ADMIN_EXTEND . 'events/assets/');
28
+			define('EVENTS_CAF_ASSETS_URL', EE_CORE_CAF_ADMIN_EXTEND_URL . 'events/assets/');
29
+		}
30
+	}
31
+
32
+
33
+	/**
34
+	 * Sets routes.
35
+	 */
36
+	protected function _extend_page_config()
37
+	{
38
+		$this->_admin_base_path = EE_CORE_CAF_ADMIN_EXTEND . 'events';
39
+		//is there a evt_id in the request?
40
+		$evt_id = ! empty($this->_req_data['EVT_ID']) && ! is_array($this->_req_data['EVT_ID'])
41
+			? $this->_req_data['EVT_ID']
42
+			: 0;
43
+		$evt_id = ! empty($this->_req_data['post']) ? $this->_req_data['post'] : $evt_id;
44
+		//tkt_id?
45
+		$tkt_id             = ! empty($this->_req_data['TKT_ID']) && ! is_array($this->_req_data['TKT_ID'])
46
+			? $this->_req_data['TKT_ID']
47
+			: 0;
48
+		$new_page_routes    = array(
49
+			'duplicate_event'          => array(
50
+				'func'       => '_duplicate_event',
51
+				'capability' => 'ee_edit_event',
52
+				'obj_id'     => $evt_id,
53
+				'noheader'   => true,
54
+			),
55
+			'ticket_list_table'        => array(
56
+				'func'       => '_tickets_overview_list_table',
57
+				'capability' => 'ee_read_default_tickets',
58
+			),
59
+			'trash_ticket'             => array(
60
+				'func'       => '_trash_or_restore_ticket',
61
+				'capability' => 'ee_delete_default_ticket',
62
+				'obj_id'     => $tkt_id,
63
+				'noheader'   => true,
64
+				'args'       => array('trash' => true),
65
+			),
66
+			'trash_tickets'            => array(
67
+				'func'       => '_trash_or_restore_ticket',
68
+				'capability' => 'ee_delete_default_tickets',
69
+				'noheader'   => true,
70
+				'args'       => array('trash' => true),
71
+			),
72
+			'restore_ticket'           => array(
73
+				'func'       => '_trash_or_restore_ticket',
74
+				'capability' => 'ee_delete_default_ticket',
75
+				'obj_id'     => $tkt_id,
76
+				'noheader'   => true,
77
+			),
78
+			'restore_tickets'          => array(
79
+				'func'       => '_trash_or_restore_ticket',
80
+				'capability' => 'ee_delete_default_tickets',
81
+				'noheader'   => true,
82
+			),
83
+			'delete_ticket'            => array(
84
+				'func'       => '_delete_ticket',
85
+				'capability' => 'ee_delete_default_ticket',
86
+				'obj_id'     => $tkt_id,
87
+				'noheader'   => true,
88
+			),
89
+			'delete_tickets'           => array(
90
+				'func'       => '_delete_ticket',
91
+				'capability' => 'ee_delete_default_tickets',
92
+				'noheader'   => true,
93
+			),
94
+			'import_page'              => array(
95
+				'func'       => '_import_page',
96
+				'capability' => 'import',
97
+			),
98
+			'import'                   => array(
99
+				'func'       => '_import_events',
100
+				'capability' => 'import',
101
+				'noheader'   => true,
102
+			),
103
+			'import_events'            => array(
104
+				'func'       => '_import_events',
105
+				'capability' => 'import',
106
+				'noheader'   => true,
107
+			),
108
+			'export_events'            => array(
109
+				'func'       => '_events_export',
110
+				'capability' => 'export',
111
+				'noheader'   => true,
112
+			),
113
+			'export_categories'        => array(
114
+				'func'       => '_categories_export',
115
+				'capability' => 'export',
116
+				'noheader'   => true,
117
+			),
118
+			'sample_export_file'       => array(
119
+				'func'       => '_sample_export_file',
120
+				'capability' => 'export',
121
+				'noheader'   => true,
122
+			),
123
+			'update_template_settings' => array(
124
+				'func'       => '_update_template_settings',
125
+				'capability' => 'manage_options',
126
+				'noheader'   => true,
127
+			),
128
+		);
129
+		$this->_page_routes = array_merge($this->_page_routes, $new_page_routes);
130
+		//partial route/config override
131
+		$this->_page_config['import_events']['metaboxes'] = $this->_default_espresso_metaboxes;
132
+		$this->_page_config['create_new']['metaboxes'][]  = '_premium_event_editor_meta_boxes';
133
+		$this->_page_config['create_new']['qtips'][]      = 'EE_Event_Editor_Tips';
134
+		$this->_page_config['edit']['qtips'][]            = 'EE_Event_Editor_Tips';
135
+		$this->_page_config['edit']['metaboxes'][]        = '_premium_event_editor_meta_boxes';
136
+		$this->_page_config['default']['list_table']      = 'Extend_Events_Admin_List_Table';
137
+		//add tickets tab but only if there are more than one default ticket!
138
+		$tkt_count = EEM_Ticket::instance()->count_deleted_and_undeleted(
139
+			array(array('TKT_is_default' => 1)),
140
+			'TKT_ID',
141
+			true
142
+		);
143
+		if ($tkt_count > 1) {
144
+			$new_page_config = array(
145
+				'ticket_list_table' => array(
146
+					'nav'           => array(
147
+						'label' => esc_html__('Default Tickets', 'event_espresso'),
148
+						'order' => 60,
149
+					),
150
+					'list_table'    => 'Tickets_List_Table',
151
+					'require_nonce' => false,
152
+				),
153
+			);
154
+		}
155
+		//template settings
156
+		$new_page_config['template_settings'] = array(
157
+			'nav'           => array(
158
+				'label' => esc_html__('Templates', 'event_espresso'),
159
+				'order' => 30,
160
+			),
161
+			'metaboxes'     => array_merge($this->_default_espresso_metaboxes, array('_publish_post_box')),
162
+			'help_tabs'     => array(
163
+				'general_settings_templates_help_tab' => array(
164
+					'title'    => esc_html__('Templates', 'event_espresso'),
165
+					'filename' => 'general_settings_templates',
166
+				),
167
+			),
168
+			'help_tour'     => array('Templates_Help_Tour'),
169
+			'require_nonce' => false,
170
+		);
171
+		$this->_page_config                   = array_merge($this->_page_config, $new_page_config);
172
+		//add filters and actions
173
+		//modifying _views
174
+		add_filter(
175
+			'FHEE_event_datetime_metabox_add_additional_date_time_template',
176
+			array($this, 'add_additional_datetime_button'),
177
+			10,
178
+			2
179
+		);
180
+		add_filter(
181
+			'FHEE_event_datetime_metabox_clone_button_template',
182
+			array($this, 'add_datetime_clone_button'),
183
+			10,
184
+			2
185
+		);
186
+		add_filter(
187
+			'FHEE_event_datetime_metabox_timezones_template',
188
+			array($this, 'datetime_timezones_template'),
189
+			10,
190
+			2
191
+		);
192
+		//filters for event list table
193
+		add_filter('FHEE__Extend_Events_Admin_List_Table__filters', array($this, 'list_table_filters'), 10, 2);
194
+		add_filter(
195
+			'FHEE__Events_Admin_List_Table__column_actions__action_links',
196
+			array($this, 'extra_list_table_actions'),
197
+			10,
198
+			2
199
+		);
200
+		//legend item
201
+		add_filter('FHEE__Events_Admin_Page___event_legend_items__items', array($this, 'additional_legend_items'));
202
+		add_action('admin_init', array($this, 'admin_init'));
203
+		//heartbeat stuff
204
+		add_filter('heartbeat_received', array($this, 'heartbeat_response'), 10, 2);
205
+	}
206
+
207
+
208
+	/**
209
+	 * admin_init
210
+	 */
211
+	public function admin_init()
212
+	{
213
+		EE_Registry::$i18n_js_strings = array_merge(
214
+			EE_Registry::$i18n_js_strings,
215
+			array(
216
+				'image_confirm'          => esc_html__(
217
+					'Do you really want to delete this image? Please remember to update your event to complete the removal.',
218
+					'event_espresso'
219
+				),
220
+				'event_starts_on'        => esc_html__('Event Starts on', 'event_espresso'),
221
+				'event_ends_on'          => esc_html__('Event Ends on', 'event_espresso'),
222
+				'event_datetime_actions' => esc_html__('Actions', 'event_espresso'),
223
+				'event_clone_dt_msg'     => esc_html__('Clone this Event Date and Time', 'event_espresso'),
224
+				'remove_event_dt_msg'    => esc_html__('Remove this Event Time', 'event_espresso'),
225
+			)
226
+		);
227
+	}
228
+
229
+
230
+	/**
231
+	 * This will be used to listen for any heartbeat data packages coming via the WordPress heartbeat API and handle
232
+	 * accordingly.
233
+	 *
234
+	 * @param array $response The existing heartbeat response array.
235
+	 * @param array $data     The incoming data package.
236
+	 * @return array  possibly appended response.
237
+	 */
238
+	public function heartbeat_response($response, $data)
239
+	{
240
+		/**
241
+		 * check whether count of tickets is approaching the potential
242
+		 * limits for the server.
243
+		 */
244
+		if (! empty($data['input_count'])) {
245
+			$response['max_input_vars_check'] = EE_Registry::instance()->CFG->environment->max_input_vars_limit_check(
246
+				$data['input_count']
247
+			);
248
+		}
249
+		return $response;
250
+	}
251
+
252
+
253
+	/**
254
+	 * Add per page screen options to the default ticket list table view.
255
+	 */
256
+	protected function _add_screen_options_ticket_list_table()
257
+	{
258
+		$this->_per_page_screen_option();
259
+	}
260
+
261
+
262
+	/**
263
+	 * @param string $return
264
+	 * @param int    $id
265
+	 * @param string $new_title
266
+	 * @param string $new_slug
267
+	 * @return string
268
+	 */
269
+	public function extra_permalink_field_buttons($return, $id, $new_title, $new_slug)
270
+	{
271
+		$return = parent::extra_permalink_field_buttons($return, $id, $new_title, $new_slug);
272
+		//make sure this is only when editing
273
+		if (! empty($id)) {
274
+			$href   = EE_Admin_Page::add_query_args_and_nonce(
275
+				array('action' => 'duplicate_event', 'EVT_ID' => $id),
276
+				$this->_admin_base_url
277
+			);
278
+			$title  = esc_attr__('Duplicate Event', 'event_espresso');
279
+			$return .= '<a href="'
280
+					   . $href
281
+					   . '" title="'
282
+					   . $title
283
+					   . '" id="ee-duplicate-event-button" class="button button-small"  value="duplicate_event">'
284
+					   . $title
285
+					   . '</button>';
286
+		}
287
+		return $return;
288
+	}
289
+
290
+
291
+	/**
292
+	 * Set the list table views for the default ticket list table view.
293
+	 */
294
+	public function _set_list_table_views_ticket_list_table()
295
+	{
296
+		$this->_views = array(
297
+			'all'     => array(
298
+				'slug'        => 'all',
299
+				'label'       => esc_html__('All', 'event_espresso'),
300
+				'count'       => 0,
301
+				'bulk_action' => array(
302
+					'trash_tickets' => esc_html__('Move to Trash', 'event_espresso'),
303
+				),
304
+			),
305
+			'trashed' => array(
306
+				'slug'        => 'trashed',
307
+				'label'       => esc_html__('Trash', 'event_espresso'),
308
+				'count'       => 0,
309
+				'bulk_action' => array(
310
+					'restore_tickets' => esc_html__('Restore from Trash', 'event_espresso'),
311
+					'delete_tickets'  => esc_html__('Delete Permanently', 'event_espresso'),
312
+				),
313
+			),
314
+		);
315
+	}
316
+
317
+
318
+	/**
319
+	 * Enqueue scripts and styles for the event editor.
320
+	 */
321
+	public function load_scripts_styles_edit()
322
+	{
323
+		wp_register_script(
324
+			'ee-event-editor-heartbeat',
325
+			EVENTS_CAF_ASSETS_URL . 'event-editor-heartbeat.js',
326
+			array('ee_admin_js', 'heartbeat'),
327
+			EVENT_ESPRESSO_VERSION,
328
+			true
329
+		);
330
+		wp_enqueue_script('ee-accounting');
331
+		//styles
332
+		wp_enqueue_style('espresso-ui-theme');
333
+		wp_enqueue_script('event_editor_js');
334
+		wp_enqueue_script('ee-event-editor-heartbeat');
335
+	}
336
+
337
+
338
+	/**
339
+	 * Returns template for the additional datetime.
340
+	 * @param $template
341
+	 * @param $template_args
342
+	 * @return mixed
343
+	 * @throws DomainException
344
+	 */
345
+	public function add_additional_datetime_button($template, $template_args)
346
+	{
347
+		return EEH_Template::display_template(
348
+			EVENTS_CAF_TEMPLATE_PATH . 'event_datetime_add_additional_time.template.php',
349
+			$template_args,
350
+			true
351
+		);
352
+	}
353
+
354
+
355
+	/**
356
+	 * Returns the template for cloning a datetime.
357
+	 * @param $template
358
+	 * @param $template_args
359
+	 * @return mixed
360
+	 * @throws DomainException
361
+	 */
362
+	public function add_datetime_clone_button($template, $template_args)
363
+	{
364
+		return EEH_Template::display_template(
365
+			EVENTS_CAF_TEMPLATE_PATH . 'event_datetime_metabox_clone_button.template.php',
366
+			$template_args,
367
+			true
368
+		);
369
+	}
370
+
371
+
372
+	/**
373
+	 * Returns the template for datetime timezones.
374
+	 * @param $template
375
+	 * @param $template_args
376
+	 * @return mixed
377
+	 * @throws DomainException
378
+	 */
379
+	public function datetime_timezones_template($template, $template_args)
380
+	{
381
+		return EEH_Template::display_template(
382
+			EVENTS_CAF_TEMPLATE_PATH . 'event_datetime_timezones.template.php',
383
+			$template_args,
384
+			true
385
+		);
386
+	}
387
+
388
+
389
+	/**
390
+	 * Sets the views for the default list table view.
391
+	 */
392
+	protected function _set_list_table_views_default()
393
+	{
394
+		parent::_set_list_table_views_default();
395
+		$new_views    = array(
396
+			'today' => array(
397
+				'slug'        => 'today',
398
+				'label'       => esc_html__('Today', 'event_espresso'),
399
+				'count'       => $this->total_events_today(),
400
+				'bulk_action' => array(
401
+					'trash_events' => esc_html__('Move to Trash', 'event_espresso'),
402
+				),
403
+			),
404
+			'month' => array(
405
+				'slug'        => 'month',
406
+				'label'       => esc_html__('This Month', 'event_espresso'),
407
+				'count'       => $this->total_events_this_month(),
408
+				'bulk_action' => array(
409
+					'trash_events' => esc_html__('Move to Trash', 'event_espresso'),
410
+				),
411
+			),
412
+		);
413
+		$this->_views = array_merge($this->_views, $new_views);
414
+	}
415
+
416
+
417
+	/**
418
+	 * Returns the extra action links for the default list table view.
419
+	 * @param array     $action_links
420
+	 * @param \EE_Event $event
421
+	 * @return array
422
+	 * @throws EE_Error
423
+	 */
424
+	public function extra_list_table_actions(array $action_links, \EE_Event $event)
425
+	{
426
+		if (EE_Registry::instance()->CAP->current_user_can(
427
+			'ee_read_registrations',
428
+			'espresso_registrations_reports',
429
+			$event->ID()
430
+		)
431
+		) {
432
+			$reports_query_args = array(
433
+				'action' => 'reports',
434
+				'EVT_ID' => $event->ID(),
435
+			);
436
+			$reports_link       = EE_Admin_Page::add_query_args_and_nonce($reports_query_args, REG_ADMIN_URL);
437
+			$action_links[]     = '<a href="'
438
+								  . $reports_link
439
+								  . '" title="'
440
+								  . esc_attr__('View Report', 'event_espresso')
441
+								  . '"><div class="dashicons dashicons-chart-bar"></div></a>'
442
+								  . "\n\t";
443
+		}
444
+		if (EE_Registry::instance()->CAP->current_user_can('ee_read_global_messages', 'view_filtered_messages')) {
445
+			EE_Registry::instance()->load_helper('MSG_Template');
446
+			$action_links[] = EEH_MSG_Template::get_message_action_link(
447
+				'see_notifications_for',
448
+				null,
449
+				array('EVT_ID' => $event->ID())
450
+			);
451
+		}
452
+		return $action_links;
453
+	}
454
+
455
+
456
+	/**
457
+	 * @param $items
458
+	 * @return mixed
459
+	 */
460
+	public function additional_legend_items($items)
461
+	{
462
+		if (EE_Registry::instance()->CAP->current_user_can(
463
+			'ee_read_registrations',
464
+			'espresso_registrations_reports'
465
+		)
466
+		) {
467
+			$items['reports'] = array(
468
+				'class' => 'dashicons dashicons-chart-bar',
469
+				'desc'  => esc_html__('Event Reports', 'event_espresso'),
470
+			);
471
+		}
472
+		if (EE_Registry::instance()->CAP->current_user_can('ee_read_global_messages', 'view_filtered_messages')) {
473
+			$related_for_icon = EEH_MSG_Template::get_message_action_icon('see_notifications_for');
474
+			if (isset($related_for_icon['css_class']) && isset($related_for_icon['label'])) {
475
+				$items['view_related_messages'] = array(
476
+					'class' => $related_for_icon['css_class'],
477
+					'desc'  => $related_for_icon['label'],
478
+				);
479
+			}
480
+		}
481
+		return $items;
482
+	}
483
+
484
+
485
+	/**
486
+	 * This is the callback method for the duplicate event route
487
+	 * Method looks for 'EVT_ID' in the request and retrieves that event and its details and duplicates them
488
+	 * into a new event.  We add a hook so that any plugins that add extra event details can hook into this
489
+	 * action.  Note that the dupe will have **DUPLICATE** as its title and slug.
490
+	 * After duplication the redirect is to the new event edit page.
491
+	 *
492
+	 * @return void
493
+	 * @access protected
494
+	 * @throws EE_Error If EE_Event is not available with given ID
495
+	 */
496
+	protected function _duplicate_event()
497
+	{
498
+		// first make sure the ID for the event is in the request.
499
+		//  If it isn't then we need to bail and redirect back to overview list table (cause how did we get here?)
500
+		if (! isset($this->_req_data['EVT_ID'])) {
501
+			EE_Error::add_error(
502
+				esc_html__(
503
+					'In order to duplicate an event an Event ID is required.  None was given.',
504
+					'event_espresso'
505
+				),
506
+				__FILE__,
507
+				__FUNCTION__,
508
+				__LINE__
509
+			);
510
+			$this->_redirect_after_action(false, '', '', array(), true);
511
+			return;
512
+		}
513
+		//k we've got EVT_ID so let's use that to get the event we'll duplicate
514
+		$orig_event = EEM_Event::instance()->get_one_by_ID($this->_req_data['EVT_ID']);
515
+		if (! $orig_event instanceof EE_Event) {
516
+			throw new EE_Error(
517
+				sprintf(
518
+					esc_html__('An EE_Event object could not be retrieved for the given ID (%s)', 'event_espresso'),
519
+					$this->_req_data['EVT_ID']
520
+				)
521
+			);
522
+		}
523
+		//k now let's clone the $orig_event before getting relations
524
+		$new_event = clone $orig_event;
525
+		//original datetimes
526
+		$orig_datetimes = $orig_event->get_many_related('Datetime');
527
+		//other original relations
528
+		$orig_ven = $orig_event->get_many_related('Venue');
529
+		//reset the ID and modify other details to make it clear this is a dupe
530
+		$new_event->set('EVT_ID', 0);
531
+		$new_name = $new_event->name() . ' ' . esc_html__('**DUPLICATE**', 'event_espresso');
532
+		$new_event->set('EVT_name', $new_name);
533
+		$new_event->set(
534
+			'EVT_slug',
535
+			wp_unique_post_slug(
536
+				sanitize_title($orig_event->name()),
537
+				0,
538
+				'publish',
539
+				'espresso_events',
540
+				0
541
+			)
542
+		);
543
+		$new_event->set('status', 'draft');
544
+		//duplicate discussion settings
545
+		$new_event->set('comment_status', $orig_event->get('comment_status'));
546
+		$new_event->set('ping_status', $orig_event->get('ping_status'));
547
+		//save the new event
548
+		$new_event->save();
549
+		//venues
550
+		foreach ($orig_ven as $ven) {
551
+			$new_event->_add_relation_to($ven, 'Venue');
552
+		}
553
+		$new_event->save();
554
+		//now we need to get the question group relations and handle that
555
+		//first primary question groups
556
+		$orig_primary_qgs = $orig_event->get_many_related(
557
+			'Question_Group',
558
+			array(array('Event_Question_Group.EQG_primary' => 1))
559
+		);
560
+		if (! empty($orig_primary_qgs)) {
561
+			foreach ($orig_primary_qgs as $id => $obj) {
562
+				if ($obj instanceof EE_Question_Group) {
563
+					$new_event->_add_relation_to($obj, 'Question_Group', array('EQG_primary' => 1));
564
+				}
565
+			}
566
+		}
567
+		//next additional attendee question groups
568
+		$orig_additional_qgs = $orig_event->get_many_related(
569
+			'Question_Group',
570
+			array(array('Event_Question_Group.EQG_primary' => 0))
571
+		);
572
+		if (! empty($orig_additional_qgs)) {
573
+			foreach ($orig_additional_qgs as $id => $obj) {
574
+				if ($obj instanceof EE_Question_Group) {
575
+					$new_event->_add_relation_to($obj, 'Question_Group', array('EQG_primary' => 0));
576
+				}
577
+			}
578
+		}
579
+		//now save
580
+		$new_event->save();
581
+		//k now that we have the new event saved we can loop through the datetimes and start adding relations.
582
+		$cloned_tickets = array();
583
+		foreach ($orig_datetimes as $orig_dtt) {
584
+			if (! $orig_dtt instanceof EE_Datetime) {
585
+				continue;
586
+			}
587
+			$new_dtt   = clone $orig_dtt;
588
+			$orig_tkts = $orig_dtt->tickets();
589
+			//save new dtt then add to event
590
+			$new_dtt->set('DTT_ID', 0);
591
+			$new_dtt->set('DTT_sold', 0);
592
+			$new_dtt->set_reserved(0);
593
+			$new_dtt->save();
594
+			$new_event->_add_relation_to($new_dtt, 'Datetime');
595
+			$new_event->save();
596
+			//now let's get the ticket relations setup.
597
+			foreach ((array)$orig_tkts as $orig_tkt) {
598
+				//it's possible a datetime will have no tickets so let's verify we HAVE a ticket first.
599
+				if (! $orig_tkt instanceof EE_Ticket) {
600
+					continue;
601
+				}
602
+				//is this ticket archived?  If it is then let's skip
603
+				if ($orig_tkt->get('TKT_deleted')) {
604
+					continue;
605
+				}
606
+				// does this original ticket already exist in the clone_tickets cache?
607
+				//  If so we'll just use the new ticket from it.
608
+				if (isset($cloned_tickets[$orig_tkt->ID()])) {
609
+					$new_tkt = $cloned_tickets[$orig_tkt->ID()];
610
+				} else {
611
+					$new_tkt = clone $orig_tkt;
612
+					//get relations on the $orig_tkt that we need to setup.
613
+					$orig_prices = $orig_tkt->prices();
614
+					$new_tkt->set('TKT_ID', 0);
615
+					$new_tkt->set('TKT_sold', 0);
616
+					$new_tkt->set('TKT_reserved', 0);
617
+					$new_tkt->save(); //make sure new ticket has ID.
618
+					//price relations on new ticket need to be setup.
619
+					foreach ($orig_prices as $orig_price) {
620
+						$new_price = clone $orig_price;
621
+						$new_price->set('PRC_ID', 0);
622
+						$new_price->save();
623
+						$new_tkt->_add_relation_to($new_price, 'Price');
624
+						$new_tkt->save();
625
+					}
626
+
627
+					do_action(
628
+						'AHEE__Extend_Events_Admin_Page___duplicate_event__duplicate_ticket__after',
629
+						$orig_tkt,
630
+						$new_tkt,
631
+						$orig_prices,
632
+						$orig_event,
633
+						$orig_dtt,
634
+						$new_dtt
635
+					);
636
+				}
637
+				// k now we can add the new ticket as a relation to the new datetime
638
+				// and make sure its added to our cached $cloned_tickets array
639
+				// for use with later datetimes that have the same ticket.
640
+				$new_dtt->_add_relation_to($new_tkt, 'Ticket');
641
+				$new_dtt->save();
642
+				$cloned_tickets[$orig_tkt->ID()] = $new_tkt;
643
+			}
644
+		}
645
+		//clone taxonomy information
646
+		$taxonomies_to_clone_with = apply_filters(
647
+			'FHEE__Extend_Events_Admin_Page___duplicate_event__taxonomies_to_clone',
648
+			array('espresso_event_categories', 'espresso_event_type', 'post_tag')
649
+		);
650
+		//get terms for original event (notice)
651
+		$orig_terms = wp_get_object_terms($orig_event->ID(), $taxonomies_to_clone_with);
652
+		//loop through terms and add them to new event.
653
+		foreach ($orig_terms as $term) {
654
+			wp_set_object_terms($new_event->ID(), $term->term_id, $term->taxonomy, true);
655
+		}
656
+		do_action('AHEE__Extend_Events_Admin_Page___duplicate_event__after', $new_event, $orig_event);
657
+		//now let's redirect to the edit page for this duplicated event if we have a new event id.
658
+		if ($new_event->ID()) {
659
+			$redirect_args = array(
660
+				'post'   => $new_event->ID(),
661
+				'action' => 'edit',
662
+			);
663
+			EE_Error::add_success(
664
+				esc_html__(
665
+					'Event successfully duplicated.  Please review the details below and make any necessary edits',
666
+					'event_espresso'
667
+				)
668
+			);
669
+		} else {
670
+			$redirect_args = array(
671
+				'action' => 'default',
672
+			);
673
+			EE_Error::add_error(
674
+				esc_html__('Not able to duplicate event.  Something went wrong.', 'event_espresso'),
675
+				__FILE__,
676
+				__FUNCTION__,
677
+				__LINE__
678
+			);
679
+		}
680
+		$this->_redirect_after_action(false, '', '', $redirect_args, true);
681
+	}
682
+
683
+
684
+	/**
685
+	 * Generates output for the import page.
686
+	 * @throws DomainException
687
+	 */
688
+	protected function _import_page()
689
+	{
690
+		$title                                      = esc_html__('Import', 'event_espresso');
691
+		$intro                                      = esc_html__(
692
+			'If you have a previously exported Event Espresso 4 information in a Comma Separated Value (CSV) file format, you can upload the file here: ',
693
+			'event_espresso'
694
+		);
695
+		$form_url                                   = EVENTS_ADMIN_URL;
696
+		$action                                     = 'import_events';
697
+		$type                                       = 'csv';
698
+		$this->_template_args['form']               = EE_Import::instance()->upload_form(
699
+			$title, $intro, $form_url, $action, $type
700
+		);
701
+		$this->_template_args['sample_file_link']   = EE_Admin_Page::add_query_args_and_nonce(
702
+			array('action' => 'sample_export_file'),
703
+			$this->_admin_base_url
704
+		);
705
+		$content                                    = EEH_Template::display_template(
706
+			EVENTS_CAF_TEMPLATE_PATH . 'import_page.template.php',
707
+			$this->_template_args,
708
+			true
709
+		);
710
+		$this->_template_args['admin_page_content'] = $content;
711
+		$this->display_admin_page_with_sidebar();
712
+	}
713
+
714
+
715
+	/**
716
+	 * _import_events
717
+	 * This handles displaying the screen and running imports for importing events.
718
+	 *
719
+	 * @return void
720
+	 */
721
+	protected function _import_events()
722
+	{
723
+		require_once(EE_CLASSES . 'EE_Import.class.php');
724
+		$success = EE_Import::instance()->import();
725
+		$this->_redirect_after_action($success, 'Import File', 'ran', array('action' => 'import_page'), true);
726
+	}
727
+
728
+
729
+	/**
730
+	 * _events_export
731
+	 * Will export all (or just the given event) to a Excel compatible file.
732
+	 *
733
+	 * @access protected
734
+	 * @return void
735
+	 */
736
+	protected function _events_export()
737
+	{
738
+		if (isset($this->_req_data['EVT_ID'])) {
739
+			$event_ids = $this->_req_data['EVT_ID'];
740
+		} elseif (isset($this->_req_data['EVT_IDs'])) {
741
+			$event_ids = $this->_req_data['EVT_IDs'];
742
+		} else {
743
+			$event_ids = null;
744
+		}
745
+		//todo: I don't like doing this but it'll do until we modify EE_Export Class.
746
+		$new_request_args = array(
747
+			'export' => 'report',
748
+			'action' => 'all_event_data',
749
+			'EVT_ID' => $event_ids,
750
+		);
751
+		$this->_req_data  = array_merge($this->_req_data, $new_request_args);
752
+		if (is_readable(EE_CLASSES . 'EE_Export.class.php')) {
753
+			require_once(EE_CLASSES . 'EE_Export.class.php');
754
+			$EE_Export = EE_Export::instance($this->_req_data);
755
+			$EE_Export->export();
756
+		}
757
+	}
758
+
759
+
760
+	/**
761
+	 * handle category exports()
762
+	 *
763
+	 * @return void
764
+	 */
765
+	protected function _categories_export()
766
+	{
767
+		//todo: I don't like doing this but it'll do until we modify EE_Export Class.
768
+		$new_request_args = array(
769
+			'export'       => 'report',
770
+			'action'       => 'categories',
771
+			'category_ids' => $this->_req_data['EVT_CAT_ID'],
772
+		);
773
+		$this->_req_data  = array_merge($this->_req_data, $new_request_args);
774
+		if (is_readable(EE_CLASSES . 'EE_Export.class.php')) {
775
+			require_once(EE_CLASSES . 'EE_Export.class.php');
776
+			$EE_Export = EE_Export::instance($this->_req_data);
777
+			$EE_Export->export();
778
+		}
779
+	}
780
+
781
+
782
+	/**
783
+	 * Creates a sample CSV file for importing
784
+	 */
785
+	protected function _sample_export_file()
786
+	{
787
+		//		require_once(EE_CLASSES . 'EE_Export.class.php');
788
+		EE_Export::instance()->export_sample();
789
+	}
790
+
791
+
792
+	/*************        Template Settings        *************/
793
+	/**
794
+	 * Generates template settings page output
795
+	 * @throws DomainException
796
+	 * @throws EE_Error
797
+	 */
798
+	protected function _template_settings()
799
+	{
800
+		$this->_template_args['values'] = $this->_yes_no_values;
801
+		/**
802
+		 * Note leaving this filter in for backward compatibility this was moved in 4.6.x
803
+		 * from General_Settings_Admin_Page to here.
804
+		 */
805
+		$this->_template_args = apply_filters(
806
+			'FHEE__General_Settings_Admin_Page__template_settings__template_args',
807
+			$this->_template_args
808
+		);
809
+		$this->_set_add_edit_form_tags('update_template_settings');
810
+		$this->_set_publish_post_box_vars(null, false, false, null, false);
811
+		$this->_template_args['admin_page_content'] = EEH_Template::display_template(
812
+			EVENTS_CAF_TEMPLATE_PATH . 'template_settings.template.php',
813
+			$this->_template_args,
814
+			true
815
+		);
816
+		$this->display_admin_page_with_sidebar();
817
+	}
818
+
819
+
820
+	/**
821
+	 * Handler for updating template settings.
822
+	 */
823
+	protected function _update_template_settings()
824
+	{
825
+		/**
826
+		 * Note leaving this filter in for backward compatibility this was moved in 4.6.x
827
+		 * from General_Settings_Admin_Page to here.
828
+		 */
829
+		EE_Registry::instance()->CFG->template_settings = apply_filters(
830
+			'FHEE__General_Settings_Admin_Page__update_template_settings__data',
831
+			EE_Registry::instance()->CFG->template_settings,
832
+			$this->_req_data
833
+		);
834
+		//update custom post type slugs and detect if we need to flush rewrite rules
835
+		$old_slug                                          = EE_Registry::instance()->CFG->core->event_cpt_slug;
836
+		EE_Registry::instance()->CFG->core->event_cpt_slug = empty($this->_req_data['event_cpt_slug'])
837
+			? EE_Registry::instance()->CFG->core->event_cpt_slug
838
+			: sanitize_title_with_dashes($this->_req_data['event_cpt_slug']);
839
+		$what                                              = 'Template Settings';
840
+		$success                                           = $this->_update_espresso_configuration(
841
+			$what,
842
+			EE_Registry::instance()->CFG->template_settings,
843
+			__FILE__,
844
+			__FUNCTION__,
845
+			__LINE__
846
+		);
847
+		if (EE_Registry::instance()->CFG->core->event_cpt_slug != $old_slug) {
848
+			update_option('ee_flush_rewrite_rules', true);
849
+		}
850
+		$this->_redirect_after_action($success, $what, 'updated', array('action' => 'template_settings'));
851
+	}
852
+
853
+
854
+	/**
855
+	 * _premium_event_editor_meta_boxes
856
+	 * add all metaboxes related to the event_editor
857
+	 *
858
+	 * @access protected
859
+	 * @return void
860
+	 * @throws EE_Error
861
+	 */
862
+	protected function _premium_event_editor_meta_boxes()
863
+	{
864
+		$this->verify_cpt_object();
865
+		add_meta_box(
866
+			'espresso_event_editor_event_options',
867
+			esc_html__('Event Registration Options', 'event_espresso'),
868
+			array($this, 'registration_options_meta_box'),
869
+			$this->page_slug,
870
+			'side',
871
+			'core'
872
+		);
873
+	}
874
+
875
+
876
+	/**
877
+	 * override caf metabox
878
+	 *
879
+	 * @return void
880
+	 * @throws DomainException
881
+	 */
882
+	public function registration_options_meta_box()
883
+	{
884
+		$yes_no_values                                    = array(
885
+			array('id' => true, 'text' => esc_html__('Yes', 'event_espresso')),
886
+			array('id' => false, 'text' => esc_html__('No', 'event_espresso')),
887
+		);
888
+		$default_reg_status_values                        = EEM_Registration::reg_status_array(
889
+			array(
890
+				EEM_Registration::status_id_cancelled,
891
+				EEM_Registration::status_id_declined,
892
+				EEM_Registration::status_id_incomplete,
893
+				EEM_Registration::status_id_wait_list,
894
+			),
895
+			true
896
+		);
897
+		$template_args['active_status']                   = $this->_cpt_model_obj->pretty_active_status(false);
898
+		$template_args['_event']                          = $this->_cpt_model_obj;
899
+		$template_args['additional_limit']                = $this->_cpt_model_obj->additional_limit();
900
+		$template_args['default_registration_status']     = EEH_Form_Fields::select_input(
901
+			'default_reg_status',
902
+			$default_reg_status_values,
903
+			$this->_cpt_model_obj->default_registration_status()
904
+		);
905
+		$template_args['display_description']             = EEH_Form_Fields::select_input(
906
+			'display_desc',
907
+			$yes_no_values,
908
+			$this->_cpt_model_obj->display_description()
909
+		);
910
+		$template_args['display_ticket_selector']         = EEH_Form_Fields::select_input(
911
+			'display_ticket_selector',
912
+			$yes_no_values,
913
+			$this->_cpt_model_obj->display_ticket_selector(),
914
+			'',
915
+			'',
916
+			false
917
+		);
918
+		$template_args['EVT_default_registration_status'] = EEH_Form_Fields::select_input(
919
+			'EVT_default_registration_status',
920
+			$default_reg_status_values,
921
+			$this->_cpt_model_obj->default_registration_status()
922
+		);
923
+		$template_args['additional_registration_options'] = apply_filters(
924
+			'FHEE__Events_Admin_Page__registration_options_meta_box__additional_registration_options',
925
+			'',
926
+			$template_args,
927
+			$yes_no_values,
928
+			$default_reg_status_values
929
+		);
930
+		EEH_Template::display_template(
931
+			EVENTS_CAF_TEMPLATE_PATH . 'event_registration_options.template.php',
932
+			$template_args
933
+		);
934
+	}
935
+
936
+
937
+
938
+	/**
939
+	 * wp_list_table_mods for caf
940
+	 * ============================
941
+	 */
942
+	/**
943
+	 * hook into list table filters and provide filters for caffeinated list table
944
+	 *
945
+	 * @param  array $old_filters    any existing filters present
946
+	 * @param  array $list_table_obj the list table object
947
+	 * @return array                  new filters
948
+	 */
949
+	public function list_table_filters($old_filters, $list_table_obj)
950
+	{
951
+		$filters = array();
952
+		//first month/year filters
953
+		$filters[] = $this->espresso_event_months_dropdown();
954
+		$status    = isset($this->_req_data['status']) ? $this->_req_data['status'] : null;
955
+		//active status dropdown
956
+		if ($status !== 'draft') {
957
+			$filters[] = $this->active_status_dropdown(
958
+				isset($this->_req_data['active_status']) ? $this->_req_data['active_status'] : ''
959
+			);
960
+		}
961
+		//category filter
962
+		$filters[] = $this->category_dropdown();
963
+		return array_merge($old_filters, $filters);
964
+	}
965
+
966
+
967
+	/**
968
+	 * espresso_event_months_dropdown
969
+	 *
970
+	 * @access public
971
+	 * @return string                dropdown listing month/year selections for events.
972
+	 */
973
+	public function espresso_event_months_dropdown()
974
+	{
975
+		// what we need to do is get all PRIMARY datetimes for all events to filter on.
976
+		// Note we need to include any other filters that are set!
977
+		$status = isset($this->_req_data['status']) ? $this->_req_data['status'] : null;
978
+		//categories?
979
+		$category = isset($this->_req_data['EVT_CAT']) && $this->_req_data['EVT_CAT'] > 0
980
+			? $this->_req_data['EVT_CAT']
981
+			: null;
982
+		//active status?
983
+		$active_status = isset($this->_req_data['active_status']) ? $this->_req_data['active_status'] : null;
984
+		$cur_date      = isset($this->_req_data['month_range']) ? $this->_req_data['month_range'] : '';
985
+		return EEH_Form_Fields::generate_event_months_dropdown($cur_date, $status, $category, $active_status);
986
+	}
987
+
988
+
989
+	/**
990
+	 * returns a list of "active" statuses on the event
991
+	 *
992
+	 * @param  string $current_value whatever the current active status is
993
+	 * @return string
994
+	 */
995
+	public function active_status_dropdown($current_value = '')
996
+	{
997
+		$select_name = 'active_status';
998
+		$values      = array(
999
+			'none'     => esc_html__('Show Active/Inactive', 'event_espresso'),
1000
+			'active'   => esc_html__('Active', 'event_espresso'),
1001
+			'upcoming' => esc_html__('Upcoming', 'event_espresso'),
1002
+			'expired'  => esc_html__('Expired', 'event_espresso'),
1003
+			'inactive' => esc_html__('Inactive', 'event_espresso'),
1004
+		);
1005
+		$id          = 'id="espresso-active-status-dropdown-filter"';
1006
+		$class       = 'wide';
1007
+		return EEH_Form_Fields::select_input($select_name, $values, $current_value, $id, $class);
1008
+	}
1009
+
1010
+
1011
+	/**
1012
+	 * output a dropdown of the categories for the category filter on the event admin list table
1013
+	 *
1014
+	 * @access  public
1015
+	 * @return string html
1016
+	 */
1017
+	public function category_dropdown()
1018
+	{
1019
+		$cur_cat = isset($this->_req_data['EVT_CAT']) ? $this->_req_data['EVT_CAT'] : -1;
1020
+		return EEH_Form_Fields::generate_event_category_dropdown($cur_cat);
1021
+	}
1022
+
1023
+
1024
+	/**
1025
+	 * get total number of events today
1026
+	 *
1027
+	 * @access public
1028
+	 * @return int
1029
+	 * @throws EE_Error
1030
+	 */
1031
+	public function total_events_today()
1032
+	{
1033
+		$start = EEM_Datetime::instance()->convert_datetime_for_query(
1034
+			'DTT_EVT_start',
1035
+			date('Y-m-d') . ' 00:00:00',
1036
+			'Y-m-d H:i:s',
1037
+			'UTC'
1038
+		);
1039
+		$end   = EEM_Datetime::instance()->convert_datetime_for_query(
1040
+			'DTT_EVT_start',
1041
+			date('Y-m-d') . ' 23:59:59',
1042
+			'Y-m-d H:i:s',
1043
+			'UTC'
1044
+		);
1045
+		$where = array(
1046
+			'Datetime.DTT_EVT_start' => array('BETWEEN', array($start, $end)),
1047
+		);
1048
+		$count = EEM_Event::instance()->count(array($where, 'caps' => 'read_admin'), 'EVT_ID', true);
1049
+		return $count;
1050
+	}
1051
+
1052
+
1053
+	/**
1054
+	 * get total number of events this month
1055
+	 *
1056
+	 * @access public
1057
+	 * @return int
1058
+	 * @throws EE_Error
1059
+	 */
1060
+	public function total_events_this_month()
1061
+	{
1062
+		//Dates
1063
+		$this_year_r     = date('Y');
1064
+		$this_month_r    = date('m');
1065
+		$days_this_month = date('t');
1066
+		$start           = EEM_Datetime::instance()->convert_datetime_for_query(
1067
+			'DTT_EVT_start',
1068
+			$this_year_r . '-' . $this_month_r . '-01 00:00:00',
1069
+			'Y-m-d H:i:s',
1070
+			'UTC'
1071
+		);
1072
+		$end             = EEM_Datetime::instance()->convert_datetime_for_query(
1073
+			'DTT_EVT_start',
1074
+			$this_year_r . '-' . $this_month_r . '-' . $days_this_month . ' 23:59:59',
1075
+			'Y-m-d H:i:s',
1076
+			'UTC'
1077
+		);
1078
+		$where           = array(
1079
+			'Datetime.DTT_EVT_start' => array('BETWEEN', array($start, $end)),
1080
+		);
1081
+		$count           = EEM_Event::instance()->count(array($where, 'caps' => 'read_admin'), 'EVT_ID', true);
1082
+		return $count;
1083
+	}
1084
+
1085
+
1086
+	/** DEFAULT TICKETS STUFF **/
1087
+
1088
+	/**
1089
+	 * Output default tickets list table view.
1090
+	 */
1091
+	public function _tickets_overview_list_table()
1092
+	{
1093
+		$this->_search_btn_label = esc_html__('Tickets', 'event_espresso');
1094
+		$this->display_admin_list_table_page_with_no_sidebar();
1095
+	}
1096
+
1097
+
1098
+	/**
1099
+	 * @param int  $per_page
1100
+	 * @param bool $count
1101
+	 * @param bool $trashed
1102
+	 * @return \EE_Soft_Delete_Base_Class[]|int
1103
+	 */
1104
+	public function get_default_tickets($per_page = 10, $count = false, $trashed = false)
1105
+	{
1106
+		$orderby = empty($this->_req_data['orderby']) ? 'TKT_name' : $this->_req_data['orderby'];
1107
+		$order   = empty($this->_req_data['order']) ? 'ASC' : $this->_req_data['order'];
1108
+		switch ($orderby) {
1109
+			case 'TKT_name':
1110
+				$orderby = array('TKT_name' => $order);
1111
+				break;
1112
+			case 'TKT_price':
1113
+				$orderby = array('TKT_price' => $order);
1114
+				break;
1115
+			case 'TKT_uses':
1116
+				$orderby = array('TKT_uses' => $order);
1117
+				break;
1118
+			case 'TKT_min':
1119
+				$orderby = array('TKT_min' => $order);
1120
+				break;
1121
+			case 'TKT_max':
1122
+				$orderby = array('TKT_max' => $order);
1123
+				break;
1124
+			case 'TKT_qty':
1125
+				$orderby = array('TKT_qty' => $order);
1126
+				break;
1127
+		}
1128
+		$current_page = isset($this->_req_data['paged']) && ! empty($this->_req_data['paged'])
1129
+			? $this->_req_data['paged']
1130
+			: 1;
1131
+		$per_page     = isset($this->_req_data['perpage']) && ! empty($this->_req_data['perpage'])
1132
+			? $this->_req_data['perpage']
1133
+			: $per_page;
1134
+		$_where       = array(
1135
+			'TKT_is_default' => 1,
1136
+			'TKT_deleted'    => $trashed,
1137
+		);
1138
+		$offset       = ($current_page - 1) * $per_page;
1139
+		$limit        = array($offset, $per_page);
1140
+		if (isset($this->_req_data['s'])) {
1141
+			$sstr         = '%' . $this->_req_data['s'] . '%';
1142
+			$_where['OR'] = array(
1143
+				'TKT_name'        => array('LIKE', $sstr),
1144
+				'TKT_description' => array('LIKE', $sstr),
1145
+			);
1146
+		}
1147
+		$query_params = array(
1148
+			$_where,
1149
+			'order_by' => $orderby,
1150
+			'limit'    => $limit,
1151
+			'group_by' => 'TKT_ID',
1152
+		);
1153
+		if ($count) {
1154
+			return EEM_Ticket::instance()->count_deleted_and_undeleted(array($_where));
1155
+		} else {
1156
+			return EEM_Ticket::instance()->get_all_deleted_and_undeleted($query_params);
1157
+		}
1158
+	}
1159
+
1160
+
1161
+	/**
1162
+	 * @param bool $trash
1163
+	 * @throws EE_Error
1164
+	 */
1165
+	protected function _trash_or_restore_ticket($trash = false)
1166
+	{
1167
+		$success = 1;
1168
+		$TKT     = EEM_Ticket::instance();
1169
+		//checkboxes?
1170
+		if (! empty($this->_req_data['checkbox']) && is_array($this->_req_data['checkbox'])) {
1171
+			//if array has more than one element then success message should be plural
1172
+			$success = count($this->_req_data['checkbox']) > 1 ? 2 : 1;
1173
+			//cycle thru the boxes
1174
+			while (list($TKT_ID, $value) = each($this->_req_data['checkbox'])) {
1175
+				if ($trash) {
1176
+					if (! $TKT->delete_by_ID($TKT_ID)) {
1177
+						$success = 0;
1178
+					}
1179
+				} else {
1180
+					if (! $TKT->restore_by_ID($TKT_ID)) {
1181
+						$success = 0;
1182
+					}
1183
+				}
1184
+			}
1185
+		} else {
1186
+			//grab single id and trash
1187
+			$TKT_ID = absint($this->_req_data['TKT_ID']);
1188
+			if ($trash) {
1189
+				if (! $TKT->delete_by_ID($TKT_ID)) {
1190
+					$success = 0;
1191
+				}
1192
+			} else {
1193
+				if (! $TKT->restore_by_ID($TKT_ID)) {
1194
+					$success = 0;
1195
+				}
1196
+			}
1197
+		}
1198
+		$action_desc = $trash ? 'moved to the trash' : 'restored';
1199
+		$query_args  = array(
1200
+			'action' => 'ticket_list_table',
1201
+			'status' => $trash ? '' : 'trashed',
1202
+		);
1203
+		$this->_redirect_after_action($success, 'Tickets', $action_desc, $query_args);
1204
+	}
1205
+
1206
+
1207
+	/**
1208
+	 * Handles trashing default ticket.
1209
+	 */
1210
+	protected function _delete_ticket()
1211
+	{
1212
+		$success = 1;
1213
+		//checkboxes?
1214
+		if (! empty($this->_req_data['checkbox']) && is_array($this->_req_data['checkbox'])) {
1215
+			//if array has more than one element then success message should be plural
1216
+			$success = count($this->_req_data['checkbox']) > 1 ? 2 : 1;
1217
+			//cycle thru the boxes
1218
+			while (list($TKT_ID, $value) = each($this->_req_data['checkbox'])) {
1219
+				//delete
1220
+				if (! $this->_delete_the_ticket($TKT_ID)) {
1221
+					$success = 0;
1222
+				}
1223
+			}
1224
+		} else {
1225
+			//grab single id and trash
1226
+			$TKT_ID = absint($this->_req_data['TKT_ID']);
1227
+			if (! $this->_delete_the_ticket($TKT_ID)) {
1228
+				$success = 0;
1229
+			}
1230
+		}
1231
+		$action_desc = 'deleted';
1232
+		$query_args  = array(
1233
+			'action' => 'ticket_list_table',
1234
+			'status' => 'trashed',
1235
+		);
1236
+		//fail safe.  If the default ticket count === 1 then we need to redirect to event overview.
1237
+		if (EEM_Ticket::instance()->count_deleted_and_undeleted(
1238
+			array(array('TKT_is_default' => 1)),
1239
+			'TKT_ID',
1240
+			true
1241
+		)
1242
+		) {
1243
+			$query_args = array();
1244
+		}
1245
+		$this->_redirect_after_action($success, 'Tickets', $action_desc, $query_args);
1246
+	}
1247
+
1248
+
1249
+	/**
1250
+	 * @param int $TKT_ID
1251
+	 * @return bool|int
1252
+	 * @throws EE_Error
1253
+	 */
1254
+	protected function _delete_the_ticket($TKT_ID)
1255
+	{
1256
+		$tkt = EEM_Ticket::instance()->get_one_by_ID($TKT_ID);
1257
+		$tkt->_remove_relations('Datetime');
1258
+		//delete all related prices first
1259
+		$tkt->delete_related_permanently('Price');
1260
+		return $tkt->delete_permanently();
1261
+	}
1262 1262
 }
Please login to merge, or discard this patch.
core/libraries/messages/messenger/EE_Email_messenger.class.php 3 patches
Doc Comments   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -456,7 +456,7 @@
 block discarded – undo
456 456
      * be empty
457 457
      *
458 458
      * @since 4.3.1
459
-     * @return array
459
+     * @return string[]
460 460
      */
461 461
     private function _parse_from()
462 462
     {
Please login to merge, or discard this patch.
Indentation   +543 added lines, -543 removed lines patch added patch discarded remove patch
@@ -1,7 +1,7 @@  discard block
 block discarded – undo
1 1
 <?php
2 2
 
3 3
 if (! defined('EVENT_ESPRESSO_VERSION')) {
4
-    exit('NO direct script access allowed');
4
+	exit('NO direct script access allowed');
5 5
 }
6 6
 
7 7
 /**
@@ -28,548 +28,548 @@  discard block
 block discarded – undo
28 28
 class EE_Email_messenger extends EE_messenger
29 29
 {
30 30
 
31
-    /**
32
-     * The following are the properties that email requires for the message going out.
33
-     */
34
-    protected $_to;
35
-    protected $_from;
36
-    protected $_subject;
37
-    protected $_content;
38
-
39
-
40
-    /**
41
-     * constructor
42
-     *
43
-     * @access public
44
-     */
45
-    public function __construct()
46
-    {
47
-        //set name and description properties
48
-        $this->name                = 'email';
49
-        $this->description         = __('This messenger delivers messages via email using the built-in <code>wp_mail</code> function included with WordPress',
50
-            'event_espresso');
51
-        $this->label               = array(
52
-            'singular' => __('email', 'event_espresso'),
53
-            'plural'   => __('emails', 'event_espresso'),
54
-        );
55
-        $this->activate_on_install = true;
56
-
57
-        //we're using defaults so let's call parent constructor that will take care of setting up all the other properties
58
-        parent::__construct();
59
-    }
60
-
61
-
62
-    /**
63
-     * see abstract declaration in parent class for details.
64
-     */
65
-    protected function _set_admin_pages()
66
-    {
67
-        $this->admin_registered_pages = array(
68
-            'events_edit' => true,
69
-        );
70
-    }
71
-
72
-
73
-    /**
74
-     * see abstract declaration in parent class for details
75
-     */
76
-    protected function _set_valid_shortcodes()
77
-    {
78
-        //remember by leaving the other fields not set, those fields will inherit the valid shortcodes from the message type.
79
-        $this->_valid_shortcodes = array(
80
-            'to'   => array('email', 'event_author', 'primary_registration_details', 'recipient_details'),
81
-            'from' => array('email', 'event_author', 'primary_registration_details', 'recipient_details'),
82
-        );
83
-    }
84
-
85
-
86
-    /**
87
-     * see abstract declaration in parent class for details
88
-     *
89
-     * @access protected
90
-     * @return void
91
-     */
92
-    protected function _set_validator_config()
93
-    {
94
-        $valid_shortcodes = $this->get_valid_shortcodes();
95
-
96
-        $this->_validator_config = array(
97
-            'to'            => array(
98
-                'shortcodes' => $valid_shortcodes['to'],
99
-                'type'       => 'email',
100
-            ),
101
-            'from'          => array(
102
-                'shortcodes' => $valid_shortcodes['from'],
103
-                'type'       => 'email',
104
-            ),
105
-            'subject'       => array(
106
-                'shortcodes' => array(
107
-                    'organization',
108
-                    'primary_registration_details',
109
-                    'event_author',
110
-                    'primary_registration_details',
111
-                    'recipient_details',
112
-                ),
113
-            ),
114
-            'content'       => array(
115
-                'shortcodes' => array(
116
-                    'event_list',
117
-                    'attendee_list',
118
-                    'ticket_list',
119
-                    'organization',
120
-                    'primary_registration_details',
121
-                    'primary_registration_list',
122
-                    'event_author',
123
-                    'recipient_details',
124
-                    'recipient_list',
125
-                    'transaction',
126
-                    'messenger',
127
-                ),
128
-            ),
129
-            'attendee_list' => array(
130
-                'shortcodes' => array('attendee', 'event_list', 'ticket_list'),
131
-                'required'   => array('[ATTENDEE_LIST]'),
132
-            ),
133
-            'event_list'    => array(
134
-                'shortcodes' => array(
135
-                    'event',
136
-                    'attendee_list',
137
-                    'ticket_list',
138
-                    'venue',
139
-                    'datetime_list',
140
-                    'attendee',
141
-                    'primary_registration_details',
142
-                    'primary_registration_list',
143
-                    'event_author',
144
-                    'recipient_details',
145
-                    'recipient_list',
146
-                ),
147
-                'required'   => array('[EVENT_LIST]'),
148
-            ),
149
-            'ticket_list'   => array(
150
-                'shortcodes' => array(
151
-                    'event_list',
152
-                    'attendee_list',
153
-                    'ticket',
154
-                    'datetime_list',
155
-                    'primary_registration_details',
156
-                    'recipient_details',
157
-                ),
158
-                'required'   => array('[TICKET_LIST]'),
159
-            ),
160
-            'datetime_list' => array(
161
-                'shortcodes' => array('datetime'),
162
-                'required'   => array('[DATETIME_LIST]'),
163
-            ),
164
-        );
165
-    }
166
-
167
-
168
-    /**
169
-     * @see   parent EE_messenger class for docs
170
-     * @since 4.5.0
171
-     */
172
-    public function do_secondary_messenger_hooks($sending_messenger_name)
173
-    {
174
-        if ($sending_messenger_name = 'html') {
175
-            add_filter('FHEE__EE_Messages_Template_Pack__get_variation', array($this, 'add_email_css'), 10, 8);
176
-        }
177
-    }
178
-
179
-
180
-    public function add_email_css(
181
-        $variation_path,
182
-        $messenger,
183
-        $message_type,
184
-        $type,
185
-        $variation,
186
-        $file_extension,
187
-        $url,
188
-        EE_Messages_Template_Pack $template_pack
189
-    ) {
190
-        //prevent recursion on this callback.
191
-        remove_filter('FHEE__EE_Messages_Template_Pack__get_variation', array($this, 'add_email_css'), 10);
192
-        $variation = $this->get_variation($template_pack, $message_type, $url, 'main', $variation, false);
193
-
194
-        add_filter('FHEE__EE_Messages_Template_Pack__get_variation', array($this, 'add_email_css'), 10, 8);
195
-        return $variation;
196
-    }
197
-
198
-
199
-    /**
200
-     * See parent for details
201
-     *
202
-     * @access protected
203
-     * @return void
204
-     */
205
-    protected function _set_test_settings_fields()
206
-    {
207
-        $this->_test_settings_fields = array(
208
-            'to'      => array(
209
-                'input'      => 'text',
210
-                'label'      => __('Send a test email to', 'event_espresso'),
211
-                'type'       => 'email',
212
-                'required'   => true,
213
-                'validation' => true,
214
-                'css_class'  => 'large-text',
215
-                'format'     => '%s',
216
-                'default'    => get_bloginfo('admin_email'),
217
-            ),
218
-            'subject' => array(
219
-                'input'      => 'hidden',
220
-                'label'      => '',
221
-                'type'       => 'string',
222
-                'required'   => false,
223
-                'validation' => false,
224
-                'format'     => '%s',
225
-                'value'      => sprintf(__('Test email sent from %s', 'event_espresso'), get_bloginfo('name')),
226
-                'default'    => '',
227
-                'css_class'  => '',
228
-            ),
229
-        );
230
-    }
231
-
232
-
233
-    /**
234
-     * _set_template_fields
235
-     * This sets up the fields that a messenger requires for the message to go out.
236
-     *
237
-     * @access  protected
238
-     * @return void
239
-     */
240
-    protected function _set_template_fields()
241
-    {
242
-        // any extra template fields that are NOT used by the messenger but will get used by a messenger field for shortcode replacement get added to the 'extra' key in an associated array indexed by the messenger field they relate to.  This is important for the Messages_admin to know what fields to display to the user.  Also, notice that the "values" are equal to the field type that messages admin will use to know what kind of field to display. The values ALSO have one index labeled "shortcode".  the values in that array indicate which ACTUAL SHORTCODE (i.e. [SHORTCODE]) is required in order for this extra field to be displayed.  If the required shortcode isn't part of the shortcodes array then the field is not needed and will not be displayed/parsed.
243
-        $this->_template_fields = array(
244
-            'to'      => array(
245
-                'input'      => 'text',
246
-                'label'      => __('To', 'event_espresso'),
247
-                'type'       => 'string',
248
-                'required'   => true,
249
-                'validation' => true,
250
-                'css_class'  => 'large-text',
251
-                'format'     => '%s',
252
-            ),
253
-            'from'    => array(
254
-                'input'      => 'text',
255
-                'label'      => __('From', 'event_espresso'),
256
-                'type'       => 'string',
257
-                'required'   => true,
258
-                'validation' => true,
259
-                'css_class'  => 'large-text',
260
-                'format'     => '%s',
261
-            ),
262
-            'subject' => array(
263
-                'input'      => 'text',
264
-                'label'      => __('Subject', 'event_espresso'),
265
-                'type'       => 'string',
266
-                'required'   => true,
267
-                'validation' => true,
268
-                'css_class'  => 'large-text',
269
-                'format'     => '%s',
270
-            ),
271
-            'content' => '',
272
-            //left empty b/c it is in the "extra array" but messenger still needs needs to know this is a field.
273
-            'extra'   => array(
274
-                'content' => array(
275
-                    'main'          => array(
276
-                        'input'      => 'wp_editor',
277
-                        'label'      => __('Main Content', 'event_espresso'),
278
-                        'type'       => 'string',
279
-                        'required'   => true,
280
-                        'validation' => true,
281
-                        'format'     => '%s',
282
-                        'rows'       => '15',
283
-                    ),
284
-                    'event_list'    => array(
285
-                        'input'               => 'wp_editor',
286
-                        'label'               => '[EVENT_LIST]',
287
-                        'type'                => 'string',
288
-                        'required'            => true,
289
-                        'validation'          => true,
290
-                        'format'              => '%s',
291
-                        'rows'                => '15',
292
-                        'shortcodes_required' => array('[EVENT_LIST]'),
293
-                    ),
294
-                    'attendee_list' => array(
295
-                        'input'               => 'textarea',
296
-                        'label'               => '[ATTENDEE_LIST]',
297
-                        'type'                => 'string',
298
-                        'required'            => true,
299
-                        'validation'          => true,
300
-                        'format'              => '%s',
301
-                        'css_class'           => 'large-text',
302
-                        'rows'                => '5',
303
-                        'shortcodes_required' => array('[ATTENDEE_LIST]'),
304
-                    ),
305
-                    'ticket_list'   => array(
306
-                        'input'               => 'textarea',
307
-                        'label'               => '[TICKET_LIST]',
308
-                        'type'                => 'string',
309
-                        'required'            => true,
310
-                        'validation'          => true,
311
-                        'format'              => '%s',
312
-                        'css_class'           => 'large-text',
313
-                        'rows'                => '10',
314
-                        'shortcodes_required' => array('[TICKET_LIST]'),
315
-                    ),
316
-                    'datetime_list' => array(
317
-                        'input'               => 'textarea',
318
-                        'label'               => '[DATETIME_LIST]',
319
-                        'type'                => 'string',
320
-                        'required'            => true,
321
-                        'validation'          => true,
322
-                        'format'              => '%s',
323
-                        'css_class'           => 'large-text',
324
-                        'rows'                => '10',
325
-                        'shortcodes_required' => array('[DATETIME_LIST]'),
326
-                    ),
327
-                ),
328
-            ),
329
-        );
330
-    }
331
-
332
-
333
-    /**
334
-     * See definition of this class in parent
335
-     */
336
-    protected function _set_default_message_types()
337
-    {
338
-        $this->_default_message_types = array(
339
-            'payment',
340
-            'payment_refund',
341
-            'registration',
342
-            'not_approved_registration',
343
-            'pending_approval',
344
-        );
345
-    }
346
-
347
-
348
-    /**
349
-     * @see   definition of this class in parent
350
-     * @since 4.5.0
351
-     */
352
-    protected function _set_valid_message_types()
353
-    {
354
-        $this->_valid_message_types = array(
355
-            'payment',
356
-            'registration',
357
-            'not_approved_registration',
358
-            'declined_registration',
359
-            'cancelled_registration',
360
-            'pending_approval',
361
-            'registration_summary',
362
-            'payment_reminder',
363
-            'payment_declined',
364
-            'payment_refund',
365
-        );
366
-    }
367
-
368
-
369
-    /**
370
-     * setting up admin_settings_fields for messenger.
371
-     */
372
-    protected function _set_admin_settings_fields()
373
-    {
374
-    }
375
-
376
-    /**
377
-     * We just deliver the messages don't kill us!!
378
-     *
379
-     * @return bool | WP_Error  true if message delivered, false if it didn't deliver OR bubble up any error object if
380
-     *              present.
381
-     */
382
-    protected function _send_message()
383
-    {
384
-        $success = wp_mail(
385
-            html_entity_decode($this->_to, ENT_QUOTES, "UTF-8"),
386
-            stripslashes(html_entity_decode($this->_subject, ENT_QUOTES, "UTF-8")),
387
-            $this->_body(),
388
-            $this->_headers()
389
-        );
390
-        if (! $success) {
391
-            EE_Error::add_error(
392
-                sprintf(
393
-                    __('The email did not send successfully.%3$sThe WordPress wp_mail function is used for sending mails but does not give any useful information when an email fails to send.%3$sIt is possible the "to" address (%1$s) or "from" address (%2$s) is invalid.%3$s',
394
-                        'event_espresso'),
395
-                    $this->_to,
396
-                    $this->_from,
397
-                    '<br />'
398
-                ),
399
-                __FILE__, __FUNCTION__, __LINE__
400
-            );
401
-        }
402
-        return $success;
403
-    }
404
-
405
-
406
-    /**
407
-     * see parent for definition
408
-     *
409
-     * @return string html body of the message content and the related css.
410
-     */
411
-    protected function _preview()
412
-    {
413
-        return $this->_body(true);
414
-    }
415
-
416
-
417
-    /**
418
-     * Setup headers for email
419
-     *
420
-     * @access protected
421
-     * @return string formatted header for email
422
-     */
423
-    protected function _headers()
424
-    {
425
-        $this->_ensure_has_from_email_address();
426
-        $from    = stripslashes_deep(html_entity_decode($this->_from, ENT_QUOTES, "UTF-8"));
427
-        $headers = array(
428
-            'MIME-Version: 1.0',
429
-            'From:' . $from,
430
-            'Reply-To:' . $from,
431
-            'Content-Type:text/html; charset=utf-8',
432
-        );
433
-
434
-        //but wait!  Header's for the from is NOT reliable because some plugins don't respect From: as set in the header.
435
-        add_filter('wp_mail_from', array($this, 'set_from_address'), 100);
436
-        add_filter('wp_mail_from_name', array($this, 'set_from_name'), 100);
437
-        return apply_filters('FHEE__EE_Email_messenger___headers', $headers, $this->_incoming_message_type, $this);
438
-    }
439
-
440
-
441
-    /**
442
-     * This simply ensures that the from address is not empty.  If it is, then we use whatever is set as the site email
443
-     * address for the from address to avoid problems with sending emails.
444
-     */
445
-    protected function _ensure_has_from_email_address()
446
-    {
447
-        if (empty($this->_from)) {
448
-            $this->_from = get_bloginfo('admin_email');
449
-        }
450
-    }
451
-
452
-
453
-    /**
454
-     * This simply parses whatever is set as the $_from address and determines if it is in the format {name} <{email}>
455
-     * or just {email} and returns an array with the "from_name" and "from_email" as the values. Note from_name *MAY*
456
-     * be empty
457
-     *
458
-     * @since 4.3.1
459
-     * @return array
460
-     */
461
-    private function _parse_from()
462
-    {
463
-        if (strpos($this->_from, '<') !== false) {
464
-            $from_name = substr($this->_from, 0, strpos($this->_from, '<') - 1);
465
-            $from_name = str_replace('"', '', $from_name);
466
-            $from_name = trim($from_name);
467
-
468
-            $from_email = substr($this->_from, strpos($this->_from, '<') + 1);
469
-            $from_email = str_replace('>', '', $from_email);
470
-            $from_email = trim($from_email);
471
-        } elseif (trim($this->_from) !== '') {
472
-            $from_name  = '';
473
-            $from_email = trim($this->_from);
474
-        } else {
475
-            $from_name = $from_email = '';
476
-        }
477
-        return array($from_name, $from_email);
478
-    }
479
-
480
-
481
-    /**
482
-     * Callback for the wp_mail_from filter.
483
-     *
484
-     * @since 4.3.1
485
-     * @param string $from_email What the original from_email is.
486
-     */
487
-    public function set_from_address($from_email)
488
-    {
489
-        $parsed_from = $this->_parse_from();
490
-        //includes fallback if the parsing failed.
491
-        $from_email = is_array($parsed_from) && ! empty($parsed_from[1]) ? $parsed_from[1] : get_bloginfo('admin_email');
492
-        return $from_email;
493
-    }
494
-
495
-
496
-    /**
497
-     * Callback fro the wp_mail_from_name filter.
498
-     *
499
-     * @since 4.3.1
500
-     * @param string $from_name The original from_name.
501
-     */
502
-    public function set_from_name($from_name)
503
-    {
504
-        $parsed_from = $this->_parse_from();
505
-        if (is_array($parsed_from) && ! empty($parsed_from[0])) {
506
-            $from_name = $parsed_from[0];
507
-        }
508
-
509
-        //if from name is "WordPress" let's sub in the site name instead (more friendly!)
510
-        $from_name = $from_name == 'WordPress' ? get_bloginfo() : $from_name;
511
-
512
-        return stripslashes_deep(html_entity_decode($from_name, ENT_QUOTES, "UTF-8"));
513
-    }
514
-
515
-
516
-    /**
517
-     * setup body for email
518
-     *
519
-     * @param bool $preview will determine whether this is preview template or not.
520
-     * @return string formatted body for email.
521
-     */
522
-    protected function _body($preview = false)
523
-    {
524
-        //setup template args!
525
-        $this->_template_args = array(
526
-            'subject'   => $this->_subject,
527
-            'from'      => $this->_from,
528
-            'main_body' => wpautop(stripslashes_deep(html_entity_decode($this->_content, ENT_QUOTES, "UTF-8"))),
529
-        );
530
-        $body                 = $this->_get_main_template($preview);
531
-
532
-        /**
533
-         * This filter allows one to bypass the CSSToInlineStyles tool and leave the body untouched.
534
-         *
535
-         * @type    bool $preview Indicates whether a preview is being generated or not.
536
-         * @return  bool    true  indicates to use the inliner, false bypasses it.
537
-         */
538
-        if (apply_filters('FHEE__EE_Email_messenger__apply_CSSInliner ', true, $preview)) {
539
-
540
-            //require CssToInlineStyles library and its dependencies via composer autoloader
541
-            require_once EE_THIRD_PARTY . 'cssinliner/vendor/autoload.php';
542
-
543
-            //now if this isn't a preview, let's setup the body so it has inline styles
544
-            if (! $preview || ($preview && defined('DOING_AJAX'))) {
545
-                $style = file_get_contents($this->get_variation($this->_tmp_pack, $this->_incoming_message_type->name,
546
-                    false, 'main', $this->_variation), true);
547
-                $CSS   = new TijsVerkoyen\CssToInlineStyles\CssToInlineStyles($body, $style);
548
-                $body  = ltrim($CSS->convert(true),
549
-                    ">\n"); //for some reason the library has a bracket and new line at the beginning.  This takes care of that.
550
-                $body  = ltrim($body, "<?"); //see https://events.codebasehq.com/projects/event-espresso/tickets/8609
551
-            }
552
-
553
-        }
554
-        return $body;
555
-    }
556
-
557
-
558
-    /**
559
-     * This just returns any existing test settings that might be saved in the database
560
-     *
561
-     * @access public
562
-     * @return array
563
-     */
564
-    public function get_existing_test_settings()
565
-    {
566
-        $settings = parent::get_existing_test_settings();
567
-        //override subject if present because we always want it to be fresh.
568
-        if (is_array($settings) && ! empty($settings['subject'])) {
569
-            $settings['subject'] = sprintf(__('Test email sent from %s', 'event_espresso'), get_bloginfo('name'));
570
-        }
571
-        return $settings;
572
-    }
31
+	/**
32
+	 * The following are the properties that email requires for the message going out.
33
+	 */
34
+	protected $_to;
35
+	protected $_from;
36
+	protected $_subject;
37
+	protected $_content;
38
+
39
+
40
+	/**
41
+	 * constructor
42
+	 *
43
+	 * @access public
44
+	 */
45
+	public function __construct()
46
+	{
47
+		//set name and description properties
48
+		$this->name                = 'email';
49
+		$this->description         = __('This messenger delivers messages via email using the built-in <code>wp_mail</code> function included with WordPress',
50
+			'event_espresso');
51
+		$this->label               = array(
52
+			'singular' => __('email', 'event_espresso'),
53
+			'plural'   => __('emails', 'event_espresso'),
54
+		);
55
+		$this->activate_on_install = true;
56
+
57
+		//we're using defaults so let's call parent constructor that will take care of setting up all the other properties
58
+		parent::__construct();
59
+	}
60
+
61
+
62
+	/**
63
+	 * see abstract declaration in parent class for details.
64
+	 */
65
+	protected function _set_admin_pages()
66
+	{
67
+		$this->admin_registered_pages = array(
68
+			'events_edit' => true,
69
+		);
70
+	}
71
+
72
+
73
+	/**
74
+	 * see abstract declaration in parent class for details
75
+	 */
76
+	protected function _set_valid_shortcodes()
77
+	{
78
+		//remember by leaving the other fields not set, those fields will inherit the valid shortcodes from the message type.
79
+		$this->_valid_shortcodes = array(
80
+			'to'   => array('email', 'event_author', 'primary_registration_details', 'recipient_details'),
81
+			'from' => array('email', 'event_author', 'primary_registration_details', 'recipient_details'),
82
+		);
83
+	}
84
+
85
+
86
+	/**
87
+	 * see abstract declaration in parent class for details
88
+	 *
89
+	 * @access protected
90
+	 * @return void
91
+	 */
92
+	protected function _set_validator_config()
93
+	{
94
+		$valid_shortcodes = $this->get_valid_shortcodes();
95
+
96
+		$this->_validator_config = array(
97
+			'to'            => array(
98
+				'shortcodes' => $valid_shortcodes['to'],
99
+				'type'       => 'email',
100
+			),
101
+			'from'          => array(
102
+				'shortcodes' => $valid_shortcodes['from'],
103
+				'type'       => 'email',
104
+			),
105
+			'subject'       => array(
106
+				'shortcodes' => array(
107
+					'organization',
108
+					'primary_registration_details',
109
+					'event_author',
110
+					'primary_registration_details',
111
+					'recipient_details',
112
+				),
113
+			),
114
+			'content'       => array(
115
+				'shortcodes' => array(
116
+					'event_list',
117
+					'attendee_list',
118
+					'ticket_list',
119
+					'organization',
120
+					'primary_registration_details',
121
+					'primary_registration_list',
122
+					'event_author',
123
+					'recipient_details',
124
+					'recipient_list',
125
+					'transaction',
126
+					'messenger',
127
+				),
128
+			),
129
+			'attendee_list' => array(
130
+				'shortcodes' => array('attendee', 'event_list', 'ticket_list'),
131
+				'required'   => array('[ATTENDEE_LIST]'),
132
+			),
133
+			'event_list'    => array(
134
+				'shortcodes' => array(
135
+					'event',
136
+					'attendee_list',
137
+					'ticket_list',
138
+					'venue',
139
+					'datetime_list',
140
+					'attendee',
141
+					'primary_registration_details',
142
+					'primary_registration_list',
143
+					'event_author',
144
+					'recipient_details',
145
+					'recipient_list',
146
+				),
147
+				'required'   => array('[EVENT_LIST]'),
148
+			),
149
+			'ticket_list'   => array(
150
+				'shortcodes' => array(
151
+					'event_list',
152
+					'attendee_list',
153
+					'ticket',
154
+					'datetime_list',
155
+					'primary_registration_details',
156
+					'recipient_details',
157
+				),
158
+				'required'   => array('[TICKET_LIST]'),
159
+			),
160
+			'datetime_list' => array(
161
+				'shortcodes' => array('datetime'),
162
+				'required'   => array('[DATETIME_LIST]'),
163
+			),
164
+		);
165
+	}
166
+
167
+
168
+	/**
169
+	 * @see   parent EE_messenger class for docs
170
+	 * @since 4.5.0
171
+	 */
172
+	public function do_secondary_messenger_hooks($sending_messenger_name)
173
+	{
174
+		if ($sending_messenger_name = 'html') {
175
+			add_filter('FHEE__EE_Messages_Template_Pack__get_variation', array($this, 'add_email_css'), 10, 8);
176
+		}
177
+	}
178
+
179
+
180
+	public function add_email_css(
181
+		$variation_path,
182
+		$messenger,
183
+		$message_type,
184
+		$type,
185
+		$variation,
186
+		$file_extension,
187
+		$url,
188
+		EE_Messages_Template_Pack $template_pack
189
+	) {
190
+		//prevent recursion on this callback.
191
+		remove_filter('FHEE__EE_Messages_Template_Pack__get_variation', array($this, 'add_email_css'), 10);
192
+		$variation = $this->get_variation($template_pack, $message_type, $url, 'main', $variation, false);
193
+
194
+		add_filter('FHEE__EE_Messages_Template_Pack__get_variation', array($this, 'add_email_css'), 10, 8);
195
+		return $variation;
196
+	}
197
+
198
+
199
+	/**
200
+	 * See parent for details
201
+	 *
202
+	 * @access protected
203
+	 * @return void
204
+	 */
205
+	protected function _set_test_settings_fields()
206
+	{
207
+		$this->_test_settings_fields = array(
208
+			'to'      => array(
209
+				'input'      => 'text',
210
+				'label'      => __('Send a test email to', 'event_espresso'),
211
+				'type'       => 'email',
212
+				'required'   => true,
213
+				'validation' => true,
214
+				'css_class'  => 'large-text',
215
+				'format'     => '%s',
216
+				'default'    => get_bloginfo('admin_email'),
217
+			),
218
+			'subject' => array(
219
+				'input'      => 'hidden',
220
+				'label'      => '',
221
+				'type'       => 'string',
222
+				'required'   => false,
223
+				'validation' => false,
224
+				'format'     => '%s',
225
+				'value'      => sprintf(__('Test email sent from %s', 'event_espresso'), get_bloginfo('name')),
226
+				'default'    => '',
227
+				'css_class'  => '',
228
+			),
229
+		);
230
+	}
231
+
232
+
233
+	/**
234
+	 * _set_template_fields
235
+	 * This sets up the fields that a messenger requires for the message to go out.
236
+	 *
237
+	 * @access  protected
238
+	 * @return void
239
+	 */
240
+	protected function _set_template_fields()
241
+	{
242
+		// any extra template fields that are NOT used by the messenger but will get used by a messenger field for shortcode replacement get added to the 'extra' key in an associated array indexed by the messenger field they relate to.  This is important for the Messages_admin to know what fields to display to the user.  Also, notice that the "values" are equal to the field type that messages admin will use to know what kind of field to display. The values ALSO have one index labeled "shortcode".  the values in that array indicate which ACTUAL SHORTCODE (i.e. [SHORTCODE]) is required in order for this extra field to be displayed.  If the required shortcode isn't part of the shortcodes array then the field is not needed and will not be displayed/parsed.
243
+		$this->_template_fields = array(
244
+			'to'      => array(
245
+				'input'      => 'text',
246
+				'label'      => __('To', 'event_espresso'),
247
+				'type'       => 'string',
248
+				'required'   => true,
249
+				'validation' => true,
250
+				'css_class'  => 'large-text',
251
+				'format'     => '%s',
252
+			),
253
+			'from'    => array(
254
+				'input'      => 'text',
255
+				'label'      => __('From', 'event_espresso'),
256
+				'type'       => 'string',
257
+				'required'   => true,
258
+				'validation' => true,
259
+				'css_class'  => 'large-text',
260
+				'format'     => '%s',
261
+			),
262
+			'subject' => array(
263
+				'input'      => 'text',
264
+				'label'      => __('Subject', 'event_espresso'),
265
+				'type'       => 'string',
266
+				'required'   => true,
267
+				'validation' => true,
268
+				'css_class'  => 'large-text',
269
+				'format'     => '%s',
270
+			),
271
+			'content' => '',
272
+			//left empty b/c it is in the "extra array" but messenger still needs needs to know this is a field.
273
+			'extra'   => array(
274
+				'content' => array(
275
+					'main'          => array(
276
+						'input'      => 'wp_editor',
277
+						'label'      => __('Main Content', 'event_espresso'),
278
+						'type'       => 'string',
279
+						'required'   => true,
280
+						'validation' => true,
281
+						'format'     => '%s',
282
+						'rows'       => '15',
283
+					),
284
+					'event_list'    => array(
285
+						'input'               => 'wp_editor',
286
+						'label'               => '[EVENT_LIST]',
287
+						'type'                => 'string',
288
+						'required'            => true,
289
+						'validation'          => true,
290
+						'format'              => '%s',
291
+						'rows'                => '15',
292
+						'shortcodes_required' => array('[EVENT_LIST]'),
293
+					),
294
+					'attendee_list' => array(
295
+						'input'               => 'textarea',
296
+						'label'               => '[ATTENDEE_LIST]',
297
+						'type'                => 'string',
298
+						'required'            => true,
299
+						'validation'          => true,
300
+						'format'              => '%s',
301
+						'css_class'           => 'large-text',
302
+						'rows'                => '5',
303
+						'shortcodes_required' => array('[ATTENDEE_LIST]'),
304
+					),
305
+					'ticket_list'   => array(
306
+						'input'               => 'textarea',
307
+						'label'               => '[TICKET_LIST]',
308
+						'type'                => 'string',
309
+						'required'            => true,
310
+						'validation'          => true,
311
+						'format'              => '%s',
312
+						'css_class'           => 'large-text',
313
+						'rows'                => '10',
314
+						'shortcodes_required' => array('[TICKET_LIST]'),
315
+					),
316
+					'datetime_list' => array(
317
+						'input'               => 'textarea',
318
+						'label'               => '[DATETIME_LIST]',
319
+						'type'                => 'string',
320
+						'required'            => true,
321
+						'validation'          => true,
322
+						'format'              => '%s',
323
+						'css_class'           => 'large-text',
324
+						'rows'                => '10',
325
+						'shortcodes_required' => array('[DATETIME_LIST]'),
326
+					),
327
+				),
328
+			),
329
+		);
330
+	}
331
+
332
+
333
+	/**
334
+	 * See definition of this class in parent
335
+	 */
336
+	protected function _set_default_message_types()
337
+	{
338
+		$this->_default_message_types = array(
339
+			'payment',
340
+			'payment_refund',
341
+			'registration',
342
+			'not_approved_registration',
343
+			'pending_approval',
344
+		);
345
+	}
346
+
347
+
348
+	/**
349
+	 * @see   definition of this class in parent
350
+	 * @since 4.5.0
351
+	 */
352
+	protected function _set_valid_message_types()
353
+	{
354
+		$this->_valid_message_types = array(
355
+			'payment',
356
+			'registration',
357
+			'not_approved_registration',
358
+			'declined_registration',
359
+			'cancelled_registration',
360
+			'pending_approval',
361
+			'registration_summary',
362
+			'payment_reminder',
363
+			'payment_declined',
364
+			'payment_refund',
365
+		);
366
+	}
367
+
368
+
369
+	/**
370
+	 * setting up admin_settings_fields for messenger.
371
+	 */
372
+	protected function _set_admin_settings_fields()
373
+	{
374
+	}
375
+
376
+	/**
377
+	 * We just deliver the messages don't kill us!!
378
+	 *
379
+	 * @return bool | WP_Error  true if message delivered, false if it didn't deliver OR bubble up any error object if
380
+	 *              present.
381
+	 */
382
+	protected function _send_message()
383
+	{
384
+		$success = wp_mail(
385
+			html_entity_decode($this->_to, ENT_QUOTES, "UTF-8"),
386
+			stripslashes(html_entity_decode($this->_subject, ENT_QUOTES, "UTF-8")),
387
+			$this->_body(),
388
+			$this->_headers()
389
+		);
390
+		if (! $success) {
391
+			EE_Error::add_error(
392
+				sprintf(
393
+					__('The email did not send successfully.%3$sThe WordPress wp_mail function is used for sending mails but does not give any useful information when an email fails to send.%3$sIt is possible the "to" address (%1$s) or "from" address (%2$s) is invalid.%3$s',
394
+						'event_espresso'),
395
+					$this->_to,
396
+					$this->_from,
397
+					'<br />'
398
+				),
399
+				__FILE__, __FUNCTION__, __LINE__
400
+			);
401
+		}
402
+		return $success;
403
+	}
404
+
405
+
406
+	/**
407
+	 * see parent for definition
408
+	 *
409
+	 * @return string html body of the message content and the related css.
410
+	 */
411
+	protected function _preview()
412
+	{
413
+		return $this->_body(true);
414
+	}
415
+
416
+
417
+	/**
418
+	 * Setup headers for email
419
+	 *
420
+	 * @access protected
421
+	 * @return string formatted header for email
422
+	 */
423
+	protected function _headers()
424
+	{
425
+		$this->_ensure_has_from_email_address();
426
+		$from    = stripslashes_deep(html_entity_decode($this->_from, ENT_QUOTES, "UTF-8"));
427
+		$headers = array(
428
+			'MIME-Version: 1.0',
429
+			'From:' . $from,
430
+			'Reply-To:' . $from,
431
+			'Content-Type:text/html; charset=utf-8',
432
+		);
433
+
434
+		//but wait!  Header's for the from is NOT reliable because some plugins don't respect From: as set in the header.
435
+		add_filter('wp_mail_from', array($this, 'set_from_address'), 100);
436
+		add_filter('wp_mail_from_name', array($this, 'set_from_name'), 100);
437
+		return apply_filters('FHEE__EE_Email_messenger___headers', $headers, $this->_incoming_message_type, $this);
438
+	}
439
+
440
+
441
+	/**
442
+	 * This simply ensures that the from address is not empty.  If it is, then we use whatever is set as the site email
443
+	 * address for the from address to avoid problems with sending emails.
444
+	 */
445
+	protected function _ensure_has_from_email_address()
446
+	{
447
+		if (empty($this->_from)) {
448
+			$this->_from = get_bloginfo('admin_email');
449
+		}
450
+	}
451
+
452
+
453
+	/**
454
+	 * This simply parses whatever is set as the $_from address and determines if it is in the format {name} <{email}>
455
+	 * or just {email} and returns an array with the "from_name" and "from_email" as the values. Note from_name *MAY*
456
+	 * be empty
457
+	 *
458
+	 * @since 4.3.1
459
+	 * @return array
460
+	 */
461
+	private function _parse_from()
462
+	{
463
+		if (strpos($this->_from, '<') !== false) {
464
+			$from_name = substr($this->_from, 0, strpos($this->_from, '<') - 1);
465
+			$from_name = str_replace('"', '', $from_name);
466
+			$from_name = trim($from_name);
467
+
468
+			$from_email = substr($this->_from, strpos($this->_from, '<') + 1);
469
+			$from_email = str_replace('>', '', $from_email);
470
+			$from_email = trim($from_email);
471
+		} elseif (trim($this->_from) !== '') {
472
+			$from_name  = '';
473
+			$from_email = trim($this->_from);
474
+		} else {
475
+			$from_name = $from_email = '';
476
+		}
477
+		return array($from_name, $from_email);
478
+	}
479
+
480
+
481
+	/**
482
+	 * Callback for the wp_mail_from filter.
483
+	 *
484
+	 * @since 4.3.1
485
+	 * @param string $from_email What the original from_email is.
486
+	 */
487
+	public function set_from_address($from_email)
488
+	{
489
+		$parsed_from = $this->_parse_from();
490
+		//includes fallback if the parsing failed.
491
+		$from_email = is_array($parsed_from) && ! empty($parsed_from[1]) ? $parsed_from[1] : get_bloginfo('admin_email');
492
+		return $from_email;
493
+	}
494
+
495
+
496
+	/**
497
+	 * Callback fro the wp_mail_from_name filter.
498
+	 *
499
+	 * @since 4.3.1
500
+	 * @param string $from_name The original from_name.
501
+	 */
502
+	public function set_from_name($from_name)
503
+	{
504
+		$parsed_from = $this->_parse_from();
505
+		if (is_array($parsed_from) && ! empty($parsed_from[0])) {
506
+			$from_name = $parsed_from[0];
507
+		}
508
+
509
+		//if from name is "WordPress" let's sub in the site name instead (more friendly!)
510
+		$from_name = $from_name == 'WordPress' ? get_bloginfo() : $from_name;
511
+
512
+		return stripslashes_deep(html_entity_decode($from_name, ENT_QUOTES, "UTF-8"));
513
+	}
514
+
515
+
516
+	/**
517
+	 * setup body for email
518
+	 *
519
+	 * @param bool $preview will determine whether this is preview template or not.
520
+	 * @return string formatted body for email.
521
+	 */
522
+	protected function _body($preview = false)
523
+	{
524
+		//setup template args!
525
+		$this->_template_args = array(
526
+			'subject'   => $this->_subject,
527
+			'from'      => $this->_from,
528
+			'main_body' => wpautop(stripslashes_deep(html_entity_decode($this->_content, ENT_QUOTES, "UTF-8"))),
529
+		);
530
+		$body                 = $this->_get_main_template($preview);
531
+
532
+		/**
533
+		 * This filter allows one to bypass the CSSToInlineStyles tool and leave the body untouched.
534
+		 *
535
+		 * @type    bool $preview Indicates whether a preview is being generated or not.
536
+		 * @return  bool    true  indicates to use the inliner, false bypasses it.
537
+		 */
538
+		if (apply_filters('FHEE__EE_Email_messenger__apply_CSSInliner ', true, $preview)) {
539
+
540
+			//require CssToInlineStyles library and its dependencies via composer autoloader
541
+			require_once EE_THIRD_PARTY . 'cssinliner/vendor/autoload.php';
542
+
543
+			//now if this isn't a preview, let's setup the body so it has inline styles
544
+			if (! $preview || ($preview && defined('DOING_AJAX'))) {
545
+				$style = file_get_contents($this->get_variation($this->_tmp_pack, $this->_incoming_message_type->name,
546
+					false, 'main', $this->_variation), true);
547
+				$CSS   = new TijsVerkoyen\CssToInlineStyles\CssToInlineStyles($body, $style);
548
+				$body  = ltrim($CSS->convert(true),
549
+					">\n"); //for some reason the library has a bracket and new line at the beginning.  This takes care of that.
550
+				$body  = ltrim($body, "<?"); //see https://events.codebasehq.com/projects/event-espresso/tickets/8609
551
+			}
552
+
553
+		}
554
+		return $body;
555
+	}
556
+
557
+
558
+	/**
559
+	 * This just returns any existing test settings that might be saved in the database
560
+	 *
561
+	 * @access public
562
+	 * @return array
563
+	 */
564
+	public function get_existing_test_settings()
565
+	{
566
+		$settings = parent::get_existing_test_settings();
567
+		//override subject if present because we always want it to be fresh.
568
+		if (is_array($settings) && ! empty($settings['subject'])) {
569
+			$settings['subject'] = sprintf(__('Test email sent from %s', 'event_espresso'), get_bloginfo('name'));
570
+		}
571
+		return $settings;
572
+	}
573 573
 
574 574
 
575 575
 }
Please login to merge, or discard this patch.
Spacing   +7 added lines, -7 removed lines patch added patch discarded remove patch
@@ -1,6 +1,6 @@  discard block
 block discarded – undo
1 1
 <?php
2 2
 
3
-if (! defined('EVENT_ESPRESSO_VERSION')) {
3
+if ( ! defined('EVENT_ESPRESSO_VERSION')) {
4 4
     exit('NO direct script access allowed');
5 5
 }
6 6
 
@@ -387,7 +387,7 @@  discard block
 block discarded – undo
387 387
             $this->_body(),
388 388
             $this->_headers()
389 389
         );
390
-        if (! $success) {
390
+        if ( ! $success) {
391 391
             EE_Error::add_error(
392 392
                 sprintf(
393 393
                     __('The email did not send successfully.%3$sThe WordPress wp_mail function is used for sending mails but does not give any useful information when an email fails to send.%3$sIt is possible the "to" address (%1$s) or "from" address (%2$s) is invalid.%3$s',
@@ -426,8 +426,8 @@  discard block
 block discarded – undo
426 426
         $from    = stripslashes_deep(html_entity_decode($this->_from, ENT_QUOTES, "UTF-8"));
427 427
         $headers = array(
428 428
             'MIME-Version: 1.0',
429
-            'From:' . $from,
430
-            'Reply-To:' . $from,
429
+            'From:'.$from,
430
+            'Reply-To:'.$from,
431 431
             'Content-Type:text/html; charset=utf-8',
432 432
         );
433 433
 
@@ -527,7 +527,7 @@  discard block
 block discarded – undo
527 527
             'from'      => $this->_from,
528 528
             'main_body' => wpautop(stripslashes_deep(html_entity_decode($this->_content, ENT_QUOTES, "UTF-8"))),
529 529
         );
530
-        $body                 = $this->_get_main_template($preview);
530
+        $body = $this->_get_main_template($preview);
531 531
 
532 532
         /**
533 533
          * This filter allows one to bypass the CSSToInlineStyles tool and leave the body untouched.
@@ -538,10 +538,10 @@  discard block
 block discarded – undo
538 538
         if (apply_filters('FHEE__EE_Email_messenger__apply_CSSInliner ', true, $preview)) {
539 539
 
540 540
             //require CssToInlineStyles library and its dependencies via composer autoloader
541
-            require_once EE_THIRD_PARTY . 'cssinliner/vendor/autoload.php';
541
+            require_once EE_THIRD_PARTY.'cssinliner/vendor/autoload.php';
542 542
 
543 543
             //now if this isn't a preview, let's setup the body so it has inline styles
544
-            if (! $preview || ($preview && defined('DOING_AJAX'))) {
544
+            if ( ! $preview || ($preview && defined('DOING_AJAX'))) {
545 545
                 $style = file_get_contents($this->get_variation($this->_tmp_pack, $this->_incoming_message_type->name,
546 546
                     false, 'main', $this->_variation), true);
547 547
                 $CSS   = new TijsVerkoyen\CssToInlineStyles\CssToInlineStyles($body, $style);
Please login to merge, or discard this patch.
core/EE_Error.core.php 1 patch
Indentation   +1090 added lines, -1090 removed lines patch added patch discarded remove patch
@@ -5,8 +5,8 @@  discard block
 block discarded – undo
5 5
 // if you're a dev and want to receive all errors via email
6 6
 // add this to your wp-config.php: define( 'EE_ERROR_EMAILS', TRUE );
7 7
 if (defined('WP_DEBUG') && WP_DEBUG === true && defined('EE_ERROR_EMAILS') && EE_ERROR_EMAILS === true) {
8
-    set_error_handler(array('EE_Error', 'error_handler'));
9
-    register_shutdown_function(array('EE_Error', 'fatal_error_handler'));
8
+	set_error_handler(array('EE_Error', 'error_handler'));
9
+	register_shutdown_function(array('EE_Error', 'fatal_error_handler'));
10 10
 }
11 11
 
12 12
 
@@ -23,259 +23,259 @@  discard block
 block discarded – undo
23 23
 {
24 24
 
25 25
 
26
-    /**
27
-     *    name of the file to log exceptions to
28
-     *
29
-     * @var string
30
-     */
31
-    private static $_exception_log_file = 'espresso_error_log.txt';
32
-
33
-    /**
34
-     *    stores details for all exception
35
-     *
36
-     * @var array
37
-     */
38
-    private static $_all_exceptions = array();
39
-
40
-    /**
41
-     *    tracks number of errors
42
-     *
43
-     * @var int
44
-     */
45
-    private static $_error_count = 0;
46
-
47
-    /**
48
-     *    has shutdown action been added ?
49
-     *
50
-     * @var array $_espresso_notices
51
-     */
52
-    private static $_espresso_notices = array('success' => false, 'errors' => false, 'attention' => false);
53
-
54
-
55
-
56
-    /**
57
-     * @override default exception handling
58
-     * @param string         $message
59
-     * @param int            $code
60
-     * @param Exception|null $previous
61
-     */
62
-    public function __construct($message, $code = 0, Exception $previous = null)
63
-    {
64
-        if (version_compare(PHP_VERSION, '5.3.0', '<')) {
65
-            parent::__construct($message, $code);
66
-        } else {
67
-            parent::__construct($message, $code, $previous);
68
-        }
69
-    }
70
-
71
-
72
-
73
-    /**
74
-     *    error_handler
75
-     *
76
-     * @param $code
77
-     * @param $message
78
-     * @param $file
79
-     * @param $line
80
-     * @return void
81
-     */
82
-    public static function error_handler($code, $message, $file, $line)
83
-    {
84
-        $type = EE_Error::error_type($code);
85
-        $site = site_url();
86
-        switch ($site) {
87
-            case 'http://ee4.eventespresso.com/' :
88
-            case 'http://ee4decaf.eventespresso.com/' :
89
-            case 'http://ee4hf.eventespresso.com/' :
90
-            case 'http://ee4a.eventespresso.com/' :
91
-            case 'http://ee4ad.eventespresso.com/' :
92
-            case 'http://ee4b.eventespresso.com/' :
93
-            case 'http://ee4bd.eventespresso.com/' :
94
-            case 'http://ee4d.eventespresso.com/' :
95
-            case 'http://ee4dd.eventespresso.com/' :
96
-                $to = '[email protected]';
97
-                break;
98
-            default :
99
-                $to = get_option('admin_email');
100
-        }
101
-        $subject = $type . ' ' . $message . ' in ' . EVENT_ESPRESSO_VERSION . ' on ' . site_url();
102
-        $msg = EE_Error::_format_error($type, $message, $file, $line);
103
-        if (function_exists('wp_mail')) {
104
-            add_filter('wp_mail_content_type', array('EE_Error', 'set_content_type'));
105
-            wp_mail($to, $subject, $msg);
106
-        }
107
-        echo '<div id="message" class="espresso-notices error"><p>';
108
-        echo $type . ': ' . $message . '<br />' . $file . ' line ' . $line;
109
-        echo '<br /></p></div>';
110
-    }
111
-
112
-
113
-
114
-    /**
115
-     * error_type
116
-     * http://www.php.net/manual/en/errorfunc.constants.php#109430
117
-     *
118
-     * @param $code
119
-     * @return string
120
-     */
121
-    public static function error_type($code)
122
-    {
123
-        switch ($code) {
124
-            case E_ERROR: // 1 //
125
-                return 'E_ERROR';
126
-            case E_WARNING: // 2 //
127
-                return 'E_WARNING';
128
-            case E_PARSE: // 4 //
129
-                return 'E_PARSE';
130
-            case E_NOTICE: // 8 //
131
-                return 'E_NOTICE';
132
-            case E_CORE_ERROR: // 16 //
133
-                return 'E_CORE_ERROR';
134
-            case E_CORE_WARNING: // 32 //
135
-                return 'E_CORE_WARNING';
136
-            case E_COMPILE_ERROR: // 64 //
137
-                return 'E_COMPILE_ERROR';
138
-            case E_COMPILE_WARNING: // 128 //
139
-                return 'E_COMPILE_WARNING';
140
-            case E_USER_ERROR: // 256 //
141
-                return 'E_USER_ERROR';
142
-            case E_USER_WARNING: // 512 //
143
-                return 'E_USER_WARNING';
144
-            case E_USER_NOTICE: // 1024 //
145
-                return 'E_USER_NOTICE';
146
-            case E_STRICT: // 2048 //
147
-                return 'E_STRICT';
148
-            case E_RECOVERABLE_ERROR: // 4096 //
149
-                return 'E_RECOVERABLE_ERROR';
150
-            case E_DEPRECATED: // 8192 //
151
-                return 'E_DEPRECATED';
152
-            case E_USER_DEPRECATED: // 16384 //
153
-                return 'E_USER_DEPRECATED';
154
-            case E_ALL: // 16384 //
155
-                return 'E_ALL';
156
-        }
157
-        return '';
158
-    }
159
-
160
-
161
-
162
-    /**
163
-     *    fatal_error_handler
164
-     *
165
-     * @return void
166
-     */
167
-    public static function fatal_error_handler()
168
-    {
169
-        $last_error = error_get_last();
170
-        if ($last_error['type'] === E_ERROR) {
171
-            EE_Error::error_handler(E_ERROR, $last_error['message'], $last_error['file'], $last_error['line']);
172
-        }
173
-    }
174
-
175
-
176
-
177
-    /**
178
-     * _format_error
179
-     *
180
-     * @param $code
181
-     * @param $message
182
-     * @param $file
183
-     * @param $line
184
-     * @return string
185
-     */
186
-    private static function _format_error($code, $message, $file, $line)
187
-    {
188
-        $html = "<table cellpadding='5'><thead bgcolor='#f8f8f8'><th>Item</th><th align='left'>Details</th></thead><tbody>";
189
-        $html .= "<tr valign='top'><td><b>Code</b></td><td>$code</td></tr>";
190
-        $html .= "<tr valign='top'><td><b>Error</b></td><td>$message</td></tr>";
191
-        $html .= "<tr valign='top'><td><b>File</b></td><td>$file</td></tr>";
192
-        $html .= "<tr valign='top'><td><b>Line</b></td><td>$line</td></tr>";
193
-        $html .= '</tbody></table>';
194
-        return $html;
195
-    }
196
-
197
-
198
-
199
-    /**
200
-     * set_content_type
201
-     *
202
-     * @param $content_type
203
-     * @return string
204
-     */
205
-    public static function set_content_type($content_type)
206
-    {
207
-        return 'text/html';
208
-    }
209
-
210
-
211
-
212
-    /**
213
-     * @return void
214
-     * @throws EE_Error
215
-     * @throws ReflectionException
216
-     */
217
-    public function get_error()
218
-    {
219
-        if (apply_filters('FHEE__EE_Error__get_error__show_normal_exceptions', false)) {
220
-            throw $this;
221
-        }
222
-        // get separate user and developer messages if they exist
223
-        $msg = explode('||', $this->getMessage());
224
-        $user_msg = $msg[0];
225
-        $dev_msg = isset($msg[1]) ? $msg[1] : $msg[0];
226
-        $msg = WP_DEBUG ? $dev_msg : $user_msg;
227
-        // add details to _all_exceptions array
228
-        $x_time = time();
229
-        self::$_all_exceptions[$x_time]['name'] = get_class($this);
230
-        self::$_all_exceptions[$x_time]['file'] = $this->getFile();
231
-        self::$_all_exceptions[$x_time]['line'] = $this->getLine();
232
-        self::$_all_exceptions[$x_time]['msg'] = $msg;
233
-        self::$_all_exceptions[$x_time]['code'] = $this->getCode();
234
-        self::$_all_exceptions[$x_time]['trace'] = $this->getTrace();
235
-        self::$_all_exceptions[$x_time]['string'] = $this->getTraceAsString();
236
-        self::$_error_count++;
237
-        //add_action( 'shutdown', array( $this, 'display_errors' ));
238
-        $this->display_errors();
239
-    }
240
-
241
-
242
-
243
-    /**
244
-     *    has_error
245
-     *
246
-     * @param bool   $check_stored
247
-     * @param string $type_to_check
248
-     * @return bool
249
-     */
250
-    public static function has_error($check_stored = false, $type_to_check = 'errors')
251
-    {
252
-        $has_error = isset(self::$_espresso_notices[$type_to_check])
253
-                     && ! empty(self::$_espresso_notices[$type_to_check])
254
-            ? true
255
-            : false;
256
-        if ($check_stored && ! $has_error) {
257
-            $notices = (array)get_option('ee_notices', array());
258
-            foreach ($notices as $type => $notice) {
259
-                if ($type === $type_to_check && $notice) {
260
-                    return true;
261
-                }
262
-            }
263
-        }
264
-        return $has_error;
265
-    }
266
-
267
-
268
-
269
-    /**
270
-     *    display_errors
271
-     *
272
-     * @echo   string
273
-     * @throws \ReflectionException
274
-     */
275
-    public function display_errors()
276
-    {
277
-        $trace_details = '';
278
-        $output = '
26
+	/**
27
+	 *    name of the file to log exceptions to
28
+	 *
29
+	 * @var string
30
+	 */
31
+	private static $_exception_log_file = 'espresso_error_log.txt';
32
+
33
+	/**
34
+	 *    stores details for all exception
35
+	 *
36
+	 * @var array
37
+	 */
38
+	private static $_all_exceptions = array();
39
+
40
+	/**
41
+	 *    tracks number of errors
42
+	 *
43
+	 * @var int
44
+	 */
45
+	private static $_error_count = 0;
46
+
47
+	/**
48
+	 *    has shutdown action been added ?
49
+	 *
50
+	 * @var array $_espresso_notices
51
+	 */
52
+	private static $_espresso_notices = array('success' => false, 'errors' => false, 'attention' => false);
53
+
54
+
55
+
56
+	/**
57
+	 * @override default exception handling
58
+	 * @param string         $message
59
+	 * @param int            $code
60
+	 * @param Exception|null $previous
61
+	 */
62
+	public function __construct($message, $code = 0, Exception $previous = null)
63
+	{
64
+		if (version_compare(PHP_VERSION, '5.3.0', '<')) {
65
+			parent::__construct($message, $code);
66
+		} else {
67
+			parent::__construct($message, $code, $previous);
68
+		}
69
+	}
70
+
71
+
72
+
73
+	/**
74
+	 *    error_handler
75
+	 *
76
+	 * @param $code
77
+	 * @param $message
78
+	 * @param $file
79
+	 * @param $line
80
+	 * @return void
81
+	 */
82
+	public static function error_handler($code, $message, $file, $line)
83
+	{
84
+		$type = EE_Error::error_type($code);
85
+		$site = site_url();
86
+		switch ($site) {
87
+			case 'http://ee4.eventespresso.com/' :
88
+			case 'http://ee4decaf.eventespresso.com/' :
89
+			case 'http://ee4hf.eventespresso.com/' :
90
+			case 'http://ee4a.eventespresso.com/' :
91
+			case 'http://ee4ad.eventespresso.com/' :
92
+			case 'http://ee4b.eventespresso.com/' :
93
+			case 'http://ee4bd.eventespresso.com/' :
94
+			case 'http://ee4d.eventespresso.com/' :
95
+			case 'http://ee4dd.eventespresso.com/' :
96
+				$to = '[email protected]';
97
+				break;
98
+			default :
99
+				$to = get_option('admin_email');
100
+		}
101
+		$subject = $type . ' ' . $message . ' in ' . EVENT_ESPRESSO_VERSION . ' on ' . site_url();
102
+		$msg = EE_Error::_format_error($type, $message, $file, $line);
103
+		if (function_exists('wp_mail')) {
104
+			add_filter('wp_mail_content_type', array('EE_Error', 'set_content_type'));
105
+			wp_mail($to, $subject, $msg);
106
+		}
107
+		echo '<div id="message" class="espresso-notices error"><p>';
108
+		echo $type . ': ' . $message . '<br />' . $file . ' line ' . $line;
109
+		echo '<br /></p></div>';
110
+	}
111
+
112
+
113
+
114
+	/**
115
+	 * error_type
116
+	 * http://www.php.net/manual/en/errorfunc.constants.php#109430
117
+	 *
118
+	 * @param $code
119
+	 * @return string
120
+	 */
121
+	public static function error_type($code)
122
+	{
123
+		switch ($code) {
124
+			case E_ERROR: // 1 //
125
+				return 'E_ERROR';
126
+			case E_WARNING: // 2 //
127
+				return 'E_WARNING';
128
+			case E_PARSE: // 4 //
129
+				return 'E_PARSE';
130
+			case E_NOTICE: // 8 //
131
+				return 'E_NOTICE';
132
+			case E_CORE_ERROR: // 16 //
133
+				return 'E_CORE_ERROR';
134
+			case E_CORE_WARNING: // 32 //
135
+				return 'E_CORE_WARNING';
136
+			case E_COMPILE_ERROR: // 64 //
137
+				return 'E_COMPILE_ERROR';
138
+			case E_COMPILE_WARNING: // 128 //
139
+				return 'E_COMPILE_WARNING';
140
+			case E_USER_ERROR: // 256 //
141
+				return 'E_USER_ERROR';
142
+			case E_USER_WARNING: // 512 //
143
+				return 'E_USER_WARNING';
144
+			case E_USER_NOTICE: // 1024 //
145
+				return 'E_USER_NOTICE';
146
+			case E_STRICT: // 2048 //
147
+				return 'E_STRICT';
148
+			case E_RECOVERABLE_ERROR: // 4096 //
149
+				return 'E_RECOVERABLE_ERROR';
150
+			case E_DEPRECATED: // 8192 //
151
+				return 'E_DEPRECATED';
152
+			case E_USER_DEPRECATED: // 16384 //
153
+				return 'E_USER_DEPRECATED';
154
+			case E_ALL: // 16384 //
155
+				return 'E_ALL';
156
+		}
157
+		return '';
158
+	}
159
+
160
+
161
+
162
+	/**
163
+	 *    fatal_error_handler
164
+	 *
165
+	 * @return void
166
+	 */
167
+	public static function fatal_error_handler()
168
+	{
169
+		$last_error = error_get_last();
170
+		if ($last_error['type'] === E_ERROR) {
171
+			EE_Error::error_handler(E_ERROR, $last_error['message'], $last_error['file'], $last_error['line']);
172
+		}
173
+	}
174
+
175
+
176
+
177
+	/**
178
+	 * _format_error
179
+	 *
180
+	 * @param $code
181
+	 * @param $message
182
+	 * @param $file
183
+	 * @param $line
184
+	 * @return string
185
+	 */
186
+	private static function _format_error($code, $message, $file, $line)
187
+	{
188
+		$html = "<table cellpadding='5'><thead bgcolor='#f8f8f8'><th>Item</th><th align='left'>Details</th></thead><tbody>";
189
+		$html .= "<tr valign='top'><td><b>Code</b></td><td>$code</td></tr>";
190
+		$html .= "<tr valign='top'><td><b>Error</b></td><td>$message</td></tr>";
191
+		$html .= "<tr valign='top'><td><b>File</b></td><td>$file</td></tr>";
192
+		$html .= "<tr valign='top'><td><b>Line</b></td><td>$line</td></tr>";
193
+		$html .= '</tbody></table>';
194
+		return $html;
195
+	}
196
+
197
+
198
+
199
+	/**
200
+	 * set_content_type
201
+	 *
202
+	 * @param $content_type
203
+	 * @return string
204
+	 */
205
+	public static function set_content_type($content_type)
206
+	{
207
+		return 'text/html';
208
+	}
209
+
210
+
211
+
212
+	/**
213
+	 * @return void
214
+	 * @throws EE_Error
215
+	 * @throws ReflectionException
216
+	 */
217
+	public function get_error()
218
+	{
219
+		if (apply_filters('FHEE__EE_Error__get_error__show_normal_exceptions', false)) {
220
+			throw $this;
221
+		}
222
+		// get separate user and developer messages if they exist
223
+		$msg = explode('||', $this->getMessage());
224
+		$user_msg = $msg[0];
225
+		$dev_msg = isset($msg[1]) ? $msg[1] : $msg[0];
226
+		$msg = WP_DEBUG ? $dev_msg : $user_msg;
227
+		// add details to _all_exceptions array
228
+		$x_time = time();
229
+		self::$_all_exceptions[$x_time]['name'] = get_class($this);
230
+		self::$_all_exceptions[$x_time]['file'] = $this->getFile();
231
+		self::$_all_exceptions[$x_time]['line'] = $this->getLine();
232
+		self::$_all_exceptions[$x_time]['msg'] = $msg;
233
+		self::$_all_exceptions[$x_time]['code'] = $this->getCode();
234
+		self::$_all_exceptions[$x_time]['trace'] = $this->getTrace();
235
+		self::$_all_exceptions[$x_time]['string'] = $this->getTraceAsString();
236
+		self::$_error_count++;
237
+		//add_action( 'shutdown', array( $this, 'display_errors' ));
238
+		$this->display_errors();
239
+	}
240
+
241
+
242
+
243
+	/**
244
+	 *    has_error
245
+	 *
246
+	 * @param bool   $check_stored
247
+	 * @param string $type_to_check
248
+	 * @return bool
249
+	 */
250
+	public static function has_error($check_stored = false, $type_to_check = 'errors')
251
+	{
252
+		$has_error = isset(self::$_espresso_notices[$type_to_check])
253
+					 && ! empty(self::$_espresso_notices[$type_to_check])
254
+			? true
255
+			: false;
256
+		if ($check_stored && ! $has_error) {
257
+			$notices = (array)get_option('ee_notices', array());
258
+			foreach ($notices as $type => $notice) {
259
+				if ($type === $type_to_check && $notice) {
260
+					return true;
261
+				}
262
+			}
263
+		}
264
+		return $has_error;
265
+	}
266
+
267
+
268
+
269
+	/**
270
+	 *    display_errors
271
+	 *
272
+	 * @echo   string
273
+	 * @throws \ReflectionException
274
+	 */
275
+	public function display_errors()
276
+	{
277
+		$trace_details = '';
278
+		$output = '
279 279
 <style type="text/css">
280 280
 	#ee-error-message {
281 281
 		max-width:90% !important;
@@ -331,19 +331,19 @@  discard block
 block discarded – undo
331 331
 	}
332 332
 </style>
333 333
 <div id="ee-error-message" class="error">';
334
-        if (! WP_DEBUG) {
335
-            $output .= '
334
+		if (! WP_DEBUG) {
335
+			$output .= '
336 336
 	<p>';
337
-        }
338
-        // cycle thru errors
339
-        foreach (self::$_all_exceptions as $time => $ex) {
340
-            $error_code = '';
341
-            // process trace info
342
-            if (empty($ex['trace'])) {
343
-                $trace_details .= __('Sorry, but no trace information was available for this exception.',
344
-                    'event_espresso');
345
-            } else {
346
-                $trace_details .= '
337
+		}
338
+		// cycle thru errors
339
+		foreach (self::$_all_exceptions as $time => $ex) {
340
+			$error_code = '';
341
+			// process trace info
342
+			if (empty($ex['trace'])) {
343
+				$trace_details .= __('Sorry, but no trace information was available for this exception.',
344
+					'event_espresso');
345
+			} else {
346
+				$trace_details .= '
347 347
 			<div id="ee-trace-details">
348 348
 			<table width="100%" border="0" cellpadding="5" cellspacing="0">
349 349
 				<tr>
@@ -353,38 +353,38 @@  discard block
 block discarded – undo
353 353
 					<th scope="col" align="left">Class</th>
354 354
 					<th scope="col" align="left">Method( arguments )</th>
355 355
 				</tr>';
356
-                $last_on_stack = count($ex['trace']) - 1;
357
-                // reverse array so that stack is in proper chronological order
358
-                $sorted_trace = array_reverse($ex['trace']);
359
-                foreach ($sorted_trace as $nmbr => $trace) {
360
-                    $file = isset($trace['file']) ? $trace['file'] : '';
361
-                    $class = isset($trace['class']) ? $trace['class'] : '';
362
-                    $type = isset($trace['type']) ? $trace['type'] : '';
363
-                    $function = isset($trace['function']) ? $trace['function'] : '';
364
-                    $args = isset($trace['args']) ? $this->_convert_args_to_string($trace['args']) : '';
365
-                    $line = isset($trace['line']) ? $trace['line'] : '';
366
-                    $zebra = ($nmbr % 2) ? ' odd' : '';
367
-                    if (empty($file) && ! empty($class)) {
368
-                        $a = new ReflectionClass($class);
369
-                        $file = $a->getFileName();
370
-                        if (empty($line) && ! empty($function)) {
371
-                            $b = new ReflectionMethod($class, $function);
372
-                            $line = $b->getStartLine();
373
-                        }
374
-                    }
375
-                    if ($nmbr === $last_on_stack) {
376
-                        $file = $ex['file'] !== '' ? $ex['file'] : $file;
377
-                        $line = $ex['line'] !== '' ? $ex['line'] : $line;
378
-                        $error_code = self::generate_error_code($file, $trace['function'], $line);
379
-                    }
380
-                    $nmbr_dsply = ! empty($nmbr) ? $nmbr : '&nbsp;';
381
-                    $line_dsply = ! empty($line) ? $line : '&nbsp;';
382
-                    $file_dsply = ! empty($file) ? $file : '&nbsp;';
383
-                    $class_dsply = ! empty($class) ? $class : '&nbsp;';
384
-                    $type_dsply = ! empty($type) ? $type : '&nbsp;';
385
-                    $function_dsply = ! empty($function) ? $function : '&nbsp;';
386
-                    $args_dsply = ! empty($args) ? '( ' . $args . ' )' : '';
387
-                    $trace_details .= '
356
+				$last_on_stack = count($ex['trace']) - 1;
357
+				// reverse array so that stack is in proper chronological order
358
+				$sorted_trace = array_reverse($ex['trace']);
359
+				foreach ($sorted_trace as $nmbr => $trace) {
360
+					$file = isset($trace['file']) ? $trace['file'] : '';
361
+					$class = isset($trace['class']) ? $trace['class'] : '';
362
+					$type = isset($trace['type']) ? $trace['type'] : '';
363
+					$function = isset($trace['function']) ? $trace['function'] : '';
364
+					$args = isset($trace['args']) ? $this->_convert_args_to_string($trace['args']) : '';
365
+					$line = isset($trace['line']) ? $trace['line'] : '';
366
+					$zebra = ($nmbr % 2) ? ' odd' : '';
367
+					if (empty($file) && ! empty($class)) {
368
+						$a = new ReflectionClass($class);
369
+						$file = $a->getFileName();
370
+						if (empty($line) && ! empty($function)) {
371
+							$b = new ReflectionMethod($class, $function);
372
+							$line = $b->getStartLine();
373
+						}
374
+					}
375
+					if ($nmbr === $last_on_stack) {
376
+						$file = $ex['file'] !== '' ? $ex['file'] : $file;
377
+						$line = $ex['line'] !== '' ? $ex['line'] : $line;
378
+						$error_code = self::generate_error_code($file, $trace['function'], $line);
379
+					}
380
+					$nmbr_dsply = ! empty($nmbr) ? $nmbr : '&nbsp;';
381
+					$line_dsply = ! empty($line) ? $line : '&nbsp;';
382
+					$file_dsply = ! empty($file) ? $file : '&nbsp;';
383
+					$class_dsply = ! empty($class) ? $class : '&nbsp;';
384
+					$type_dsply = ! empty($type) ? $type : '&nbsp;';
385
+					$function_dsply = ! empty($function) ? $function : '&nbsp;';
386
+					$args_dsply = ! empty($args) ? '( ' . $args . ' )' : '';
387
+					$trace_details .= '
388 388
 					<tr>
389 389
 						<td align="right" class="' . $zebra . '">' . $nmbr_dsply . '</td>
390 390
 						<td align="right" class="' . $zebra . '">' . $line_dsply . '</td>
@@ -392,674 +392,674 @@  discard block
 block discarded – undo
392 392
 						<td align="left" class="' . $zebra . '">' . $class_dsply . '</td>
393 393
 						<td align="left" class="' . $zebra . '">' . $type_dsply . $function_dsply . $args_dsply . '</td>
394 394
 					</tr>';
395
-                }
396
-                $trace_details .= '
395
+				}
396
+				$trace_details .= '
397 397
 			 </table>
398 398
 			</div>';
399
-            }
400
-            $ex['code'] = $ex['code'] ? $ex['code'] : $error_code;
401
-            // add generic non-identifying messages for non-privileged users
402
-            if (! WP_DEBUG) {
403
-                $output .= '<span class="ee-error-user-msg-spn">'
404
-                           . trim($ex['msg'])
405
-                           . '</span> &nbsp; <sup>'
406
-                           . $ex['code']
407
-                           . '</sup><br />';
408
-            } else {
409
-                // or helpful developer messages if debugging is on
410
-                $output .= '
399
+			}
400
+			$ex['code'] = $ex['code'] ? $ex['code'] : $error_code;
401
+			// add generic non-identifying messages for non-privileged users
402
+			if (! WP_DEBUG) {
403
+				$output .= '<span class="ee-error-user-msg-spn">'
404
+						   . trim($ex['msg'])
405
+						   . '</span> &nbsp; <sup>'
406
+						   . $ex['code']
407
+						   . '</sup><br />';
408
+			} else {
409
+				// or helpful developer messages if debugging is on
410
+				$output .= '
411 411
 		<div class="ee-error-dev-msg-dv">
412 412
 			<p class="ee-error-dev-msg-pg">
413 413
 				<strong class="ee-error-dev-msg-str">An '
414
-                           . $ex['name']
415
-                           . ' exception was thrown!</strong>  &nbsp; <span>code: '
416
-                           . $ex['code']
417
-                           . '</span><br />
414
+						   . $ex['name']
415
+						   . ' exception was thrown!</strong>  &nbsp; <span>code: '
416
+						   . $ex['code']
417
+						   . '</span><br />
418 418
 				<span class="big-text">"'
419
-                           . trim($ex['msg'])
420
-                           . '"</span><br/>
419
+						   . trim($ex['msg'])
420
+						   . '"</span><br/>
421 421
 				<a id="display-ee-error-trace-'
422
-                           . self::$_error_count
423
-                           . $time
424
-                           . '" class="display-ee-error-trace-lnk small-text" rel="ee-error-trace-'
425
-                           . self::$_error_count
426
-                           . $time
427
-                           . '">
422
+						   . self::$_error_count
423
+						   . $time
424
+						   . '" class="display-ee-error-trace-lnk small-text" rel="ee-error-trace-'
425
+						   . self::$_error_count
426
+						   . $time
427
+						   . '">
428 428
 					'
429
-                           . __('click to view backtrace and class/method details', 'event_espresso')
430
-                           . '
429
+						   . __('click to view backtrace and class/method details', 'event_espresso')
430
+						   . '
431 431
 				</a><br />
432 432
 				<span class="small-text lt-grey-text">'
433
-                           . $ex['file']
434
-                           . ' &nbsp; ( line no: '
435
-                           . $ex['line']
436
-                           . ' )</span>
433
+						   . $ex['file']
434
+						   . ' &nbsp; ( line no: '
435
+						   . $ex['line']
436
+						   . ' )</span>
437 437
 			</p>
438 438
 			<div id="ee-error-trace-'
439
-                           . self::$_error_count
440
-                           . $time
441
-                           . '-dv" class="ee-error-trace-dv" style="display: none;">
439
+						   . self::$_error_count
440
+						   . $time
441
+						   . '-dv" class="ee-error-trace-dv" style="display: none;">
442 442
 				'
443
-                           . $trace_details;
444
-                if (! empty($class)) {
445
-                    $output .= '
443
+						   . $trace_details;
444
+				if (! empty($class)) {
445
+					$output .= '
446 446
 				<div style="padding:3px; margin:0 0 1em; border:1px solid #666; background:#fff; border-radius:3px;">
447 447
 					<div style="padding:1em 2em; border:1px solid #666; background:#f9f9f9;">
448 448
 						<h3>Class Details</h3>';
449
-                    $a = new ReflectionClass($class);
450
-                    $output .= '
449
+					$a = new ReflectionClass($class);
450
+					$output .= '
451 451
 						<pre>' . $a . '</pre>
452 452
 					</div>
453 453
 				</div>';
454
-                }
455
-                $output .= '
454
+				}
455
+				$output .= '
456 456
 			</div>
457 457
 		</div>
458 458
 		<br />';
459
-            }
460
-            $this->write_to_error_log($time, $ex);
461
-        }
462
-        // remove last linebreak
463
-        $output = substr($output, 0, -6);
464
-        if (! WP_DEBUG) {
465
-            $output .= '
459
+			}
460
+			$this->write_to_error_log($time, $ex);
461
+		}
462
+		// remove last linebreak
463
+		$output = substr($output, 0, -6);
464
+		if (! WP_DEBUG) {
465
+			$output .= '
466 466
 	</p>';
467
-        }
468
-        $output .= '
467
+		}
468
+		$output .= '
469 469
 </div>';
470
-        $output .= self::_print_scripts(true);
471
-        if (defined('DOING_AJAX')) {
472
-            echo wp_json_encode(array('error' => $output));
473
-            exit();
474
-        }
475
-        echo $output;
476
-        die();
477
-    }
478
-
479
-
480
-
481
-    /**
482
-     *    generate string from exception trace args
483
-     *
484
-     * @param array $arguments
485
-     * @param bool  $array
486
-     * @return string
487
-     */
488
-    private function _convert_args_to_string($arguments = array(), $array = false)
489
-    {
490
-        $arg_string = '';
491
-        if (! empty($arguments)) {
492
-            $args = array();
493
-            foreach ($arguments as $arg) {
494
-                if (! empty($arg)) {
495
-                    if (is_string($arg)) {
496
-                        $args[] = " '" . $arg . "'";
497
-                    } elseif (is_array($arg)) {
498
-                        $args[] = 'ARRAY(' . $this->_convert_args_to_string($arg, true);
499
-                    } elseif ($arg === null) {
500
-                        $args[] = ' NULL';
501
-                    } elseif (is_bool($arg)) {
502
-                        $args[] = ($arg) ? ' TRUE' : ' FALSE';
503
-                    } elseif (is_object($arg)) {
504
-                        $args[] = ' OBJECT ' . get_class($arg);
505
-                    } elseif (is_resource($arg)) {
506
-                        $args[] = get_resource_type($arg);
507
-                    } else {
508
-                        $args[] = $arg;
509
-                    }
510
-                }
511
-            }
512
-            $arg_string = implode(', ', $args);
513
-        }
514
-        if ($array) {
515
-            $arg_string .= ' )';
516
-        }
517
-        return $arg_string;
518
-    }
519
-
520
-
521
-
522
-    /**
523
-     *    add error message
524
-     *
525
-     * @param        string $msg  the message to display to users or developers - adding a double pipe || (OR) creates
526
-     *                            separate messages for user || dev
527
-     * @param        string $file the file that the error occurred in - just use __FILE__
528
-     * @param        string $func the function/method that the error occurred in - just use __FUNCTION__
529
-     * @param        string $line the line number where the error occurred - just use __LINE__
530
-     * @return        void
531
-     */
532
-    public static function add_error($msg = null, $file = null, $func = null, $line = null)
533
-    {
534
-        self::_add_notice('errors', $msg, $file, $func, $line);
535
-        self::$_error_count++;
536
-    }
537
-
538
-
539
-
540
-    /**
541
-     * If WP_DEBUG is active, throws an exception. If WP_DEBUG is off, just
542
-     * adds an error
543
-     *
544
-     * @param string $msg
545
-     * @param string $file
546
-     * @param string $func
547
-     * @param string $line
548
-     * @throws EE_Error
549
-     */
550
-    public static function throw_exception_if_debugging($msg = null, $file = null, $func = null, $line = null)
551
-    {
552
-        if (WP_DEBUG) {
553
-            throw new EE_Error($msg);
554
-        }
555
-        EE_Error::add_error($msg, $file, $func, $line);
556
-    }
557
-
558
-
559
-
560
-    /**
561
-     *    add success message
562
-     *
563
-     * @param        string $msg  the message to display to users or developers - adding a double pipe || (OR) creates
564
-     *                            separate messages for user || dev
565
-     * @param        string $file the file that the error occurred in - just use __FILE__
566
-     * @param        string $func the function/method that the error occurred in - just use __FUNCTION__
567
-     * @param        string $line the line number where the error occurred - just use __LINE__
568
-     * @return        void
569
-     */
570
-    public static function add_success($msg = null, $file = null, $func = null, $line = null)
571
-    {
572
-        self::_add_notice('success', $msg, $file, $func, $line);
573
-    }
574
-
575
-
576
-
577
-    /**
578
-     *    add attention message
579
-     *
580
-     * @param        string $msg  the message to display to users or developers - adding a double pipe || (OR) creates
581
-     *                            separate messages for user || dev
582
-     * @param        string $file the file that the error occurred in - just use __FILE__
583
-     * @param        string $func the function/method that the error occurred in - just use __FUNCTION__
584
-     * @param        string $line the line number where the error occurred - just use __LINE__
585
-     * @return        void
586
-     */
587
-    public static function add_attention($msg = null, $file = null, $func = null, $line = null)
588
-    {
589
-        self::_add_notice('attention', $msg, $file, $func, $line);
590
-    }
591
-
592
-
593
-
594
-    /**
595
-     *    add success message
596
-     *
597
-     * @param        string $type whether the message is for a success or error notification
598
-     * @param        string $msg  the message to display to users or developers - adding a double pipe || (OR) creates
599
-     *                            separate messages for user || dev
600
-     * @param        string $file the file that the error occurred in - just use __FILE__
601
-     * @param        string $func the function/method that the error occurred in - just use __FUNCTION__
602
-     * @param        string $line the line number where the error occurred - just use __LINE__
603
-     * @return        void
604
-     */
605
-    private static function _add_notice($type = 'success', $msg = null, $file = null, $func = null, $line = null)
606
-    {
607
-        if (empty($msg)) {
608
-            EE_Error::doing_it_wrong(
609
-                'EE_Error::add_' . $type . '()',
610
-                sprintf(
611
-                    __('Notifications are not much use without a message! Please add a message to the EE_Error::add_%s() call made in %s on line %d',
612
-                        'event_espresso'),
613
-                    $type,
614
-                    $file,
615
-                    $line
616
-                ),
617
-                EVENT_ESPRESSO_VERSION
618
-            );
619
-        }
620
-        if ($type === 'errors' && (empty($file) || empty($func) || empty($line))) {
621
-            EE_Error::doing_it_wrong(
622
-                'EE_Error::add_error()',
623
-                __('You need to provide the file name, function name, and line number that the error occurred on in order to better assist with debugging.',
624
-                    'event_espresso'),
625
-                EVENT_ESPRESSO_VERSION
626
-            );
627
-        }
628
-        // get separate user and developer messages if they exist
629
-        $msg = explode('||', $msg);
630
-        $user_msg = $msg[0];
631
-        $dev_msg = isset($msg[1]) ? $msg[1] : $msg[0];
632
-        /**
633
-         * Do an action so other code can be triggered when a notice is created
634
-         *
635
-         * @param string $type     can be 'errors', 'attention', or 'success'
636
-         * @param string $user_msg message displayed to user when WP_DEBUG is off
637
-         * @param string $user_msg message displayed to user when WP_DEBUG is on
638
-         * @param string $file     file where error was generated
639
-         * @param string $func     function where error was generated
640
-         * @param string $line     line where error was generated
641
-         */
642
-        do_action('AHEE__EE_Error___add_notice', $type, $user_msg, $dev_msg, $file, $func, $line);
643
-        $msg = WP_DEBUG ? $dev_msg : $user_msg;
644
-        // add notice if message exists
645
-        if (! empty($msg)) {
646
-            // get error code
647
-            $notice_code = EE_Error::generate_error_code($file, $func, $line);
648
-            if (WP_DEBUG && $type === 'errors') {
649
-                $msg .= '<br/><span class="tiny-text">' . $notice_code . '</span>';
650
-            }
651
-            // add notice. Index by code if it's not blank
652
-            if ($notice_code) {
653
-                self::$_espresso_notices[$type][$notice_code] = $msg;
654
-            } else {
655
-                self::$_espresso_notices[$type][] = $msg;
656
-            }
657
-            add_action('wp_footer', array('EE_Error', 'enqueue_error_scripts'), 1);
658
-        }
659
-    }
660
-
661
-
662
-
663
-    /**
664
-     *    in some case it may be necessary to overwrite the existing success messages
665
-     *
666
-     * @return        void
667
-     */
668
-    public static function overwrite_success()
669
-    {
670
-        self::$_espresso_notices['success'] = false;
671
-    }
672
-
673
-
674
-
675
-    /**
676
-     *    in some case it may be necessary to overwrite the existing attention messages
677
-     *
678
-     * @return        void
679
-     */
680
-    public static function overwrite_attention()
681
-    {
682
-        self::$_espresso_notices['attention'] = false;
683
-    }
684
-
685
-
686
-
687
-    /**
688
-     *    in some case it may be necessary to overwrite the existing error messages
689
-     *
690
-     * @return        void
691
-     */
692
-    public static function overwrite_errors()
693
-    {
694
-        self::$_espresso_notices['errors'] = false;
695
-    }
696
-
697
-
698
-
699
-    /**
700
-     *    reset_notices
701
-     *
702
-     * @return void
703
-     */
704
-    public static function reset_notices()
705
-    {
706
-        self::$_espresso_notices['success'] = false;
707
-        self::$_espresso_notices['attention'] = false;
708
-        self::$_espresso_notices['errors'] = false;
709
-    }
710
-
711
-
712
-
713
-    /**
714
-     *    has_errors
715
-     *
716
-     * @return int
717
-     */
718
-    public static function has_notices()
719
-    {
720
-        $has_notices = 0;
721
-        // check for success messages
722
-        $has_notices = self::$_espresso_notices['success'] && ! empty(self::$_espresso_notices['success']) ? 3
723
-            : $has_notices;
724
-        // check for attention messages
725
-        $has_notices = self::$_espresso_notices['attention'] && ! empty(self::$_espresso_notices['attention']) ? 2
726
-            : $has_notices;
727
-        // check for error messages
728
-        $has_notices = self::$_espresso_notices['errors'] && ! empty(self::$_espresso_notices['errors']) ? 1
729
-            : $has_notices;
730
-        return $has_notices;
731
-    }
732
-
733
-
734
-
735
-    /**
736
-     * This simply returns non formatted error notices as they were sent into the EE_Error object.
737
-     *
738
-     * @since 4.9.0
739
-     * @return array
740
-     */
741
-    public static function get_vanilla_notices()
742
-    {
743
-        return array(
744
-            'success'   => isset(self::$_espresso_notices['success']) ? self::$_espresso_notices['success'] : array(),
745
-            'attention' => isset(self::$_espresso_notices['attention']) ? self::$_espresso_notices['attention']
746
-                : array(),
747
-            'errors'    => isset(self::$_espresso_notices['errors']) ? self::$_espresso_notices['errors'] : array(),
748
-        );
749
-    }
750
-
751
-
752
-
753
-    /**
754
-     *    compile all error or success messages into one string
755
-     *
756
-     * @see EE_Error::get_raw_notices if you want the raw notices without any preparations made to them
757
-     * @param        boolean $format_output     whether or not to format the messages for display in the WP admin
758
-     * @param        boolean $save_to_transient whether or not to save notices to the db for retrieval on next request
759
-     *                                          - ONLY do this just before redirecting
760
-     * @param        boolean $remove_empty      whether or not to unset empty messages
761
-     * @return        array
762
-     */
763
-    public static function get_notices($format_output = true, $save_to_transient = false, $remove_empty = true)
764
-    {
765
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
766
-        $success_messages = '';
767
-        $attention_messages = '';
768
-        $error_messages = '';
769
-        $print_scripts = false;
770
-        // either save notices to the db
771
-        if ($save_to_transient) {
772
-            update_option('ee_notices', self::$_espresso_notices);
773
-            return array();
774
-        }
775
-        // grab any notices that have been previously saved
776
-        if ($notices = get_option('ee_notices', false)) {
777
-            foreach ($notices as $type => $notice) {
778
-                if (is_array($notice) && ! empty($notice)) {
779
-                    // make sure that existing notice type is an array
780
-                    self::$_espresso_notices[$type] = is_array(self::$_espresso_notices[$type])
781
-                                                      && ! empty(self::$_espresso_notices[$type])
782
-                        ? self::$_espresso_notices[$type] : array();
783
-                    // merge stored notices with any newly created ones
784
-                    self::$_espresso_notices[$type] = array_merge(self::$_espresso_notices[$type], $notice);
785
-                    $print_scripts = true;
786
-                }
787
-            }
788
-            // now clear any stored notices
789
-            update_option('ee_notices', false);
790
-        }
791
-        // check for success messages
792
-        if (self::$_espresso_notices['success'] && ! empty(self::$_espresso_notices['success'])) {
793
-            // combine messages
794
-            $success_messages .= implode(self::$_espresso_notices['success'], '<br /><br />');
795
-            $print_scripts = true;
796
-        }
797
-        // check for attention messages
798
-        if (self::$_espresso_notices['attention'] && ! empty(self::$_espresso_notices['attention'])) {
799
-            // combine messages
800
-            $attention_messages .= implode(self::$_espresso_notices['attention'], '<br /><br />');
801
-            $print_scripts = true;
802
-        }
803
-        // check for error messages
804
-        if (self::$_espresso_notices['errors'] && ! empty(self::$_espresso_notices['errors'])) {
805
-            $error_messages .= count(self::$_espresso_notices['errors']) > 1
806
-                ? __('The following errors have occurred:<br />', 'event_espresso')
807
-                : __('An error has occurred:<br />', 'event_espresso');
808
-            // combine messages
809
-            $error_messages .= implode(self::$_espresso_notices['errors'], '<br /><br />');
810
-            $print_scripts = true;
811
-        }
812
-        if ($format_output) {
813
-            $notices = '<div id="espresso-notices">';
814
-            $close = is_admin() ? ''
815
-                : '<a class="close-espresso-notice hide-if-no-js"><span class="dashicons dashicons-no"></span></a>';
816
-            if ($success_messages !== '') {
817
-                $css_id = is_admin() ? 'message' : 'espresso-notices-success';
818
-                $css_class = is_admin() ? 'updated fade' : 'success fade-away';
819
-                //showMessage( $success_messages );
820
-                $notices .= '<div id="'
821
-                            . $css_id
822
-                            . '" class="espresso-notices '
823
-                            . $css_class
824
-                            . '" style="display:none;"><p>'
825
-                            . $success_messages
826
-                            . '</p>'
827
-                            . $close
828
-                            . '</div>';
829
-            }
830
-            if ($attention_messages !== '') {
831
-                $css_id = is_admin() ? 'message' : 'espresso-notices-attention';
832
-                $css_class = is_admin() ? 'updated ee-notices-attention' : 'attention fade-away';
833
-                //showMessage( $error_messages, TRUE );
834
-                $notices .= '<div id="'
835
-                            . $css_id
836
-                            . '" class="espresso-notices '
837
-                            . $css_class
838
-                            . '" style="display:none;"><p>'
839
-                            . $attention_messages
840
-                            . '</p>'
841
-                            . $close
842
-                            . '</div>';
843
-            }
844
-            if ($error_messages !== '') {
845
-                $css_id = is_admin() ? 'message' : 'espresso-notices-error';
846
-                $css_class = is_admin() ? 'error' : 'error fade-away';
847
-                //showMessage( $error_messages, TRUE );
848
-                $notices .= '<div id="'
849
-                            . $css_id
850
-                            . '" class="espresso-notices '
851
-                            . $css_class
852
-                            . '" style="display:none;"><p>'
853
-                            . $error_messages
854
-                            . '</p>'
855
-                            . $close
856
-                            . '</div>';
857
-            }
858
-            $notices .= '</div>';
859
-        } else {
860
-            $notices = array(
861
-                'success'   => $success_messages,
862
-                'attention' => $attention_messages,
863
-                'errors'    => $error_messages,
864
-            );
865
-            if ($remove_empty) {
866
-                // remove empty notices
867
-                foreach ($notices as $type => $notice) {
868
-                    if (empty($notice)) {
869
-                        unset($notices[$type]);
870
-                    }
871
-                }
872
-            }
873
-        }
874
-        if ($print_scripts) {
875
-            self::_print_scripts();
876
-        }
877
-        return $notices;
878
-    }
879
-
880
-
881
-
882
-    /**
883
-     *    add_persistent_admin_notice
884
-     *
885
-     * @param        string $pan_name     the name, or key of the Persistent Admin Notice to be stored
886
-     * @param        string $pan_message  the message to be stored persistently until dismissed
887
-     * @param bool          $force_update allows one to enforce the reappearance of a persistent message.
888
-     * @return        void
889
-     */
890
-    public static function add_persistent_admin_notice($pan_name = '', $pan_message, $force_update = false)
891
-    {
892
-        if (! empty($pan_name) && ! empty($pan_message)) {
893
-            $persistent_admin_notices = get_option('ee_pers_admin_notices', array());
894
-            //maybe initialize persistent_admin_notices
895
-            if (empty($persistent_admin_notices)) {
896
-                add_option('ee_pers_admin_notices', array(), '', 'no');
897
-            }
898
-            $pan_name = sanitize_key($pan_name);
899
-            if (! array_key_exists($pan_name, $persistent_admin_notices) || $force_update) {
900
-                $persistent_admin_notices[$pan_name] = $pan_message;
901
-                update_option('ee_pers_admin_notices', $persistent_admin_notices);
902
-            }
903
-        }
904
-    }
905
-
906
-
907
-
908
-    /**
909
-     *    dismiss_persistent_admin_notice
910
-     *
911
-     * @param        string $pan_name the name, or key of the Persistent Admin Notice to be dismissed
912
-     * @param bool          $purge
913
-     * @param bool          $return_immediately
914
-     * @return        void
915
-     */
916
-    public static function dismiss_persistent_admin_notice($pan_name = '', $purge = false, $return_immediately = false)
917
-    {
918
-        $pan_name = EE_Registry::instance()->REQ->is_set('ee_nag_notice')
919
-            ? EE_Registry::instance()->REQ->get('ee_nag_notice') : $pan_name;
920
-        if (! empty($pan_name)) {
921
-            $persistent_admin_notices = get_option('ee_pers_admin_notices', array());
922
-            // check if notice we wish to dismiss is actually in the $persistent_admin_notices array
923
-            if (is_array($persistent_admin_notices) && isset($persistent_admin_notices[$pan_name])) {
924
-                // completely delete nag notice, or just NULL message so that it can NOT be added again ?
925
-                if ($purge) {
926
-                    unset($persistent_admin_notices[$pan_name]);
927
-                } else {
928
-                    $persistent_admin_notices[$pan_name] = null;
929
-                }
930
-                if (update_option('ee_pers_admin_notices', $persistent_admin_notices) === false) {
931
-                    EE_Error::add_error(sprintf(__('The persistent admin notice for "%s" could not be deleted.',
932
-                        'event_espresso'), $pan_name), __FILE__, __FUNCTION__, __LINE__);
933
-                }
934
-            }
935
-        }
936
-        if ($return_immediately) {
937
-            return;
938
-        }
939
-        if (EE_Registry::instance()->REQ->ajax) {
940
-            // grab any notices and concatenate into string
941
-            echo wp_json_encode(array('errors' => implode('<br />', EE_Error::get_notices(false))));
942
-            exit();
943
-        }
944
-        // save errors to a transient to be displayed on next request (after redirect)
945
-        EE_Error::get_notices(false, true);
946
-        $return_url = EE_Registry::instance()->REQ->is_set('return_url')
947
-            ? EE_Registry::instance()->REQ->get('return_url') : '';
948
-        wp_safe_redirect(urldecode($return_url));
949
-    }
950
-
951
-
952
-
953
-    /**
954
-     * display_persistent_admin_notices
955
-     *
956
-     * @param  string $pan_name    the name, or key of the Persistent Admin Notice to be stored
957
-     * @param  string $pan_message the message to be stored persistently until dismissed
958
-     * @param  string $return_url  URL to go back to after nag notice is dismissed
959
-     * @return string
960
-     */
961
-    public static function display_persistent_admin_notices($pan_name = '', $pan_message = '', $return_url = '')
962
-    {
963
-        if (! empty($pan_name) && ! empty($pan_message)) {
964
-            $args = array(
965
-                'nag_notice'    => $pan_name,
966
-                'return_url'    => urlencode($return_url),
967
-                'ajax_url'      => WP_AJAX_URL,
968
-                'unknown_error' => esc_html__(
969
-                    'An unknown error has occurred on the server while attempting to dismiss this notice.',
970
-                    'event_espresso'
971
-                ),
972
-            );
973
-            EE_Registry::$i18n_js_strings = array_merge(
974
-                EE_Registry::$i18n_js_strings,
975
-                array('ee_dismiss' => $args)
976
-            );
977
-            return '
470
+		$output .= self::_print_scripts(true);
471
+		if (defined('DOING_AJAX')) {
472
+			echo wp_json_encode(array('error' => $output));
473
+			exit();
474
+		}
475
+		echo $output;
476
+		die();
477
+	}
478
+
479
+
480
+
481
+	/**
482
+	 *    generate string from exception trace args
483
+	 *
484
+	 * @param array $arguments
485
+	 * @param bool  $array
486
+	 * @return string
487
+	 */
488
+	private function _convert_args_to_string($arguments = array(), $array = false)
489
+	{
490
+		$arg_string = '';
491
+		if (! empty($arguments)) {
492
+			$args = array();
493
+			foreach ($arguments as $arg) {
494
+				if (! empty($arg)) {
495
+					if (is_string($arg)) {
496
+						$args[] = " '" . $arg . "'";
497
+					} elseif (is_array($arg)) {
498
+						$args[] = 'ARRAY(' . $this->_convert_args_to_string($arg, true);
499
+					} elseif ($arg === null) {
500
+						$args[] = ' NULL';
501
+					} elseif (is_bool($arg)) {
502
+						$args[] = ($arg) ? ' TRUE' : ' FALSE';
503
+					} elseif (is_object($arg)) {
504
+						$args[] = ' OBJECT ' . get_class($arg);
505
+					} elseif (is_resource($arg)) {
506
+						$args[] = get_resource_type($arg);
507
+					} else {
508
+						$args[] = $arg;
509
+					}
510
+				}
511
+			}
512
+			$arg_string = implode(', ', $args);
513
+		}
514
+		if ($array) {
515
+			$arg_string .= ' )';
516
+		}
517
+		return $arg_string;
518
+	}
519
+
520
+
521
+
522
+	/**
523
+	 *    add error message
524
+	 *
525
+	 * @param        string $msg  the message to display to users or developers - adding a double pipe || (OR) creates
526
+	 *                            separate messages for user || dev
527
+	 * @param        string $file the file that the error occurred in - just use __FILE__
528
+	 * @param        string $func the function/method that the error occurred in - just use __FUNCTION__
529
+	 * @param        string $line the line number where the error occurred - just use __LINE__
530
+	 * @return        void
531
+	 */
532
+	public static function add_error($msg = null, $file = null, $func = null, $line = null)
533
+	{
534
+		self::_add_notice('errors', $msg, $file, $func, $line);
535
+		self::$_error_count++;
536
+	}
537
+
538
+
539
+
540
+	/**
541
+	 * If WP_DEBUG is active, throws an exception. If WP_DEBUG is off, just
542
+	 * adds an error
543
+	 *
544
+	 * @param string $msg
545
+	 * @param string $file
546
+	 * @param string $func
547
+	 * @param string $line
548
+	 * @throws EE_Error
549
+	 */
550
+	public static function throw_exception_if_debugging($msg = null, $file = null, $func = null, $line = null)
551
+	{
552
+		if (WP_DEBUG) {
553
+			throw new EE_Error($msg);
554
+		}
555
+		EE_Error::add_error($msg, $file, $func, $line);
556
+	}
557
+
558
+
559
+
560
+	/**
561
+	 *    add success message
562
+	 *
563
+	 * @param        string $msg  the message to display to users or developers - adding a double pipe || (OR) creates
564
+	 *                            separate messages for user || dev
565
+	 * @param        string $file the file that the error occurred in - just use __FILE__
566
+	 * @param        string $func the function/method that the error occurred in - just use __FUNCTION__
567
+	 * @param        string $line the line number where the error occurred - just use __LINE__
568
+	 * @return        void
569
+	 */
570
+	public static function add_success($msg = null, $file = null, $func = null, $line = null)
571
+	{
572
+		self::_add_notice('success', $msg, $file, $func, $line);
573
+	}
574
+
575
+
576
+
577
+	/**
578
+	 *    add attention message
579
+	 *
580
+	 * @param        string $msg  the message to display to users or developers - adding a double pipe || (OR) creates
581
+	 *                            separate messages for user || dev
582
+	 * @param        string $file the file that the error occurred in - just use __FILE__
583
+	 * @param        string $func the function/method that the error occurred in - just use __FUNCTION__
584
+	 * @param        string $line the line number where the error occurred - just use __LINE__
585
+	 * @return        void
586
+	 */
587
+	public static function add_attention($msg = null, $file = null, $func = null, $line = null)
588
+	{
589
+		self::_add_notice('attention', $msg, $file, $func, $line);
590
+	}
591
+
592
+
593
+
594
+	/**
595
+	 *    add success message
596
+	 *
597
+	 * @param        string $type whether the message is for a success or error notification
598
+	 * @param        string $msg  the message to display to users or developers - adding a double pipe || (OR) creates
599
+	 *                            separate messages for user || dev
600
+	 * @param        string $file the file that the error occurred in - just use __FILE__
601
+	 * @param        string $func the function/method that the error occurred in - just use __FUNCTION__
602
+	 * @param        string $line the line number where the error occurred - just use __LINE__
603
+	 * @return        void
604
+	 */
605
+	private static function _add_notice($type = 'success', $msg = null, $file = null, $func = null, $line = null)
606
+	{
607
+		if (empty($msg)) {
608
+			EE_Error::doing_it_wrong(
609
+				'EE_Error::add_' . $type . '()',
610
+				sprintf(
611
+					__('Notifications are not much use without a message! Please add a message to the EE_Error::add_%s() call made in %s on line %d',
612
+						'event_espresso'),
613
+					$type,
614
+					$file,
615
+					$line
616
+				),
617
+				EVENT_ESPRESSO_VERSION
618
+			);
619
+		}
620
+		if ($type === 'errors' && (empty($file) || empty($func) || empty($line))) {
621
+			EE_Error::doing_it_wrong(
622
+				'EE_Error::add_error()',
623
+				__('You need to provide the file name, function name, and line number that the error occurred on in order to better assist with debugging.',
624
+					'event_espresso'),
625
+				EVENT_ESPRESSO_VERSION
626
+			);
627
+		}
628
+		// get separate user and developer messages if they exist
629
+		$msg = explode('||', $msg);
630
+		$user_msg = $msg[0];
631
+		$dev_msg = isset($msg[1]) ? $msg[1] : $msg[0];
632
+		/**
633
+		 * Do an action so other code can be triggered when a notice is created
634
+		 *
635
+		 * @param string $type     can be 'errors', 'attention', or 'success'
636
+		 * @param string $user_msg message displayed to user when WP_DEBUG is off
637
+		 * @param string $user_msg message displayed to user when WP_DEBUG is on
638
+		 * @param string $file     file where error was generated
639
+		 * @param string $func     function where error was generated
640
+		 * @param string $line     line where error was generated
641
+		 */
642
+		do_action('AHEE__EE_Error___add_notice', $type, $user_msg, $dev_msg, $file, $func, $line);
643
+		$msg = WP_DEBUG ? $dev_msg : $user_msg;
644
+		// add notice if message exists
645
+		if (! empty($msg)) {
646
+			// get error code
647
+			$notice_code = EE_Error::generate_error_code($file, $func, $line);
648
+			if (WP_DEBUG && $type === 'errors') {
649
+				$msg .= '<br/><span class="tiny-text">' . $notice_code . '</span>';
650
+			}
651
+			// add notice. Index by code if it's not blank
652
+			if ($notice_code) {
653
+				self::$_espresso_notices[$type][$notice_code] = $msg;
654
+			} else {
655
+				self::$_espresso_notices[$type][] = $msg;
656
+			}
657
+			add_action('wp_footer', array('EE_Error', 'enqueue_error_scripts'), 1);
658
+		}
659
+	}
660
+
661
+
662
+
663
+	/**
664
+	 *    in some case it may be necessary to overwrite the existing success messages
665
+	 *
666
+	 * @return        void
667
+	 */
668
+	public static function overwrite_success()
669
+	{
670
+		self::$_espresso_notices['success'] = false;
671
+	}
672
+
673
+
674
+
675
+	/**
676
+	 *    in some case it may be necessary to overwrite the existing attention messages
677
+	 *
678
+	 * @return        void
679
+	 */
680
+	public static function overwrite_attention()
681
+	{
682
+		self::$_espresso_notices['attention'] = false;
683
+	}
684
+
685
+
686
+
687
+	/**
688
+	 *    in some case it may be necessary to overwrite the existing error messages
689
+	 *
690
+	 * @return        void
691
+	 */
692
+	public static function overwrite_errors()
693
+	{
694
+		self::$_espresso_notices['errors'] = false;
695
+	}
696
+
697
+
698
+
699
+	/**
700
+	 *    reset_notices
701
+	 *
702
+	 * @return void
703
+	 */
704
+	public static function reset_notices()
705
+	{
706
+		self::$_espresso_notices['success'] = false;
707
+		self::$_espresso_notices['attention'] = false;
708
+		self::$_espresso_notices['errors'] = false;
709
+	}
710
+
711
+
712
+
713
+	/**
714
+	 *    has_errors
715
+	 *
716
+	 * @return int
717
+	 */
718
+	public static function has_notices()
719
+	{
720
+		$has_notices = 0;
721
+		// check for success messages
722
+		$has_notices = self::$_espresso_notices['success'] && ! empty(self::$_espresso_notices['success']) ? 3
723
+			: $has_notices;
724
+		// check for attention messages
725
+		$has_notices = self::$_espresso_notices['attention'] && ! empty(self::$_espresso_notices['attention']) ? 2
726
+			: $has_notices;
727
+		// check for error messages
728
+		$has_notices = self::$_espresso_notices['errors'] && ! empty(self::$_espresso_notices['errors']) ? 1
729
+			: $has_notices;
730
+		return $has_notices;
731
+	}
732
+
733
+
734
+
735
+	/**
736
+	 * This simply returns non formatted error notices as they were sent into the EE_Error object.
737
+	 *
738
+	 * @since 4.9.0
739
+	 * @return array
740
+	 */
741
+	public static function get_vanilla_notices()
742
+	{
743
+		return array(
744
+			'success'   => isset(self::$_espresso_notices['success']) ? self::$_espresso_notices['success'] : array(),
745
+			'attention' => isset(self::$_espresso_notices['attention']) ? self::$_espresso_notices['attention']
746
+				: array(),
747
+			'errors'    => isset(self::$_espresso_notices['errors']) ? self::$_espresso_notices['errors'] : array(),
748
+		);
749
+	}
750
+
751
+
752
+
753
+	/**
754
+	 *    compile all error or success messages into one string
755
+	 *
756
+	 * @see EE_Error::get_raw_notices if you want the raw notices without any preparations made to them
757
+	 * @param        boolean $format_output     whether or not to format the messages for display in the WP admin
758
+	 * @param        boolean $save_to_transient whether or not to save notices to the db for retrieval on next request
759
+	 *                                          - ONLY do this just before redirecting
760
+	 * @param        boolean $remove_empty      whether or not to unset empty messages
761
+	 * @return        array
762
+	 */
763
+	public static function get_notices($format_output = true, $save_to_transient = false, $remove_empty = true)
764
+	{
765
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
766
+		$success_messages = '';
767
+		$attention_messages = '';
768
+		$error_messages = '';
769
+		$print_scripts = false;
770
+		// either save notices to the db
771
+		if ($save_to_transient) {
772
+			update_option('ee_notices', self::$_espresso_notices);
773
+			return array();
774
+		}
775
+		// grab any notices that have been previously saved
776
+		if ($notices = get_option('ee_notices', false)) {
777
+			foreach ($notices as $type => $notice) {
778
+				if (is_array($notice) && ! empty($notice)) {
779
+					// make sure that existing notice type is an array
780
+					self::$_espresso_notices[$type] = is_array(self::$_espresso_notices[$type])
781
+													  && ! empty(self::$_espresso_notices[$type])
782
+						? self::$_espresso_notices[$type] : array();
783
+					// merge stored notices with any newly created ones
784
+					self::$_espresso_notices[$type] = array_merge(self::$_espresso_notices[$type], $notice);
785
+					$print_scripts = true;
786
+				}
787
+			}
788
+			// now clear any stored notices
789
+			update_option('ee_notices', false);
790
+		}
791
+		// check for success messages
792
+		if (self::$_espresso_notices['success'] && ! empty(self::$_espresso_notices['success'])) {
793
+			// combine messages
794
+			$success_messages .= implode(self::$_espresso_notices['success'], '<br /><br />');
795
+			$print_scripts = true;
796
+		}
797
+		// check for attention messages
798
+		if (self::$_espresso_notices['attention'] && ! empty(self::$_espresso_notices['attention'])) {
799
+			// combine messages
800
+			$attention_messages .= implode(self::$_espresso_notices['attention'], '<br /><br />');
801
+			$print_scripts = true;
802
+		}
803
+		// check for error messages
804
+		if (self::$_espresso_notices['errors'] && ! empty(self::$_espresso_notices['errors'])) {
805
+			$error_messages .= count(self::$_espresso_notices['errors']) > 1
806
+				? __('The following errors have occurred:<br />', 'event_espresso')
807
+				: __('An error has occurred:<br />', 'event_espresso');
808
+			// combine messages
809
+			$error_messages .= implode(self::$_espresso_notices['errors'], '<br /><br />');
810
+			$print_scripts = true;
811
+		}
812
+		if ($format_output) {
813
+			$notices = '<div id="espresso-notices">';
814
+			$close = is_admin() ? ''
815
+				: '<a class="close-espresso-notice hide-if-no-js"><span class="dashicons dashicons-no"></span></a>';
816
+			if ($success_messages !== '') {
817
+				$css_id = is_admin() ? 'message' : 'espresso-notices-success';
818
+				$css_class = is_admin() ? 'updated fade' : 'success fade-away';
819
+				//showMessage( $success_messages );
820
+				$notices .= '<div id="'
821
+							. $css_id
822
+							. '" class="espresso-notices '
823
+							. $css_class
824
+							. '" style="display:none;"><p>'
825
+							. $success_messages
826
+							. '</p>'
827
+							. $close
828
+							. '</div>';
829
+			}
830
+			if ($attention_messages !== '') {
831
+				$css_id = is_admin() ? 'message' : 'espresso-notices-attention';
832
+				$css_class = is_admin() ? 'updated ee-notices-attention' : 'attention fade-away';
833
+				//showMessage( $error_messages, TRUE );
834
+				$notices .= '<div id="'
835
+							. $css_id
836
+							. '" class="espresso-notices '
837
+							. $css_class
838
+							. '" style="display:none;"><p>'
839
+							. $attention_messages
840
+							. '</p>'
841
+							. $close
842
+							. '</div>';
843
+			}
844
+			if ($error_messages !== '') {
845
+				$css_id = is_admin() ? 'message' : 'espresso-notices-error';
846
+				$css_class = is_admin() ? 'error' : 'error fade-away';
847
+				//showMessage( $error_messages, TRUE );
848
+				$notices .= '<div id="'
849
+							. $css_id
850
+							. '" class="espresso-notices '
851
+							. $css_class
852
+							. '" style="display:none;"><p>'
853
+							. $error_messages
854
+							. '</p>'
855
+							. $close
856
+							. '</div>';
857
+			}
858
+			$notices .= '</div>';
859
+		} else {
860
+			$notices = array(
861
+				'success'   => $success_messages,
862
+				'attention' => $attention_messages,
863
+				'errors'    => $error_messages,
864
+			);
865
+			if ($remove_empty) {
866
+				// remove empty notices
867
+				foreach ($notices as $type => $notice) {
868
+					if (empty($notice)) {
869
+						unset($notices[$type]);
870
+					}
871
+				}
872
+			}
873
+		}
874
+		if ($print_scripts) {
875
+			self::_print_scripts();
876
+		}
877
+		return $notices;
878
+	}
879
+
880
+
881
+
882
+	/**
883
+	 *    add_persistent_admin_notice
884
+	 *
885
+	 * @param        string $pan_name     the name, or key of the Persistent Admin Notice to be stored
886
+	 * @param        string $pan_message  the message to be stored persistently until dismissed
887
+	 * @param bool          $force_update allows one to enforce the reappearance of a persistent message.
888
+	 * @return        void
889
+	 */
890
+	public static function add_persistent_admin_notice($pan_name = '', $pan_message, $force_update = false)
891
+	{
892
+		if (! empty($pan_name) && ! empty($pan_message)) {
893
+			$persistent_admin_notices = get_option('ee_pers_admin_notices', array());
894
+			//maybe initialize persistent_admin_notices
895
+			if (empty($persistent_admin_notices)) {
896
+				add_option('ee_pers_admin_notices', array(), '', 'no');
897
+			}
898
+			$pan_name = sanitize_key($pan_name);
899
+			if (! array_key_exists($pan_name, $persistent_admin_notices) || $force_update) {
900
+				$persistent_admin_notices[$pan_name] = $pan_message;
901
+				update_option('ee_pers_admin_notices', $persistent_admin_notices);
902
+			}
903
+		}
904
+	}
905
+
906
+
907
+
908
+	/**
909
+	 *    dismiss_persistent_admin_notice
910
+	 *
911
+	 * @param        string $pan_name the name, or key of the Persistent Admin Notice to be dismissed
912
+	 * @param bool          $purge
913
+	 * @param bool          $return_immediately
914
+	 * @return        void
915
+	 */
916
+	public static function dismiss_persistent_admin_notice($pan_name = '', $purge = false, $return_immediately = false)
917
+	{
918
+		$pan_name = EE_Registry::instance()->REQ->is_set('ee_nag_notice')
919
+			? EE_Registry::instance()->REQ->get('ee_nag_notice') : $pan_name;
920
+		if (! empty($pan_name)) {
921
+			$persistent_admin_notices = get_option('ee_pers_admin_notices', array());
922
+			// check if notice we wish to dismiss is actually in the $persistent_admin_notices array
923
+			if (is_array($persistent_admin_notices) && isset($persistent_admin_notices[$pan_name])) {
924
+				// completely delete nag notice, or just NULL message so that it can NOT be added again ?
925
+				if ($purge) {
926
+					unset($persistent_admin_notices[$pan_name]);
927
+				} else {
928
+					$persistent_admin_notices[$pan_name] = null;
929
+				}
930
+				if (update_option('ee_pers_admin_notices', $persistent_admin_notices) === false) {
931
+					EE_Error::add_error(sprintf(__('The persistent admin notice for "%s" could not be deleted.',
932
+						'event_espresso'), $pan_name), __FILE__, __FUNCTION__, __LINE__);
933
+				}
934
+			}
935
+		}
936
+		if ($return_immediately) {
937
+			return;
938
+		}
939
+		if (EE_Registry::instance()->REQ->ajax) {
940
+			// grab any notices and concatenate into string
941
+			echo wp_json_encode(array('errors' => implode('<br />', EE_Error::get_notices(false))));
942
+			exit();
943
+		}
944
+		// save errors to a transient to be displayed on next request (after redirect)
945
+		EE_Error::get_notices(false, true);
946
+		$return_url = EE_Registry::instance()->REQ->is_set('return_url')
947
+			? EE_Registry::instance()->REQ->get('return_url') : '';
948
+		wp_safe_redirect(urldecode($return_url));
949
+	}
950
+
951
+
952
+
953
+	/**
954
+	 * display_persistent_admin_notices
955
+	 *
956
+	 * @param  string $pan_name    the name, or key of the Persistent Admin Notice to be stored
957
+	 * @param  string $pan_message the message to be stored persistently until dismissed
958
+	 * @param  string $return_url  URL to go back to after nag notice is dismissed
959
+	 * @return string
960
+	 */
961
+	public static function display_persistent_admin_notices($pan_name = '', $pan_message = '', $return_url = '')
962
+	{
963
+		if (! empty($pan_name) && ! empty($pan_message)) {
964
+			$args = array(
965
+				'nag_notice'    => $pan_name,
966
+				'return_url'    => urlencode($return_url),
967
+				'ajax_url'      => WP_AJAX_URL,
968
+				'unknown_error' => esc_html__(
969
+					'An unknown error has occurred on the server while attempting to dismiss this notice.',
970
+					'event_espresso'
971
+				),
972
+			);
973
+			EE_Registry::$i18n_js_strings = array_merge(
974
+				EE_Registry::$i18n_js_strings,
975
+				array('ee_dismiss' => $args)
976
+			);
977
+			return '
978 978
 			<div id="'
979
-                   . $pan_name
980
-                   . '" class="espresso-notices updated ee-nag-notice clearfix" style="border-left: 4px solid #fcb93c;">
979
+				   . $pan_name
980
+				   . '" class="espresso-notices updated ee-nag-notice clearfix" style="border-left: 4px solid #fcb93c;">
981 981
 				<p>'
982
-                   . $pan_message
983
-                   . '</p>
982
+				   . $pan_message
983
+				   . '</p>
984 984
 				<a class="dismiss-ee-nag-notice hide-if-no-js" style="float: right; cursor: pointer; text-decoration:none;" rel="'
985
-                   . $pan_name
986
-                   . '">
985
+				   . $pan_name
986
+				   . '">
987 987
 					<span class="dashicons dashicons-dismiss" style="position:relative; top:-1px; margin-right:.25em;"></span>'
988
-                   . __('Dismiss', 'event_espresso')
989
-                   . '
988
+				   . __('Dismiss', 'event_espresso')
989
+				   . '
990 990
 				</a>
991 991
 				<div style="clear:both;"></div>
992 992
 			</div>';
993
-        }
994
-        return '';
995
-    }
996
-
997
-
998
-
999
-    /**
1000
-     *    get_persistent_admin_notices
1001
-     *
1002
-     * @param string $return_url
1003
-     * @return string
1004
-     */
1005
-    public static function get_persistent_admin_notices($return_url = '')
1006
-    {
1007
-        $notices = '';
1008
-        // check for persistent admin notices
1009
-        //filter the list though so plugins can notify the admin in a different way if they want
1010
-        $persistent_admin_notices = apply_filters(
1011
-            'FHEE__EE_Error__get_persistent_admin_notices',
1012
-            get_option('ee_pers_admin_notices', false),
1013
-            'ee_pers_admin_notices',
1014
-            $return_url
1015
-        );
1016
-        if ($persistent_admin_notices) {
1017
-            // load scripts
1018
-            wp_register_script(
1019
-                'espresso_core',
1020
-                EE_GLOBAL_ASSETS_URL . 'scripts/espresso_core.js',
1021
-                array('jquery'),
1022
-                EVENT_ESPRESSO_VERSION,
1023
-                true
1024
-            );
1025
-            wp_register_script(
1026
-                'ee_error_js',
1027
-                EE_GLOBAL_ASSETS_URL . 'scripts/EE_Error.js',
1028
-                array('espresso_core'),
1029
-                EVENT_ESPRESSO_VERSION,
1030
-                true
1031
-            );
1032
-            wp_enqueue_script('ee_error_js');
1033
-            // and display notices
1034
-            foreach ($persistent_admin_notices as $pan_name => $pan_message) {
1035
-                $notices .= self::display_persistent_admin_notices($pan_name, $pan_message, $return_url);
1036
-            }
1037
-        }
1038
-        return $notices;
1039
-    }
1040
-
1041
-
1042
-
1043
-    /**
1044
-     * _print_scripts
1045
-     *
1046
-     * @param    bool $force_print
1047
-     * @return    string
1048
-     */
1049
-    private static function _print_scripts($force_print = false)
1050
-    {
1051
-        if (! $force_print && (did_action('admin_enqueue_scripts') || did_action('wp_enqueue_scripts'))) {
1052
-            if (wp_script_is('ee_error_js', 'enqueued')) {
1053
-                return '';
1054
-            }
1055
-            if (wp_script_is('ee_error_js', 'registered')) {
1056
-                wp_enqueue_style('espresso_default');
1057
-                wp_enqueue_style('espresso_custom_css');
1058
-                wp_enqueue_script('ee_error_js');
1059
-                wp_localize_script('ee_error_js', 'ee_settings', array('wp_debug' => WP_DEBUG));
1060
-            }
1061
-        } else {
1062
-            return '
993
+		}
994
+		return '';
995
+	}
996
+
997
+
998
+
999
+	/**
1000
+	 *    get_persistent_admin_notices
1001
+	 *
1002
+	 * @param string $return_url
1003
+	 * @return string
1004
+	 */
1005
+	public static function get_persistent_admin_notices($return_url = '')
1006
+	{
1007
+		$notices = '';
1008
+		// check for persistent admin notices
1009
+		//filter the list though so plugins can notify the admin in a different way if they want
1010
+		$persistent_admin_notices = apply_filters(
1011
+			'FHEE__EE_Error__get_persistent_admin_notices',
1012
+			get_option('ee_pers_admin_notices', false),
1013
+			'ee_pers_admin_notices',
1014
+			$return_url
1015
+		);
1016
+		if ($persistent_admin_notices) {
1017
+			// load scripts
1018
+			wp_register_script(
1019
+				'espresso_core',
1020
+				EE_GLOBAL_ASSETS_URL . 'scripts/espresso_core.js',
1021
+				array('jquery'),
1022
+				EVENT_ESPRESSO_VERSION,
1023
+				true
1024
+			);
1025
+			wp_register_script(
1026
+				'ee_error_js',
1027
+				EE_GLOBAL_ASSETS_URL . 'scripts/EE_Error.js',
1028
+				array('espresso_core'),
1029
+				EVENT_ESPRESSO_VERSION,
1030
+				true
1031
+			);
1032
+			wp_enqueue_script('ee_error_js');
1033
+			// and display notices
1034
+			foreach ($persistent_admin_notices as $pan_name => $pan_message) {
1035
+				$notices .= self::display_persistent_admin_notices($pan_name, $pan_message, $return_url);
1036
+			}
1037
+		}
1038
+		return $notices;
1039
+	}
1040
+
1041
+
1042
+
1043
+	/**
1044
+	 * _print_scripts
1045
+	 *
1046
+	 * @param    bool $force_print
1047
+	 * @return    string
1048
+	 */
1049
+	private static function _print_scripts($force_print = false)
1050
+	{
1051
+		if (! $force_print && (did_action('admin_enqueue_scripts') || did_action('wp_enqueue_scripts'))) {
1052
+			if (wp_script_is('ee_error_js', 'enqueued')) {
1053
+				return '';
1054
+			}
1055
+			if (wp_script_is('ee_error_js', 'registered')) {
1056
+				wp_enqueue_style('espresso_default');
1057
+				wp_enqueue_style('espresso_custom_css');
1058
+				wp_enqueue_script('ee_error_js');
1059
+				wp_localize_script('ee_error_js', 'ee_settings', array('wp_debug' => WP_DEBUG));
1060
+			}
1061
+		} else {
1062
+			return '
1063 1063
 <script>
1064 1064
 /* <![CDATA[ */
1065 1065
 var ee_settings = {"wp_debug":"' . WP_DEBUG . '"};
@@ -1069,143 +1069,143 @@  discard block
 block discarded – undo
1069 1069
 <script src="' . EE_GLOBAL_ASSETS_URL . 'scripts/espresso_core.js' . '?ver=' . espresso_version() . '" type="text/javascript"></script>
1070 1070
 <script src="' . EE_GLOBAL_ASSETS_URL . 'scripts/EE_Error.js' . '?ver=' . espresso_version() . '" type="text/javascript"></script>
1071 1071
 ';
1072
-        }
1073
-        return '';
1074
-    }
1075
-
1076
-
1077
-
1078
-    /**
1079
-     *    enqueue_error_scripts
1080
-     *
1081
-     * @return        void
1082
-     */
1083
-    public static function enqueue_error_scripts()
1084
-    {
1085
-        self::_print_scripts();
1086
-    }
1087
-
1088
-
1089
-
1090
-    /**
1091
-     *    create error code from filepath, function name,
1092
-     *    and line number where exception or error was thrown
1093
-     *
1094
-     * @param string $file
1095
-     * @param string $func
1096
-     * @param string $line
1097
-     * @return string
1098
-     */
1099
-    public static function generate_error_code($file = '', $func = '', $line = '')
1100
-    {
1101
-        $file = explode('.', basename($file));
1102
-        $error_code = ! empty($file[0]) ? $file[0] : '';
1103
-        $error_code .= ! empty($func) ? ' - ' . $func : '';
1104
-        $error_code .= ! empty($line) ? ' - ' . $line : '';
1105
-        return $error_code;
1106
-    }
1107
-
1108
-
1109
-
1110
-    /**
1111
-     *    write exception details to log file
1112
-     *
1113
-     * @param int   $time
1114
-     * @param array $ex
1115
-     * @param bool  $clear
1116
-     * @return void
1117
-     */
1118
-    public function write_to_error_log($time = 0, $ex = array(), $clear = false)
1119
-    {
1120
-        if (empty($ex)) {
1121
-            return;
1122
-        }
1123
-        if (! $time) {
1124
-            $time = time();
1125
-        }
1126
-        $exception_log = '----------------------------------------------------------------------------------------'
1127
-                         . PHP_EOL;
1128
-        $exception_log .= '[' . date('Y-m-d H:i:s', $time) . ']  Exception Details' . PHP_EOL;
1129
-        $exception_log .= 'Message: ' . $ex['msg'] . PHP_EOL;
1130
-        $exception_log .= 'Code: ' . $ex['code'] . PHP_EOL;
1131
-        $exception_log .= 'File: ' . $ex['file'] . PHP_EOL;
1132
-        $exception_log .= 'Line No: ' . $ex['line'] . PHP_EOL;
1133
-        $exception_log .= 'Stack trace: ' . PHP_EOL;
1134
-        $exception_log .= $ex['string'] . PHP_EOL;
1135
-        $exception_log .= '----------------------------------------------------------------------------------------'
1136
-                          . PHP_EOL;
1137
-        try {
1138
-            EEH_File::ensure_file_exists_and_is_writable(
1139
-                EVENT_ESPRESSO_UPLOAD_DIR . 'logs' . DS . self::$_exception_log_file
1140
-            );
1141
-            EEH_File::add_htaccess_deny_from_all(EVENT_ESPRESSO_UPLOAD_DIR . 'logs');
1142
-            if (! $clear) {
1143
-                //get existing log file and append new log info
1144
-                $exception_log = EEH_File::get_file_contents(
1145
-                    EVENT_ESPRESSO_UPLOAD_DIR . 'logs' . DS . self::$_exception_log_file
1146
-                ) . $exception_log;
1147
-            }
1148
-            EEH_File::write_to_file(
1149
-                EVENT_ESPRESSO_UPLOAD_DIR . 'logs' . DS . self::$_exception_log_file,
1150
-                $exception_log
1151
-            );
1152
-        } catch (EE_Error $e) {
1153
-            EE_Error::add_error(sprintf(__('Event Espresso error logging could not be setup because: %s',
1154
-                'event_espresso'), $e->getMessage()));
1155
-            return;
1156
-        }
1157
-    }
1158
-
1159
-
1160
-
1161
-    /**
1162
-     * This is just a wrapper for the EEH_Debug_Tools::instance()->doing_it_wrong() method.
1163
-     * doing_it_wrong() is used in those cases where a normal PHP error won't get thrown,
1164
-     * but the code execution is done in a manner that could lead to unexpected results
1165
-     * (i.e. running to early, or too late in WP or EE loading process).
1166
-     * A good test for knowing whether to use this method is:
1167
-     * 1. Is there going to be a PHP error if something isn't setup/used correctly?
1168
-     * Yes -> use EE_Error::add_error() or throw new EE_Error()
1169
-     * 2. If this is loaded before something else, it won't break anything,
1170
-     * but just wont' do what its supposed to do? Yes -> use EE_Error::doing_it_wrong()
1171
-     *
1172
-     * @uses   constant WP_DEBUG test if wp_debug is on or not
1173
-     * @param string $function      The function that was called
1174
-     * @param string $message       A message explaining what has been done incorrectly
1175
-     * @param string $version       The version of Event Espresso where the error was added
1176
-     * @param string $applies_when  a version string for when you want the doing_it_wrong notice to begin appearing
1177
-     *                              for a deprecated function. This allows deprecation to occur during one version,
1178
-     *                              but not have any notices appear until a later version. This allows developers
1179
-     *                              extra time to update their code before notices appear.
1180
-     * @param int    $error_type
1181
-     */
1182
-    public static function doing_it_wrong(
1183
-        $function,
1184
-        $message,
1185
-        $version,
1186
-        $applies_when = '',
1187
-        $error_type = null
1188
-    ) {
1189
-        if (defined('WP_DEBUG') && WP_DEBUG) {
1190
-            EEH_Debug_Tools::instance()->doing_it_wrong($function, $message, $version, $applies_when, $error_type);
1191
-        }
1192
-    }
1193
-
1194
-
1195
-
1196
-    /**
1197
-     * Like get_notices, but returns an array of all the notices of the given type.
1198
-     *
1199
-     * @return array {
1200
-     * @type array $success   all the success messages
1201
-     * @type array $errors    all the error messages
1202
-     * @type array $attention all the attention messages
1203
-     * }
1204
-     */
1205
-    public static function get_raw_notices()
1206
-    {
1207
-        return self::$_espresso_notices;
1208
-    }
1072
+		}
1073
+		return '';
1074
+	}
1075
+
1076
+
1077
+
1078
+	/**
1079
+	 *    enqueue_error_scripts
1080
+	 *
1081
+	 * @return        void
1082
+	 */
1083
+	public static function enqueue_error_scripts()
1084
+	{
1085
+		self::_print_scripts();
1086
+	}
1087
+
1088
+
1089
+
1090
+	/**
1091
+	 *    create error code from filepath, function name,
1092
+	 *    and line number where exception or error was thrown
1093
+	 *
1094
+	 * @param string $file
1095
+	 * @param string $func
1096
+	 * @param string $line
1097
+	 * @return string
1098
+	 */
1099
+	public static function generate_error_code($file = '', $func = '', $line = '')
1100
+	{
1101
+		$file = explode('.', basename($file));
1102
+		$error_code = ! empty($file[0]) ? $file[0] : '';
1103
+		$error_code .= ! empty($func) ? ' - ' . $func : '';
1104
+		$error_code .= ! empty($line) ? ' - ' . $line : '';
1105
+		return $error_code;
1106
+	}
1107
+
1108
+
1109
+
1110
+	/**
1111
+	 *    write exception details to log file
1112
+	 *
1113
+	 * @param int   $time
1114
+	 * @param array $ex
1115
+	 * @param bool  $clear
1116
+	 * @return void
1117
+	 */
1118
+	public function write_to_error_log($time = 0, $ex = array(), $clear = false)
1119
+	{
1120
+		if (empty($ex)) {
1121
+			return;
1122
+		}
1123
+		if (! $time) {
1124
+			$time = time();
1125
+		}
1126
+		$exception_log = '----------------------------------------------------------------------------------------'
1127
+						 . PHP_EOL;
1128
+		$exception_log .= '[' . date('Y-m-d H:i:s', $time) . ']  Exception Details' . PHP_EOL;
1129
+		$exception_log .= 'Message: ' . $ex['msg'] . PHP_EOL;
1130
+		$exception_log .= 'Code: ' . $ex['code'] . PHP_EOL;
1131
+		$exception_log .= 'File: ' . $ex['file'] . PHP_EOL;
1132
+		$exception_log .= 'Line No: ' . $ex['line'] . PHP_EOL;
1133
+		$exception_log .= 'Stack trace: ' . PHP_EOL;
1134
+		$exception_log .= $ex['string'] . PHP_EOL;
1135
+		$exception_log .= '----------------------------------------------------------------------------------------'
1136
+						  . PHP_EOL;
1137
+		try {
1138
+			EEH_File::ensure_file_exists_and_is_writable(
1139
+				EVENT_ESPRESSO_UPLOAD_DIR . 'logs' . DS . self::$_exception_log_file
1140
+			);
1141
+			EEH_File::add_htaccess_deny_from_all(EVENT_ESPRESSO_UPLOAD_DIR . 'logs');
1142
+			if (! $clear) {
1143
+				//get existing log file and append new log info
1144
+				$exception_log = EEH_File::get_file_contents(
1145
+					EVENT_ESPRESSO_UPLOAD_DIR . 'logs' . DS . self::$_exception_log_file
1146
+				) . $exception_log;
1147
+			}
1148
+			EEH_File::write_to_file(
1149
+				EVENT_ESPRESSO_UPLOAD_DIR . 'logs' . DS . self::$_exception_log_file,
1150
+				$exception_log
1151
+			);
1152
+		} catch (EE_Error $e) {
1153
+			EE_Error::add_error(sprintf(__('Event Espresso error logging could not be setup because: %s',
1154
+				'event_espresso'), $e->getMessage()));
1155
+			return;
1156
+		}
1157
+	}
1158
+
1159
+
1160
+
1161
+	/**
1162
+	 * This is just a wrapper for the EEH_Debug_Tools::instance()->doing_it_wrong() method.
1163
+	 * doing_it_wrong() is used in those cases where a normal PHP error won't get thrown,
1164
+	 * but the code execution is done in a manner that could lead to unexpected results
1165
+	 * (i.e. running to early, or too late in WP or EE loading process).
1166
+	 * A good test for knowing whether to use this method is:
1167
+	 * 1. Is there going to be a PHP error if something isn't setup/used correctly?
1168
+	 * Yes -> use EE_Error::add_error() or throw new EE_Error()
1169
+	 * 2. If this is loaded before something else, it won't break anything,
1170
+	 * but just wont' do what its supposed to do? Yes -> use EE_Error::doing_it_wrong()
1171
+	 *
1172
+	 * @uses   constant WP_DEBUG test if wp_debug is on or not
1173
+	 * @param string $function      The function that was called
1174
+	 * @param string $message       A message explaining what has been done incorrectly
1175
+	 * @param string $version       The version of Event Espresso where the error was added
1176
+	 * @param string $applies_when  a version string for when you want the doing_it_wrong notice to begin appearing
1177
+	 *                              for a deprecated function. This allows deprecation to occur during one version,
1178
+	 *                              but not have any notices appear until a later version. This allows developers
1179
+	 *                              extra time to update their code before notices appear.
1180
+	 * @param int    $error_type
1181
+	 */
1182
+	public static function doing_it_wrong(
1183
+		$function,
1184
+		$message,
1185
+		$version,
1186
+		$applies_when = '',
1187
+		$error_type = null
1188
+	) {
1189
+		if (defined('WP_DEBUG') && WP_DEBUG) {
1190
+			EEH_Debug_Tools::instance()->doing_it_wrong($function, $message, $version, $applies_when, $error_type);
1191
+		}
1192
+	}
1193
+
1194
+
1195
+
1196
+	/**
1197
+	 * Like get_notices, but returns an array of all the notices of the given type.
1198
+	 *
1199
+	 * @return array {
1200
+	 * @type array $success   all the success messages
1201
+	 * @type array $errors    all the error messages
1202
+	 * @type array $attention all the attention messages
1203
+	 * }
1204
+	 */
1205
+	public static function get_raw_notices()
1206
+	{
1207
+		return self::$_espresso_notices;
1208
+	}
1209 1209
 
1210 1210
 
1211 1211
 
@@ -1221,27 +1221,27 @@  discard block
 block discarded – undo
1221 1221
  */
1222 1222
 function espresso_error_enqueue_scripts()
1223 1223
 {
1224
-    // js for error handling
1225
-    wp_register_script(
1226
-        'espresso_core',
1227
-        EE_GLOBAL_ASSETS_URL . 'scripts/espresso_core.js',
1228
-        array('jquery'),
1229
-        EVENT_ESPRESSO_VERSION,
1230
-        false
1231
-    );
1232
-    wp_register_script(
1233
-        'ee_error_js',
1234
-        EE_GLOBAL_ASSETS_URL . 'scripts/EE_Error.js',
1235
-        array('espresso_core'),
1236
-        EVENT_ESPRESSO_VERSION,
1237
-        false
1238
-    );
1224
+	// js for error handling
1225
+	wp_register_script(
1226
+		'espresso_core',
1227
+		EE_GLOBAL_ASSETS_URL . 'scripts/espresso_core.js',
1228
+		array('jquery'),
1229
+		EVENT_ESPRESSO_VERSION,
1230
+		false
1231
+	);
1232
+	wp_register_script(
1233
+		'ee_error_js',
1234
+		EE_GLOBAL_ASSETS_URL . 'scripts/EE_Error.js',
1235
+		array('espresso_core'),
1236
+		EVENT_ESPRESSO_VERSION,
1237
+		false
1238
+	);
1239 1239
 }
1240 1240
 
1241 1241
 if (is_admin()) {
1242
-    add_action('admin_enqueue_scripts', 'espresso_error_enqueue_scripts', 2);
1242
+	add_action('admin_enqueue_scripts', 'espresso_error_enqueue_scripts', 2);
1243 1243
 } else {
1244
-    add_action('wp_enqueue_scripts', 'espresso_error_enqueue_scripts', 2);
1244
+	add_action('wp_enqueue_scripts', 'espresso_error_enqueue_scripts', 2);
1245 1245
 }
1246 1246
 
1247 1247
 
Please login to merge, or discard this patch.
core/EE_Dependency_Map.core.php 2 patches
Spacing   +22 added lines, -22 removed lines patch added patch discarded remove patch
@@ -3,7 +3,7 @@  discard block
 block discarded – undo
3 3
 use EventEspresso\core\exceptions\InvalidInterfaceException;
4 4
 use EventEspresso\core\services\loaders\LoaderInterface;
5 5
 
6
-if (! defined('EVENT_ESPRESSO_VERSION')) {
6
+if ( ! defined('EVENT_ESPRESSO_VERSION')) {
7 7
     exit('No direct script access allowed');
8 8
 }
9 9
 
@@ -129,7 +129,7 @@  discard block
 block discarded – undo
129 129
     public static function instance(EE_Request $request = null, EE_Response $response = null)
130 130
     {
131 131
         // check if class object is instantiated, and instantiated properly
132
-        if (! self::$_instance instanceof EE_Dependency_Map) {
132
+        if ( ! self::$_instance instanceof EE_Dependency_Map) {
133 133
             self::$_instance = new EE_Dependency_Map($request, $response);
134 134
         }
135 135
         return self::$_instance;
@@ -184,16 +184,16 @@  discard block
 block discarded – undo
184 184
     ) {
185 185
         $class = trim($class, '\\');
186 186
         $registered = false;
187
-        if (empty(self::$_instance->_dependency_map[ $class ])) {
188
-            self::$_instance->_dependency_map[ $class ] = array();
187
+        if (empty(self::$_instance->_dependency_map[$class])) {
188
+            self::$_instance->_dependency_map[$class] = array();
189 189
         }
190 190
         // we need to make sure that any aliases used when registering a dependency
191 191
         // get resolved to the correct class name
192
-        foreach ((array)$dependencies as $dependency => $load_source) {
192
+        foreach ((array) $dependencies as $dependency => $load_source) {
193 193
             $alias = self::$_instance->get_alias($dependency);
194 194
             if (
195 195
                 $overwrite === EE_Dependency_Map::OVERWRITE_DEPENDENCIES
196
-                || ! isset(self::$_instance->_dependency_map[ $class ][ $alias ])
196
+                || ! isset(self::$_instance->_dependency_map[$class][$alias])
197 197
             ) {
198 198
                 unset($dependencies[$dependency]);
199 199
                 $dependencies[$alias] = $load_source;
@@ -206,13 +206,13 @@  discard block
 block discarded – undo
206 206
         // ie: with A = B + C, entries in B take precedence over duplicate entries in C
207 207
         // Union is way faster than array_merge() but should be used with caution...
208 208
         // especially with numerically indexed arrays
209
-        $dependencies += self::$_instance->_dependency_map[ $class ];
209
+        $dependencies += self::$_instance->_dependency_map[$class];
210 210
         // now we need to ensure that the resulting dependencies
211 211
         // array only has the entries that are required for the class
212 212
         // so first count how many dependencies were originally registered for the class
213
-        $dependency_count = count(self::$_instance->_dependency_map[ $class ]);
213
+        $dependency_count = count(self::$_instance->_dependency_map[$class]);
214 214
         // if that count is non-zero (meaning dependencies were already registered)
215
-        self::$_instance->_dependency_map[ $class ] = $dependency_count
215
+        self::$_instance->_dependency_map[$class] = $dependency_count
216 216
             // then truncate the  final array to match that count
217 217
             ? array_slice($dependencies, 0, $dependency_count)
218 218
             // otherwise just take the incoming array because nothing previously existed
@@ -230,7 +230,7 @@  discard block
 block discarded – undo
230 230
      */
231 231
     public static function register_class_loader($class_name, $loader = 'load_core')
232 232
     {
233
-        if (! $loader instanceof Closure && strpos($class_name, '\\') !== false) {
233
+        if ( ! $loader instanceof Closure && strpos($class_name, '\\') !== false) {
234 234
             throw new DomainException(
235 235
                 esc_html__('Don\'t use class loaders for FQCNs.', 'event_espresso')
236 236
             );
@@ -254,7 +254,7 @@  discard block
 block discarded – undo
254 254
             );
255 255
         }
256 256
         $class_name = self::$_instance->get_alias($class_name);
257
-        if (! isset(self::$_instance->_class_loaders[$class_name])) {
257
+        if ( ! isset(self::$_instance->_class_loaders[$class_name])) {
258 258
             self::$_instance->_class_loaders[$class_name] = $loader;
259 259
             return true;
260 260
         }
@@ -352,7 +352,7 @@  discard block
 block discarded – undo
352 352
     public function add_alias($class_name, $alias, $for_class = '')
353 353
     {
354 354
         if ($for_class !== '') {
355
-            if (! isset($this->_aliases[$for_class])) {
355
+            if ( ! isset($this->_aliases[$for_class])) {
356 356
                 $this->_aliases[$for_class] = array();
357 357
             }
358 358
             $this->_aliases[$for_class][$class_name] = $alias;
@@ -398,10 +398,10 @@  discard block
 block discarded – undo
398 398
      */
399 399
     public function get_alias($class_name = '', $for_class = '')
400 400
     {
401
-        if (! $this->has_alias($class_name, $for_class)) {
401
+        if ( ! $this->has_alias($class_name, $for_class)) {
402 402
             return $class_name;
403 403
         }
404
-        if ($for_class !== '' && isset($this->_aliases[ $for_class ][ $class_name ])) {
404
+        if ($for_class !== '' && isset($this->_aliases[$for_class][$class_name])) {
405 405
             return $this->get_alias($this->_aliases[$for_class][$class_name], $for_class);
406 406
         }
407 407
         return $this->get_alias($this->_aliases[$class_name]);
@@ -636,10 +636,10 @@  discard block
 block discarded – undo
636 636
             'EE_Front_Controller'                  => 'load_core',
637 637
             'EE_Module_Request_Router'             => 'load_core',
638 638
             'EE_Registry'                          => 'load_core',
639
-            'EE_Request'                           => function () use (&$request) {
639
+            'EE_Request'                           => function() use (&$request) {
640 640
                 return $request;
641 641
             },
642
-            'EE_Response'                          => function () use (&$response) {
642
+            'EE_Response'                          => function() use (&$response) {
643 643
                 return $response;
644 644
             },
645 645
             'EE_Request_Handler'                   => 'load_core',
@@ -655,7 +655,7 @@  discard block
 block discarded – undo
655 655
             'EE_Messages_Queue'                    => 'load_lib',
656 656
             'EE_Messages_Data_Handler_Collection'  => 'load_lib',
657 657
             'EE_Message_Template_Group_Collection' => 'load_lib',
658
-            'EE_Messages_Generator'                => function () {
658
+            'EE_Messages_Generator'                => function() {
659 659
                 return EE_Registry::instance()->load_lib(
660 660
                     'Messages_Generator',
661 661
                     array(),
@@ -663,7 +663,7 @@  discard block
 block discarded – undo
663 663
                     false
664 664
                 );
665 665
             },
666
-            'EE_Messages_Template_Defaults'        => function ($arguments = array()) {
666
+            'EE_Messages_Template_Defaults'        => function($arguments = array()) {
667 667
                 return EE_Registry::instance()->load_lib(
668 668
                     'Messages_Template_Defaults',
669 669
                     $arguments,
@@ -676,19 +676,19 @@  discard block
 block discarded – undo
676 676
             'EEM_Message_Template_Group'           => 'load_model',
677 677
             'EEM_Message_Template'                 => 'load_model',
678 678
             //load_helper
679
-            'EEH_Parse_Shortcodes'                 => function () {
679
+            'EEH_Parse_Shortcodes'                 => function() {
680 680
                 if (EE_Registry::instance()->load_helper('Parse_Shortcodes')) {
681 681
                     return new EEH_Parse_Shortcodes();
682 682
                 }
683 683
                 return null;
684 684
             },
685
-            'EE_Template_Config'                   => function () {
685
+            'EE_Template_Config'                   => function() {
686 686
                 return EE_Config::instance()->template_settings;
687 687
             },
688
-            'EE_Currency_Config'                   => function () {
688
+            'EE_Currency_Config'                   => function() {
689 689
                 return EE_Config::instance()->currency;
690 690
             },
691
-            'EventEspresso\core\services\loaders\Loader' => function () use (&$loader) {
691
+            'EventEspresso\core\services\loaders\Loader' => function() use (&$loader) {
692 692
                 return $loader;
693 693
             },
694 694
         );
Please login to merge, or discard this patch.
Indentation   +758 added lines, -758 removed lines patch added patch discarded remove patch
@@ -4,7 +4,7 @@  discard block
 block discarded – undo
4 4
 use EventEspresso\core\services\loaders\LoaderInterface;
5 5
 
6 6
 if (! defined('EVENT_ESPRESSO_VERSION')) {
7
-    exit('No direct script access allowed');
7
+	exit('No direct script access allowed');
8 8
 }
9 9
 
10 10
 
@@ -21,763 +21,763 @@  discard block
 block discarded – undo
21 21
 class EE_Dependency_Map
22 22
 {
23 23
 
24
-    /**
25
-     * This means that the requested class dependency is not present in the dependency map
26
-     */
27
-    const not_registered = 0;
28
-
29
-    /**
30
-     * This instructs class loaders to ALWAYS return a newly instantiated object for the requested class.
31
-     */
32
-    const load_new_object = 1;
33
-
34
-    /**
35
-     * This instructs class loaders to return a previously instantiated and cached object for the requested class.
36
-     * IF a previously instantiated object does not exist, a new one will be created and added to the cache.
37
-     */
38
-    const load_from_cache = 2;
39
-
40
-    /**
41
-     * When registering a dependency,
42
-     * this indicates to keep any existing dependencies that already exist,
43
-     * and simply discard any new dependencies declared in the incoming data
44
-     */
45
-    const KEEP_EXISTING_DEPENDENCIES = 0;
46
-
47
-    /**
48
-     * When registering a dependency,
49
-     * this indicates to overwrite any existing dependencies that already exist using the incoming data
50
-     */
51
-    const OVERWRITE_DEPENDENCIES = 1;
52
-
53
-
54
-
55
-    /**
56
-     * @type EE_Dependency_Map $_instance
57
-     */
58
-    protected static $_instance;
59
-
60
-    /**
61
-     * @type EE_Request $request
62
-     */
63
-    protected $_request;
64
-
65
-    /**
66
-     * @type EE_Response $response
67
-     */
68
-    protected $_response;
69
-
70
-    /**
71
-     * @type LoaderInterface $loader
72
-     */
73
-    protected $loader;
74
-
75
-    /**
76
-     * @type array $_dependency_map
77
-     */
78
-    protected $_dependency_map = array();
79
-
80
-    /**
81
-     * @type array $_class_loaders
82
-     */
83
-    protected $_class_loaders = array();
84
-
85
-    /**
86
-     * @type array $_aliases
87
-     */
88
-    protected $_aliases = array();
89
-
90
-
91
-
92
-    /**
93
-     * EE_Dependency_Map constructor.
94
-     *
95
-     * @param EE_Request  $request
96
-     * @param EE_Response $response
97
-     */
98
-    protected function __construct(EE_Request $request, EE_Response $response)
99
-    {
100
-        $this->_request = $request;
101
-        $this->_response = $response;
102
-        add_action('EE_Load_Espresso_Core__handle_request__initialize_core_loading', array($this, 'initialize'));
103
-        do_action('EE_Dependency_Map____construct');
104
-    }
105
-
106
-
107
-
108
-    /**
109
-     * @throws InvalidDataTypeException
110
-     * @throws InvalidInterfaceException
111
-     * @throws InvalidArgumentException
112
-     */
113
-    public function initialize()
114
-    {
115
-        $this->_register_core_dependencies();
116
-        $this->_register_core_class_loaders();
117
-        $this->_register_core_aliases();
118
-    }
119
-
120
-
121
-
122
-    /**
123
-     * @singleton method used to instantiate class object
124
-     * @access    public
125
-     * @param EE_Request  $request
126
-     * @param EE_Response $response
127
-     * @return EE_Dependency_Map
128
-     */
129
-    public static function instance(EE_Request $request = null, EE_Response $response = null)
130
-    {
131
-        // check if class object is instantiated, and instantiated properly
132
-        if (! self::$_instance instanceof EE_Dependency_Map) {
133
-            self::$_instance = new EE_Dependency_Map($request, $response);
134
-        }
135
-        return self::$_instance;
136
-    }
137
-
138
-
139
-
140
-    /**
141
-     * @param LoaderInterface $loader
142
-     */
143
-    public function setLoader(LoaderInterface $loader)
144
-    {
145
-        $this->loader = $loader;
146
-    }
147
-
148
-
149
-
150
-    /**
151
-     * @param string $class
152
-     * @param array  $dependencies
153
-     * @param int    $overwrite
154
-     * @return bool
155
-     */
156
-    public static function register_dependencies(
157
-        $class,
158
-        array $dependencies,
159
-        $overwrite = EE_Dependency_Map::KEEP_EXISTING_DEPENDENCIES
160
-    ) {
161
-        return self::$_instance->registerDependencies($class, $dependencies, $overwrite);
162
-    }
163
-
164
-
165
-
166
-    /**
167
-     * Assigns an array of class names and corresponding load sources (new or cached)
168
-     * to the class specified by the first parameter.
169
-     * IMPORTANT !!!
170
-     * The order of elements in the incoming $dependencies array MUST match
171
-     * the order of the constructor parameters for the class in question.
172
-     * This is especially important when overriding any existing dependencies that are registered.
173
-     * the third parameter controls whether any duplicate dependencies are overwritten or not.
174
-     *
175
-     * @param string $class
176
-     * @param array  $dependencies
177
-     * @param int    $overwrite
178
-     * @return bool
179
-     */
180
-    public function registerDependencies(
181
-        $class,
182
-        array $dependencies,
183
-        $overwrite = EE_Dependency_Map::KEEP_EXISTING_DEPENDENCIES
184
-    ) {
185
-        $class = trim($class, '\\');
186
-        $registered = false;
187
-        if (empty(self::$_instance->_dependency_map[ $class ])) {
188
-            self::$_instance->_dependency_map[ $class ] = array();
189
-        }
190
-        // we need to make sure that any aliases used when registering a dependency
191
-        // get resolved to the correct class name
192
-        foreach ((array)$dependencies as $dependency => $load_source) {
193
-            $alias = self::$_instance->get_alias($dependency);
194
-            if (
195
-                $overwrite === EE_Dependency_Map::OVERWRITE_DEPENDENCIES
196
-                || ! isset(self::$_instance->_dependency_map[ $class ][ $alias ])
197
-            ) {
198
-                unset($dependencies[$dependency]);
199
-                $dependencies[$alias] = $load_source;
200
-                $registered = true;
201
-            }
202
-        }
203
-        // now add our two lists of dependencies together.
204
-        // using Union (+=) favours the arrays in precedence from left to right,
205
-        // so $dependencies is NOT overwritten because it is listed first
206
-        // ie: with A = B + C, entries in B take precedence over duplicate entries in C
207
-        // Union is way faster than array_merge() but should be used with caution...
208
-        // especially with numerically indexed arrays
209
-        $dependencies += self::$_instance->_dependency_map[ $class ];
210
-        // now we need to ensure that the resulting dependencies
211
-        // array only has the entries that are required for the class
212
-        // so first count how many dependencies were originally registered for the class
213
-        $dependency_count = count(self::$_instance->_dependency_map[ $class ]);
214
-        // if that count is non-zero (meaning dependencies were already registered)
215
-        self::$_instance->_dependency_map[ $class ] = $dependency_count
216
-            // then truncate the  final array to match that count
217
-            ? array_slice($dependencies, 0, $dependency_count)
218
-            // otherwise just take the incoming array because nothing previously existed
219
-            : $dependencies;
220
-        return $registered;
221
-    }
222
-
223
-
224
-
225
-    /**
226
-     * @param string $class_name
227
-     * @param string $loader
228
-     * @return bool
229
-     * @throws DomainException
230
-     */
231
-    public static function register_class_loader($class_name, $loader = 'load_core')
232
-    {
233
-        if (! $loader instanceof Closure && strpos($class_name, '\\') !== false) {
234
-            throw new DomainException(
235
-                esc_html__('Don\'t use class loaders for FQCNs.', 'event_espresso')
236
-            );
237
-        }
238
-        // check that loader is callable or method starts with "load_" and exists in EE_Registry
239
-        if (
240
-            ! is_callable($loader)
241
-            && (
242
-                strpos($loader, 'load_') !== 0
243
-                || ! method_exists('EE_Registry', $loader)
244
-            )
245
-        ) {
246
-            throw new DomainException(
247
-                sprintf(
248
-                    esc_html__(
249
-                        '"%1$s" is not a valid loader method on EE_Registry.',
250
-                        'event_espresso'
251
-                    ),
252
-                    $loader
253
-                )
254
-            );
255
-        }
256
-        $class_name = self::$_instance->get_alias($class_name);
257
-        if (! isset(self::$_instance->_class_loaders[$class_name])) {
258
-            self::$_instance->_class_loaders[$class_name] = $loader;
259
-            return true;
260
-        }
261
-        return false;
262
-    }
263
-
264
-
265
-
266
-    /**
267
-     * @return array
268
-     */
269
-    public function dependency_map()
270
-    {
271
-        return $this->_dependency_map;
272
-    }
273
-
274
-
275
-
276
-    /**
277
-     * returns TRUE if dependency map contains a listing for the provided class name
278
-     *
279
-     * @param string $class_name
280
-     * @return boolean
281
-     */
282
-    public function has($class_name = '')
283
-    {
284
-        return isset($this->_dependency_map[$class_name]) ? true : false;
285
-    }
286
-
287
-
288
-
289
-    /**
290
-     * returns TRUE if dependency map contains a listing for the provided class name AND dependency
291
-     *
292
-     * @param string $class_name
293
-     * @param string $dependency
294
-     * @return bool
295
-     */
296
-    public function has_dependency_for_class($class_name = '', $dependency = '')
297
-    {
298
-        $dependency = $this->get_alias($dependency);
299
-        return isset($this->_dependency_map[$class_name], $this->_dependency_map[$class_name][$dependency])
300
-            ? true
301
-            : false;
302
-    }
303
-
304
-
305
-
306
-    /**
307
-     * returns loading strategy for whether a previously cached dependency should be loaded or a new instance returned
308
-     *
309
-     * @param string $class_name
310
-     * @param string $dependency
311
-     * @return int
312
-     */
313
-    public function loading_strategy_for_class_dependency($class_name = '', $dependency = '')
314
-    {
315
-        $dependency = $this->get_alias($dependency);
316
-        return $this->has_dependency_for_class($class_name, $dependency)
317
-            ? $this->_dependency_map[$class_name][$dependency]
318
-            : EE_Dependency_Map::not_registered;
319
-    }
320
-
321
-
322
-
323
-    /**
324
-     * @param string $class_name
325
-     * @return string | Closure
326
-     */
327
-    public function class_loader($class_name)
328
-    {
329
-        $class_name = $this->get_alias($class_name);
330
-        return isset($this->_class_loaders[$class_name]) ? $this->_class_loaders[$class_name] : '';
331
-    }
332
-
333
-
334
-
335
-    /**
336
-     * @return array
337
-     */
338
-    public function class_loaders()
339
-    {
340
-        return $this->_class_loaders;
341
-    }
342
-
343
-
344
-
345
-    /**
346
-     * adds an alias for a classname
347
-     *
348
-     * @param string $class_name the class name that should be used (concrete class to replace interface)
349
-     * @param string $alias      the class name that would be type hinted for (abstract parent or interface)
350
-     * @param string $for_class  the class that has the dependency (is type hinting for the interface)
351
-     */
352
-    public function add_alias($class_name, $alias, $for_class = '')
353
-    {
354
-        if ($for_class !== '') {
355
-            if (! isset($this->_aliases[$for_class])) {
356
-                $this->_aliases[$for_class] = array();
357
-            }
358
-            $this->_aliases[$for_class][$class_name] = $alias;
359
-        }
360
-        $this->_aliases[$class_name] = $alias;
361
-    }
362
-
363
-
364
-
365
-    /**
366
-     * returns TRUE if the provided class name has an alias
367
-     *
368
-     * @param string $class_name
369
-     * @param string $for_class
370
-     * @return bool
371
-     */
372
-    public function has_alias($class_name = '', $for_class = '')
373
-    {
374
-        return isset($this->_aliases[$for_class], $this->_aliases[$for_class][$class_name])
375
-               || (
376
-                   isset($this->_aliases[$class_name])
377
-                   && ! is_array($this->_aliases[$class_name])
378
-               );
379
-    }
380
-
381
-
382
-
383
-    /**
384
-     * returns alias for class name if one exists, otherwise returns the original classname
385
-     * functions recursively, so that multiple aliases can be used to drill down to a classname
386
-     *  for example:
387
-     *      if the following two entries were added to the _aliases array:
388
-     *          array(
389
-     *              'interface_alias'           => 'some\namespace\interface'
390
-     *              'some\namespace\interface'  => 'some\namespace\classname'
391
-     *          )
392
-     *      then one could use EE_Registry::instance()->create( 'interface_alias' )
393
-     *      to load an instance of 'some\namespace\classname'
394
-     *
395
-     * @param string $class_name
396
-     * @param string $for_class
397
-     * @return string
398
-     */
399
-    public function get_alias($class_name = '', $for_class = '')
400
-    {
401
-        if (! $this->has_alias($class_name, $for_class)) {
402
-            return $class_name;
403
-        }
404
-        if ($for_class !== '' && isset($this->_aliases[ $for_class ][ $class_name ])) {
405
-            return $this->get_alias($this->_aliases[$for_class][$class_name], $for_class);
406
-        }
407
-        return $this->get_alias($this->_aliases[$class_name]);
408
-    }
409
-
410
-
411
-
412
-    /**
413
-     * Registers the core dependencies and whether a previously instantiated object should be loaded from the cache,
414
-     * if one exists, or whether a new object should be generated every time the requested class is loaded.
415
-     * This is done by using the following class constants:
416
-     *        EE_Dependency_Map::load_from_cache - loads previously instantiated object
417
-     *        EE_Dependency_Map::load_new_object - generates a new object every time
418
-     */
419
-    protected function _register_core_dependencies()
420
-    {
421
-        $this->_dependency_map = array(
422
-            'EE_Request_Handler'                                                                                          => array(
423
-                'EE_Request' => EE_Dependency_Map::load_from_cache,
424
-            ),
425
-            'EE_System'                                                                                                   => array(
426
-                'EE_Registry'                                => EE_Dependency_Map::load_from_cache,
427
-                'EventEspresso\core\services\loaders\Loader' => EE_Dependency_Map::load_from_cache,
428
-                'EE_Maintenance_Mode'                        => EE_Dependency_Map::load_from_cache,
429
-            ),
430
-            'EE_Session'                                                                                                  => array(
431
-                'EventEspresso\core\services\cache\TransientCacheStorage' => EE_Dependency_Map::load_from_cache,
432
-                'EE_Encryption'                                           => EE_Dependency_Map::load_from_cache,
433
-            ),
434
-            'EE_Cart'                                                                                                     => array(
435
-                'EE_Session' => EE_Dependency_Map::load_from_cache,
436
-            ),
437
-            'EE_Front_Controller'                                                                                         => array(
438
-                'EE_Registry'              => EE_Dependency_Map::load_from_cache,
439
-                'EE_Request_Handler'       => EE_Dependency_Map::load_from_cache,
440
-                'EE_Module_Request_Router' => EE_Dependency_Map::load_from_cache,
441
-            ),
442
-            'EE_Messenger_Collection_Loader'                                                                              => array(
443
-                'EE_Messenger_Collection' => EE_Dependency_Map::load_new_object,
444
-            ),
445
-            'EE_Message_Type_Collection_Loader'                                                                           => array(
446
-                'EE_Message_Type_Collection' => EE_Dependency_Map::load_new_object,
447
-            ),
448
-            'EE_Message_Resource_Manager'                                                                                 => array(
449
-                'EE_Messenger_Collection_Loader'    => EE_Dependency_Map::load_new_object,
450
-                'EE_Message_Type_Collection_Loader' => EE_Dependency_Map::load_new_object,
451
-                'EEM_Message_Template_Group'        => EE_Dependency_Map::load_from_cache,
452
-            ),
453
-            'EE_Message_Factory'                                                                                          => array(
454
-                'EE_Message_Resource_Manager' => EE_Dependency_Map::load_from_cache,
455
-            ),
456
-            'EE_messages'                                                                                                 => array(
457
-                'EE_Message_Resource_Manager' => EE_Dependency_Map::load_from_cache,
458
-            ),
459
-            'EE_Messages_Generator'                                                                                       => array(
460
-                'EE_Messages_Queue'                    => EE_Dependency_Map::load_new_object,
461
-                'EE_Messages_Data_Handler_Collection'  => EE_Dependency_Map::load_new_object,
462
-                'EE_Message_Template_Group_Collection' => EE_Dependency_Map::load_new_object,
463
-                'EEH_Parse_Shortcodes'                 => EE_Dependency_Map::load_from_cache,
464
-            ),
465
-            'EE_Messages_Processor'                                                                                       => array(
466
-                'EE_Message_Resource_Manager' => EE_Dependency_Map::load_from_cache,
467
-            ),
468
-            'EE_Messages_Queue'                                                                                           => array(
469
-                'EE_Message_Repository' => EE_Dependency_Map::load_new_object,
470
-            ),
471
-            'EE_Messages_Template_Defaults'                                                                               => array(
472
-                'EEM_Message_Template_Group' => EE_Dependency_Map::load_from_cache,
473
-                'EEM_Message_Template'       => EE_Dependency_Map::load_from_cache,
474
-            ),
475
-            'EE_Message_To_Generate_From_Request'                                                                         => array(
476
-                'EE_Message_Resource_Manager' => EE_Dependency_Map::load_from_cache,
477
-                'EE_Request_Handler'          => EE_Dependency_Map::load_from_cache,
478
-            ),
479
-            'EventEspresso\core\services\commands\CommandBus'                                                             => array(
480
-                'EventEspresso\core\services\commands\CommandHandlerManager' => EE_Dependency_Map::load_from_cache,
481
-            ),
482
-            'EventEspresso\services\commands\CommandHandler'                                                              => array(
483
-                'EE_Registry'         => EE_Dependency_Map::load_from_cache,
484
-                'CommandBusInterface' => EE_Dependency_Map::load_from_cache,
485
-            ),
486
-            'EventEspresso\core\services\commands\CommandHandlerManager'                                                  => array(
487
-                'EventEspresso\core\services\loaders\Loader' => EE_Dependency_Map::load_from_cache,
488
-            ),
489
-            'EventEspresso\core\services\commands\CompositeCommandHandler'                                                => array(
490
-                'EventEspresso\core\services\commands\CommandBus'     => EE_Dependency_Map::load_from_cache,
491
-                'EventEspresso\core\services\commands\CommandFactory' => EE_Dependency_Map::load_from_cache,
492
-            ),
493
-            'EventEspresso\core\services\commands\CommandFactory'                                                         => array(
494
-                'EventEspresso\core\services\loaders\Loader' => EE_Dependency_Map::load_from_cache,
495
-            ),
496
-            'EventEspresso\core\services\commands\middleware\CapChecker'                                                  => array(
497
-                'EventEspresso\core\domain\services\capabilities\CapabilitiesChecker' => EE_Dependency_Map::load_from_cache,
498
-            ),
499
-            'EventEspresso\core\domain\services\capabilities\CapabilitiesChecker'                                         => array(
500
-                'EE_Capabilities' => EE_Dependency_Map::load_from_cache,
501
-            ),
502
-            'EventEspresso\core\domain\services\capabilities\RegistrationsCapChecker'                                     => array(
503
-                'EE_Capabilities' => EE_Dependency_Map::load_from_cache,
504
-            ),
505
-            'EventEspresso\core\services\commands\registration\CreateRegistrationCommandHandler'                          => array(
506
-                'EventEspresso\core\domain\services\registration\CreateRegistrationService' => EE_Dependency_Map::load_from_cache,
507
-            ),
508
-            'EventEspresso\core\services\commands\registration\CopyRegistrationDetailsCommandHandler'                     => array(
509
-                'EventEspresso\core\domain\services\registration\CopyRegistrationService' => EE_Dependency_Map::load_from_cache,
510
-            ),
511
-            'EventEspresso\core\services\commands\registration\CopyRegistrationPaymentsCommandHandler'                    => array(
512
-                'EventEspresso\core\domain\services\registration\CopyRegistrationService' => EE_Dependency_Map::load_from_cache,
513
-            ),
514
-            'EventEspresso\core\services\commands\registration\CancelRegistrationAndTicketLineItemCommandHandler'         => array(
515
-                'EventEspresso\core\domain\services\registration\CancelTicketLineItemService' => EE_Dependency_Map::load_from_cache,
516
-            ),
517
-            'EventEspresso\core\services\commands\registration\UpdateRegistrationAndTransactionAfterChangeCommandHandler' => array(
518
-                'EventEspresso\core\domain\services\registration\UpdateRegistrationService' => EE_Dependency_Map::load_from_cache,
519
-            ),
520
-            'EventEspresso\core\services\commands\ticket\CreateTicketLineItemCommandHandler'                              => array(
521
-                'EventEspresso\core\domain\services\ticket\CreateTicketLineItemService' => EE_Dependency_Map::load_from_cache,
522
-            ),
523
-            'EventEspresso\core\services\commands\ticket\CancelTicketLineItemCommandHandler'                              => array(
524
-                'EventEspresso\core\domain\services\ticket\CancelTicketLineItemService' => EE_Dependency_Map::load_from_cache,
525
-            ),
526
-            'EventEspresso\core\domain\services\registration\CancelRegistrationService'                                   => array(
527
-                'EventEspresso\core\domain\services\ticket\CancelTicketLineItemService' => EE_Dependency_Map::load_from_cache,
528
-            ),
529
-            'EventEspresso\core\services\commands\attendee\CreateAttendeeCommandHandler'                                  => array(
530
-                'EEM_Attendee' => EE_Dependency_Map::load_from_cache,
531
-            ),
532
-            'EventEspresso\core\services\database\TableManager'                                                           => array(
533
-                'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
534
-            ),
535
-            'EE_Data_Migration_Class_Base'                                                                                => array(
536
-                'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
537
-                'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
538
-            ),
539
-            'EE_DMS_Core_4_1_0'                                                                                           => array(
540
-                'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
541
-                'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
542
-            ),
543
-            'EE_DMS_Core_4_2_0'                                                                                           => array(
544
-                'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
545
-                'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
546
-            ),
547
-            'EE_DMS_Core_4_3_0'                                                                                           => array(
548
-                'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
549
-                'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
550
-            ),
551
-            'EE_DMS_Core_4_4_0'                                                                                           => array(
552
-                'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
553
-                'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
554
-            ),
555
-            'EE_DMS_Core_4_5_0'                                                                                           => array(
556
-                'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
557
-                'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
558
-            ),
559
-            'EE_DMS_Core_4_6_0'                                                                                           => array(
560
-                'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
561
-                'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
562
-            ),
563
-            'EE_DMS_Core_4_7_0'                                                                                           => array(
564
-                'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
565
-                'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
566
-            ),
567
-            'EE_DMS_Core_4_8_0'                                                                                           => array(
568
-                'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
569
-                'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
570
-            ),
571
-            'EE_DMS_Core_4_9_0'                                                                                           => array(
572
-                'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
573
-                'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
574
-            ),
575
-            'EventEspresso\core\services\assets\Registry'                                                                 => array(
576
-                'EE_Template_Config' => EE_Dependency_Map::load_from_cache,
577
-                'EE_Currency_Config' => EE_Dependency_Map::load_from_cache,
578
-            ),
579
-            'EventEspresso\core\domain\entities\shortcodes\EspressoCancelled'                                             => array(
580
-                'EventEspresso\core\services\cache\PostRelatedCacheManager' => EE_Dependency_Map::load_from_cache,
581
-            ),
582
-            'EventEspresso\core\domain\entities\shortcodes\EspressoCheckout'                                              => array(
583
-                'EventEspresso\core\services\cache\PostRelatedCacheManager' => EE_Dependency_Map::load_from_cache,
584
-            ),
585
-            'EventEspresso\core\domain\entities\shortcodes\EspressoEventAttendees'                                        => array(
586
-                'EventEspresso\core\services\cache\PostRelatedCacheManager' => EE_Dependency_Map::load_from_cache,
587
-            ),
588
-            'EventEspresso\core\domain\entities\shortcodes\EspressoEvents'                                                => array(
589
-                'EventEspresso\core\services\cache\PostRelatedCacheManager' => EE_Dependency_Map::load_from_cache,
590
-            ),
591
-            'EventEspresso\core\domain\entities\shortcodes\EspressoThankYou'                                              => array(
592
-                'EventEspresso\core\services\cache\PostRelatedCacheManager' => EE_Dependency_Map::load_from_cache,
593
-            ),
594
-            'EventEspresso\core\domain\entities\shortcodes\EspressoTicketSelector'                                        => array(
595
-                'EventEspresso\core\services\cache\PostRelatedCacheManager' => EE_Dependency_Map::load_from_cache,
596
-            ),
597
-            'EventEspresso\core\domain\entities\shortcodes\EspressoTxnPage'                                               => array(
598
-                'EventEspresso\core\services\cache\PostRelatedCacheManager' => EE_Dependency_Map::load_from_cache,
599
-            ),
600
-            'EventEspresso\core\services\cache\BasicCacheManager'                                                         => array(
601
-                'EventEspresso\core\services\cache\TransientCacheStorage' => EE_Dependency_Map::load_from_cache,
602
-            ),
603
-            'EventEspresso\core\services\cache\PostRelatedCacheManager'            => array(
604
-                'EventEspresso\core\services\cache\TransientCacheStorage' => EE_Dependency_Map::load_from_cache,
605
-            ),
606
-            'EventEspresso\core\services\activation\ActivationsAndUpgradesManager' => array(
607
-                'EventEspresso\core\services\activation\ActivationHandler'   => EE_Dependency_Map::load_from_cache,
608
-                'EventEspresso\core\services\activation\RequestTypeDetector' => EE_Dependency_Map::load_from_cache,
609
-            ),
610
-            'EventEspresso\core\services\activation\ActivationHandler'             => array(
611
-                'EE_Maintenance_Mode' => EE_Dependency_Map::load_from_cache,
612
-            ),
613
-            'EventEspresso\core\services\activation\InitializeCore'                => array(
614
-                null,
615
-                'EE_Capabilities'           => EE_Dependency_Map::load_from_cache,
616
-                'EE_Data_Migration_Manager' => EE_Dependency_Map::load_from_cache,
617
-                'EE_Maintenance_Mode'       => EE_Dependency_Map::load_from_cache,
618
-            ),
619
-            'EventEspresso\core\services\activation\InitializeAddon' => array(
620
-                null,
621
-                'EE_Data_Migration_Manager' => EE_Dependency_Map::load_from_cache,
622
-                'EE_Maintenance_Mode'       => EE_Dependency_Map::load_from_cache,
623
-                'EE_Registry'               => EE_Dependency_Map::load_from_cache,
624
-            ),
625
-        );
626
-    }
627
-
628
-
629
-
630
-    /**
631
-     * Registers how core classes are loaded.
632
-     * This can either be done by simply providing the name of one of the EE_Registry loader methods such as:
633
-     *        'EE_Request_Handler' => 'load_core'
634
-     *        'EE_Messages_Queue'  => 'load_lib'
635
-     *        'EEH_Debug_Tools'    => 'load_helper'
636
-     * or, if greater control is required, by providing a custom closure. For example:
637
-     *        'Some_Class' => function () {
638
-     *            return new Some_Class();
639
-     *        },
640
-     * This is required for instantiating dependencies
641
-     * where an interface has been type hinted in a class constructor. For example:
642
-     *        'Required_Interface' => function () {
643
-     *            return new A_Class_That_Implements_Required_Interface();
644
-     *        },
645
-     */
646
-    protected function _register_core_class_loaders()
647
-    {
648
-        //for PHP5.3 compat, we need to register any properties called here in a variable because `$this` cannot
649
-        //be used in a closure.
650
-        $request = &$this->_request;
651
-        $response = &$this->_response;
652
-        $loader = &$this->loader;
653
-        $this->_class_loaders = array(
654
-            //load_core
655
-            'EE_Capabilities'                      => 'load_core',
656
-            'EE_Encryption'                        => 'load_core',
657
-            'EE_Front_Controller'                  => 'load_core',
658
-            'EE_Module_Request_Router'             => 'load_core',
659
-            'EE_Registry'                          => 'load_core',
660
-            'EE_Request'                           => function () use (&$request) {
661
-                return $request;
662
-            },
663
-            'EE_Response'                          => function () use (&$response) {
664
-                return $response;
665
-            },
666
-            'EE_Request_Handler'                   => 'load_core',
667
-            'EE_Session'                           => 'load_core',
668
-            'EE_System'                            => 'load_core',
669
-            'EE_Maintenance_Mode'                  => 'load_core',
670
-            'EE_Register_CPTs'                     => 'load_core',
671
-            'EE_Admin'                             => 'load_core',
672
-            'EE_Data_Migration_Manager'            => 'load_core',
673
-            //load_lib
674
-            'EE_Message_Resource_Manager'          => 'load_lib',
675
-            'EE_Message_Type_Collection'           => 'load_lib',
676
-            'EE_Message_Type_Collection_Loader'    => 'load_lib',
677
-            'EE_Messenger_Collection'              => 'load_lib',
678
-            'EE_Messenger_Collection_Loader'       => 'load_lib',
679
-            'EE_Messages_Processor'                => 'load_lib',
680
-            'EE_Message_Repository'                => 'load_lib',
681
-            'EE_Messages_Queue'                    => 'load_lib',
682
-            'EE_Messages_Data_Handler_Collection'  => 'load_lib',
683
-            'EE_Message_Template_Group_Collection' => 'load_lib',
684
-            'EE_Messages_Generator'                => function () {
685
-                return EE_Registry::instance()->load_lib(
686
-                    'Messages_Generator',
687
-                    array(),
688
-                    false,
689
-                    false
690
-                );
691
-            },
692
-            'EE_Messages_Template_Defaults'        => function ($arguments = array()) {
693
-                return EE_Registry::instance()->load_lib(
694
-                    'Messages_Template_Defaults',
695
-                    $arguments,
696
-                    false,
697
-                    false
698
-                );
699
-            },
700
-            //load_model
701
-            'EEM_Attendee'                         => 'load_model',
702
-            'EEM_Message_Template_Group'           => 'load_model',
703
-            'EEM_Message_Template'                 => 'load_model',
704
-            //load_helper
705
-            'EEH_Parse_Shortcodes'                 => function () {
706
-                if (EE_Registry::instance()->load_helper('Parse_Shortcodes')) {
707
-                    return new EEH_Parse_Shortcodes();
708
-                }
709
-                return null;
710
-            },
711
-            'EE_Template_Config'                   => function () {
712
-                return EE_Config::instance()->template_settings;
713
-            },
714
-            'EE_Currency_Config'                   => function () {
715
-                return EE_Config::instance()->currency;
716
-            },
717
-            'EventEspresso\core\services\loaders\Loader' => function () use (&$loader) {
718
-                return $loader;
719
-            },
720
-        );
721
-    }
722
-
723
-
724
-
725
-    /**
726
-     * can be used for supplying alternate names for classes,
727
-     * or for connecting interface names to instantiable classes
728
-     */
729
-    protected function _register_core_aliases()
730
-    {
731
-        $this->_aliases = array(
732
-            'CommandBusInterface'                                                 => 'EventEspresso\core\services\commands\CommandBusInterface',
733
-            'EventEspresso\core\services\commands\CommandBusInterface'            => 'EventEspresso\core\services\commands\CommandBus',
734
-            'CommandHandlerManagerInterface'                                      => 'EventEspresso\core\services\commands\CommandHandlerManagerInterface',
735
-            'EventEspresso\core\services\commands\CommandHandlerManagerInterface' => 'EventEspresso\core\services\commands\CommandHandlerManager',
736
-            'CapChecker'                                                          => 'EventEspresso\core\services\commands\middleware\CapChecker',
737
-            'AddActionHook'                                                       => 'EventEspresso\core\services\commands\middleware\AddActionHook',
738
-            'CapabilitiesChecker'                                                 => 'EventEspresso\core\domain\services\capabilities\CapabilitiesChecker',
739
-            'CapabilitiesCheckerInterface'                                        => 'EventEspresso\core\domain\services\capabilities\CapabilitiesCheckerInterface',
740
-            'EventEspresso\core\domain\services\capabilities\CapabilitiesCheckerInterface' => 'EventEspresso\core\domain\services\capabilities\CapabilitiesChecker',
741
-            'CreateRegistrationService'                                           => 'EventEspresso\core\domain\services\registration\CreateRegistrationService',
742
-            'CreateRegCodeCommandHandler'                                         => 'EventEspresso\core\services\commands\registration\CreateRegCodeCommand',
743
-            'CreateRegUrlLinkCommandHandler'                                      => 'EventEspresso\core\services\commands\registration\CreateRegUrlLinkCommand',
744
-            'CreateRegistrationCommandHandler'                                    => 'EventEspresso\core\services\commands\registration\CreateRegistrationCommand',
745
-            'CopyRegistrationDetailsCommandHandler'                               => 'EventEspresso\core\services\commands\registration\CopyRegistrationDetailsCommand',
746
-            'CopyRegistrationPaymentsCommandHandler'                              => 'EventEspresso\core\services\commands\registration\CopyRegistrationPaymentsCommand',
747
-            'CancelRegistrationAndTicketLineItemCommandHandler'                   => 'EventEspresso\core\services\commands\registration\CancelRegistrationAndTicketLineItemCommandHandler',
748
-            'UpdateRegistrationAndTransactionAfterChangeCommandHandler'           => 'EventEspresso\core\services\commands\registration\UpdateRegistrationAndTransactionAfterChangeCommandHandler',
749
-            'CreateTicketLineItemCommandHandler'                                  => 'EventEspresso\core\services\commands\ticket\CreateTicketLineItemCommand',
750
-            'TableManager'                                                        => 'EventEspresso\core\services\database\TableManager',
751
-            'TableAnalysis'                                                       => 'EventEspresso\core\services\database\TableAnalysis',
752
-            'CreateTransactionCommandHandler'                                     => 'EventEspresso\core\services\commands\transaction\CreateTransactionCommandHandler',
753
-            'CreateAttendeeCommandHandler'                                        => 'EventEspresso\core\services\commands\attendee\CreateAttendeeCommandHandler',
754
-            'EspressoShortcode'                                                   => 'EventEspresso\core\services\shortcodes\EspressoShortcode',
755
-            'ShortcodeInterface'                                                  => 'EventEspresso\core\services\shortcodes\ShortcodeInterface',
756
-            'EventEspresso\core\services\shortcodes\ShortcodeInterface'           => 'EventEspresso\core\services\shortcodes\EspressoShortcode',
757
-            'EventEspresso\core\services\cache\CacheStorageInterface'             => 'EventEspresso\core\services\cache\TransientCacheStorage',
758
-            'LoaderInterface'                                                     => 'EventEspresso\core\services\loaders\LoaderInterface',
759
-            'EventEspresso\core\services\loaders\LoaderInterface'                 => 'EventEspresso\core\services\loaders\Loader',
760
-            'CommandFactoryInterface'                                             => 'EventEspresso\core\services\commands\CommandFactoryInterface',
761
-            'EventEspresso\core\services\commands\CommandFactoryInterface'        => 'EventEspresso\core\services\commands\CommandFactory',
762
-            'EventEspresso\core\domain\services\session\SessionIdentifierInterface' => 'EE_Session',
763
-            'NoticeConverterInterface'                                            => 'EventEspresso\core\services\notices\NoticeConverterInterface',
764
-            'EventEspresso\core\services\notices\NoticeConverterInterface'        => 'EventEspresso\core\services\notices\ConvertNoticesToEeErrors',
765
-            'NoticesContainerInterface'                                            => 'EventEspresso\core\services\notices\NoticesContainerInterface',
766
-            'EventEspresso\core\services\notices\NoticesContainerInterface'        => 'EventEspresso\core\services\notices\NoticesContainer',
767
-        );
768
-    }
769
-
770
-
771
-
772
-    /**
773
-     * This is used to reset the internal map and class_loaders to their original default state at the beginning of the
774
-     * request Primarily used by unit tests.
775
-     */
776
-    public function reset()
777
-    {
778
-        $this->_register_core_class_loaders();
779
-        $this->_register_core_dependencies();
780
-    }
24
+	/**
25
+	 * This means that the requested class dependency is not present in the dependency map
26
+	 */
27
+	const not_registered = 0;
28
+
29
+	/**
30
+	 * This instructs class loaders to ALWAYS return a newly instantiated object for the requested class.
31
+	 */
32
+	const load_new_object = 1;
33
+
34
+	/**
35
+	 * This instructs class loaders to return a previously instantiated and cached object for the requested class.
36
+	 * IF a previously instantiated object does not exist, a new one will be created and added to the cache.
37
+	 */
38
+	const load_from_cache = 2;
39
+
40
+	/**
41
+	 * When registering a dependency,
42
+	 * this indicates to keep any existing dependencies that already exist,
43
+	 * and simply discard any new dependencies declared in the incoming data
44
+	 */
45
+	const KEEP_EXISTING_DEPENDENCIES = 0;
46
+
47
+	/**
48
+	 * When registering a dependency,
49
+	 * this indicates to overwrite any existing dependencies that already exist using the incoming data
50
+	 */
51
+	const OVERWRITE_DEPENDENCIES = 1;
52
+
53
+
54
+
55
+	/**
56
+	 * @type EE_Dependency_Map $_instance
57
+	 */
58
+	protected static $_instance;
59
+
60
+	/**
61
+	 * @type EE_Request $request
62
+	 */
63
+	protected $_request;
64
+
65
+	/**
66
+	 * @type EE_Response $response
67
+	 */
68
+	protected $_response;
69
+
70
+	/**
71
+	 * @type LoaderInterface $loader
72
+	 */
73
+	protected $loader;
74
+
75
+	/**
76
+	 * @type array $_dependency_map
77
+	 */
78
+	protected $_dependency_map = array();
79
+
80
+	/**
81
+	 * @type array $_class_loaders
82
+	 */
83
+	protected $_class_loaders = array();
84
+
85
+	/**
86
+	 * @type array $_aliases
87
+	 */
88
+	protected $_aliases = array();
89
+
90
+
91
+
92
+	/**
93
+	 * EE_Dependency_Map constructor.
94
+	 *
95
+	 * @param EE_Request  $request
96
+	 * @param EE_Response $response
97
+	 */
98
+	protected function __construct(EE_Request $request, EE_Response $response)
99
+	{
100
+		$this->_request = $request;
101
+		$this->_response = $response;
102
+		add_action('EE_Load_Espresso_Core__handle_request__initialize_core_loading', array($this, 'initialize'));
103
+		do_action('EE_Dependency_Map____construct');
104
+	}
105
+
106
+
107
+
108
+	/**
109
+	 * @throws InvalidDataTypeException
110
+	 * @throws InvalidInterfaceException
111
+	 * @throws InvalidArgumentException
112
+	 */
113
+	public function initialize()
114
+	{
115
+		$this->_register_core_dependencies();
116
+		$this->_register_core_class_loaders();
117
+		$this->_register_core_aliases();
118
+	}
119
+
120
+
121
+
122
+	/**
123
+	 * @singleton method used to instantiate class object
124
+	 * @access    public
125
+	 * @param EE_Request  $request
126
+	 * @param EE_Response $response
127
+	 * @return EE_Dependency_Map
128
+	 */
129
+	public static function instance(EE_Request $request = null, EE_Response $response = null)
130
+	{
131
+		// check if class object is instantiated, and instantiated properly
132
+		if (! self::$_instance instanceof EE_Dependency_Map) {
133
+			self::$_instance = new EE_Dependency_Map($request, $response);
134
+		}
135
+		return self::$_instance;
136
+	}
137
+
138
+
139
+
140
+	/**
141
+	 * @param LoaderInterface $loader
142
+	 */
143
+	public function setLoader(LoaderInterface $loader)
144
+	{
145
+		$this->loader = $loader;
146
+	}
147
+
148
+
149
+
150
+	/**
151
+	 * @param string $class
152
+	 * @param array  $dependencies
153
+	 * @param int    $overwrite
154
+	 * @return bool
155
+	 */
156
+	public static function register_dependencies(
157
+		$class,
158
+		array $dependencies,
159
+		$overwrite = EE_Dependency_Map::KEEP_EXISTING_DEPENDENCIES
160
+	) {
161
+		return self::$_instance->registerDependencies($class, $dependencies, $overwrite);
162
+	}
163
+
164
+
165
+
166
+	/**
167
+	 * Assigns an array of class names and corresponding load sources (new or cached)
168
+	 * to the class specified by the first parameter.
169
+	 * IMPORTANT !!!
170
+	 * The order of elements in the incoming $dependencies array MUST match
171
+	 * the order of the constructor parameters for the class in question.
172
+	 * This is especially important when overriding any existing dependencies that are registered.
173
+	 * the third parameter controls whether any duplicate dependencies are overwritten or not.
174
+	 *
175
+	 * @param string $class
176
+	 * @param array  $dependencies
177
+	 * @param int    $overwrite
178
+	 * @return bool
179
+	 */
180
+	public function registerDependencies(
181
+		$class,
182
+		array $dependencies,
183
+		$overwrite = EE_Dependency_Map::KEEP_EXISTING_DEPENDENCIES
184
+	) {
185
+		$class = trim($class, '\\');
186
+		$registered = false;
187
+		if (empty(self::$_instance->_dependency_map[ $class ])) {
188
+			self::$_instance->_dependency_map[ $class ] = array();
189
+		}
190
+		// we need to make sure that any aliases used when registering a dependency
191
+		// get resolved to the correct class name
192
+		foreach ((array)$dependencies as $dependency => $load_source) {
193
+			$alias = self::$_instance->get_alias($dependency);
194
+			if (
195
+				$overwrite === EE_Dependency_Map::OVERWRITE_DEPENDENCIES
196
+				|| ! isset(self::$_instance->_dependency_map[ $class ][ $alias ])
197
+			) {
198
+				unset($dependencies[$dependency]);
199
+				$dependencies[$alias] = $load_source;
200
+				$registered = true;
201
+			}
202
+		}
203
+		// now add our two lists of dependencies together.
204
+		// using Union (+=) favours the arrays in precedence from left to right,
205
+		// so $dependencies is NOT overwritten because it is listed first
206
+		// ie: with A = B + C, entries in B take precedence over duplicate entries in C
207
+		// Union is way faster than array_merge() but should be used with caution...
208
+		// especially with numerically indexed arrays
209
+		$dependencies += self::$_instance->_dependency_map[ $class ];
210
+		// now we need to ensure that the resulting dependencies
211
+		// array only has the entries that are required for the class
212
+		// so first count how many dependencies were originally registered for the class
213
+		$dependency_count = count(self::$_instance->_dependency_map[ $class ]);
214
+		// if that count is non-zero (meaning dependencies were already registered)
215
+		self::$_instance->_dependency_map[ $class ] = $dependency_count
216
+			// then truncate the  final array to match that count
217
+			? array_slice($dependencies, 0, $dependency_count)
218
+			// otherwise just take the incoming array because nothing previously existed
219
+			: $dependencies;
220
+		return $registered;
221
+	}
222
+
223
+
224
+
225
+	/**
226
+	 * @param string $class_name
227
+	 * @param string $loader
228
+	 * @return bool
229
+	 * @throws DomainException
230
+	 */
231
+	public static function register_class_loader($class_name, $loader = 'load_core')
232
+	{
233
+		if (! $loader instanceof Closure && strpos($class_name, '\\') !== false) {
234
+			throw new DomainException(
235
+				esc_html__('Don\'t use class loaders for FQCNs.', 'event_espresso')
236
+			);
237
+		}
238
+		// check that loader is callable or method starts with "load_" and exists in EE_Registry
239
+		if (
240
+			! is_callable($loader)
241
+			&& (
242
+				strpos($loader, 'load_') !== 0
243
+				|| ! method_exists('EE_Registry', $loader)
244
+			)
245
+		) {
246
+			throw new DomainException(
247
+				sprintf(
248
+					esc_html__(
249
+						'"%1$s" is not a valid loader method on EE_Registry.',
250
+						'event_espresso'
251
+					),
252
+					$loader
253
+				)
254
+			);
255
+		}
256
+		$class_name = self::$_instance->get_alias($class_name);
257
+		if (! isset(self::$_instance->_class_loaders[$class_name])) {
258
+			self::$_instance->_class_loaders[$class_name] = $loader;
259
+			return true;
260
+		}
261
+		return false;
262
+	}
263
+
264
+
265
+
266
+	/**
267
+	 * @return array
268
+	 */
269
+	public function dependency_map()
270
+	{
271
+		return $this->_dependency_map;
272
+	}
273
+
274
+
275
+
276
+	/**
277
+	 * returns TRUE if dependency map contains a listing for the provided class name
278
+	 *
279
+	 * @param string $class_name
280
+	 * @return boolean
281
+	 */
282
+	public function has($class_name = '')
283
+	{
284
+		return isset($this->_dependency_map[$class_name]) ? true : false;
285
+	}
286
+
287
+
288
+
289
+	/**
290
+	 * returns TRUE if dependency map contains a listing for the provided class name AND dependency
291
+	 *
292
+	 * @param string $class_name
293
+	 * @param string $dependency
294
+	 * @return bool
295
+	 */
296
+	public function has_dependency_for_class($class_name = '', $dependency = '')
297
+	{
298
+		$dependency = $this->get_alias($dependency);
299
+		return isset($this->_dependency_map[$class_name], $this->_dependency_map[$class_name][$dependency])
300
+			? true
301
+			: false;
302
+	}
303
+
304
+
305
+
306
+	/**
307
+	 * returns loading strategy for whether a previously cached dependency should be loaded or a new instance returned
308
+	 *
309
+	 * @param string $class_name
310
+	 * @param string $dependency
311
+	 * @return int
312
+	 */
313
+	public function loading_strategy_for_class_dependency($class_name = '', $dependency = '')
314
+	{
315
+		$dependency = $this->get_alias($dependency);
316
+		return $this->has_dependency_for_class($class_name, $dependency)
317
+			? $this->_dependency_map[$class_name][$dependency]
318
+			: EE_Dependency_Map::not_registered;
319
+	}
320
+
321
+
322
+
323
+	/**
324
+	 * @param string $class_name
325
+	 * @return string | Closure
326
+	 */
327
+	public function class_loader($class_name)
328
+	{
329
+		$class_name = $this->get_alias($class_name);
330
+		return isset($this->_class_loaders[$class_name]) ? $this->_class_loaders[$class_name] : '';
331
+	}
332
+
333
+
334
+
335
+	/**
336
+	 * @return array
337
+	 */
338
+	public function class_loaders()
339
+	{
340
+		return $this->_class_loaders;
341
+	}
342
+
343
+
344
+
345
+	/**
346
+	 * adds an alias for a classname
347
+	 *
348
+	 * @param string $class_name the class name that should be used (concrete class to replace interface)
349
+	 * @param string $alias      the class name that would be type hinted for (abstract parent or interface)
350
+	 * @param string $for_class  the class that has the dependency (is type hinting for the interface)
351
+	 */
352
+	public function add_alias($class_name, $alias, $for_class = '')
353
+	{
354
+		if ($for_class !== '') {
355
+			if (! isset($this->_aliases[$for_class])) {
356
+				$this->_aliases[$for_class] = array();
357
+			}
358
+			$this->_aliases[$for_class][$class_name] = $alias;
359
+		}
360
+		$this->_aliases[$class_name] = $alias;
361
+	}
362
+
363
+
364
+
365
+	/**
366
+	 * returns TRUE if the provided class name has an alias
367
+	 *
368
+	 * @param string $class_name
369
+	 * @param string $for_class
370
+	 * @return bool
371
+	 */
372
+	public function has_alias($class_name = '', $for_class = '')
373
+	{
374
+		return isset($this->_aliases[$for_class], $this->_aliases[$for_class][$class_name])
375
+			   || (
376
+				   isset($this->_aliases[$class_name])
377
+				   && ! is_array($this->_aliases[$class_name])
378
+			   );
379
+	}
380
+
381
+
382
+
383
+	/**
384
+	 * returns alias for class name if one exists, otherwise returns the original classname
385
+	 * functions recursively, so that multiple aliases can be used to drill down to a classname
386
+	 *  for example:
387
+	 *      if the following two entries were added to the _aliases array:
388
+	 *          array(
389
+	 *              'interface_alias'           => 'some\namespace\interface'
390
+	 *              'some\namespace\interface'  => 'some\namespace\classname'
391
+	 *          )
392
+	 *      then one could use EE_Registry::instance()->create( 'interface_alias' )
393
+	 *      to load an instance of 'some\namespace\classname'
394
+	 *
395
+	 * @param string $class_name
396
+	 * @param string $for_class
397
+	 * @return string
398
+	 */
399
+	public function get_alias($class_name = '', $for_class = '')
400
+	{
401
+		if (! $this->has_alias($class_name, $for_class)) {
402
+			return $class_name;
403
+		}
404
+		if ($for_class !== '' && isset($this->_aliases[ $for_class ][ $class_name ])) {
405
+			return $this->get_alias($this->_aliases[$for_class][$class_name], $for_class);
406
+		}
407
+		return $this->get_alias($this->_aliases[$class_name]);
408
+	}
409
+
410
+
411
+
412
+	/**
413
+	 * Registers the core dependencies and whether a previously instantiated object should be loaded from the cache,
414
+	 * if one exists, or whether a new object should be generated every time the requested class is loaded.
415
+	 * This is done by using the following class constants:
416
+	 *        EE_Dependency_Map::load_from_cache - loads previously instantiated object
417
+	 *        EE_Dependency_Map::load_new_object - generates a new object every time
418
+	 */
419
+	protected function _register_core_dependencies()
420
+	{
421
+		$this->_dependency_map = array(
422
+			'EE_Request_Handler'                                                                                          => array(
423
+				'EE_Request' => EE_Dependency_Map::load_from_cache,
424
+			),
425
+			'EE_System'                                                                                                   => array(
426
+				'EE_Registry'                                => EE_Dependency_Map::load_from_cache,
427
+				'EventEspresso\core\services\loaders\Loader' => EE_Dependency_Map::load_from_cache,
428
+				'EE_Maintenance_Mode'                        => EE_Dependency_Map::load_from_cache,
429
+			),
430
+			'EE_Session'                                                                                                  => array(
431
+				'EventEspresso\core\services\cache\TransientCacheStorage' => EE_Dependency_Map::load_from_cache,
432
+				'EE_Encryption'                                           => EE_Dependency_Map::load_from_cache,
433
+			),
434
+			'EE_Cart'                                                                                                     => array(
435
+				'EE_Session' => EE_Dependency_Map::load_from_cache,
436
+			),
437
+			'EE_Front_Controller'                                                                                         => array(
438
+				'EE_Registry'              => EE_Dependency_Map::load_from_cache,
439
+				'EE_Request_Handler'       => EE_Dependency_Map::load_from_cache,
440
+				'EE_Module_Request_Router' => EE_Dependency_Map::load_from_cache,
441
+			),
442
+			'EE_Messenger_Collection_Loader'                                                                              => array(
443
+				'EE_Messenger_Collection' => EE_Dependency_Map::load_new_object,
444
+			),
445
+			'EE_Message_Type_Collection_Loader'                                                                           => array(
446
+				'EE_Message_Type_Collection' => EE_Dependency_Map::load_new_object,
447
+			),
448
+			'EE_Message_Resource_Manager'                                                                                 => array(
449
+				'EE_Messenger_Collection_Loader'    => EE_Dependency_Map::load_new_object,
450
+				'EE_Message_Type_Collection_Loader' => EE_Dependency_Map::load_new_object,
451
+				'EEM_Message_Template_Group'        => EE_Dependency_Map::load_from_cache,
452
+			),
453
+			'EE_Message_Factory'                                                                                          => array(
454
+				'EE_Message_Resource_Manager' => EE_Dependency_Map::load_from_cache,
455
+			),
456
+			'EE_messages'                                                                                                 => array(
457
+				'EE_Message_Resource_Manager' => EE_Dependency_Map::load_from_cache,
458
+			),
459
+			'EE_Messages_Generator'                                                                                       => array(
460
+				'EE_Messages_Queue'                    => EE_Dependency_Map::load_new_object,
461
+				'EE_Messages_Data_Handler_Collection'  => EE_Dependency_Map::load_new_object,
462
+				'EE_Message_Template_Group_Collection' => EE_Dependency_Map::load_new_object,
463
+				'EEH_Parse_Shortcodes'                 => EE_Dependency_Map::load_from_cache,
464
+			),
465
+			'EE_Messages_Processor'                                                                                       => array(
466
+				'EE_Message_Resource_Manager' => EE_Dependency_Map::load_from_cache,
467
+			),
468
+			'EE_Messages_Queue'                                                                                           => array(
469
+				'EE_Message_Repository' => EE_Dependency_Map::load_new_object,
470
+			),
471
+			'EE_Messages_Template_Defaults'                                                                               => array(
472
+				'EEM_Message_Template_Group' => EE_Dependency_Map::load_from_cache,
473
+				'EEM_Message_Template'       => EE_Dependency_Map::load_from_cache,
474
+			),
475
+			'EE_Message_To_Generate_From_Request'                                                                         => array(
476
+				'EE_Message_Resource_Manager' => EE_Dependency_Map::load_from_cache,
477
+				'EE_Request_Handler'          => EE_Dependency_Map::load_from_cache,
478
+			),
479
+			'EventEspresso\core\services\commands\CommandBus'                                                             => array(
480
+				'EventEspresso\core\services\commands\CommandHandlerManager' => EE_Dependency_Map::load_from_cache,
481
+			),
482
+			'EventEspresso\services\commands\CommandHandler'                                                              => array(
483
+				'EE_Registry'         => EE_Dependency_Map::load_from_cache,
484
+				'CommandBusInterface' => EE_Dependency_Map::load_from_cache,
485
+			),
486
+			'EventEspresso\core\services\commands\CommandHandlerManager'                                                  => array(
487
+				'EventEspresso\core\services\loaders\Loader' => EE_Dependency_Map::load_from_cache,
488
+			),
489
+			'EventEspresso\core\services\commands\CompositeCommandHandler'                                                => array(
490
+				'EventEspresso\core\services\commands\CommandBus'     => EE_Dependency_Map::load_from_cache,
491
+				'EventEspresso\core\services\commands\CommandFactory' => EE_Dependency_Map::load_from_cache,
492
+			),
493
+			'EventEspresso\core\services\commands\CommandFactory'                                                         => array(
494
+				'EventEspresso\core\services\loaders\Loader' => EE_Dependency_Map::load_from_cache,
495
+			),
496
+			'EventEspresso\core\services\commands\middleware\CapChecker'                                                  => array(
497
+				'EventEspresso\core\domain\services\capabilities\CapabilitiesChecker' => EE_Dependency_Map::load_from_cache,
498
+			),
499
+			'EventEspresso\core\domain\services\capabilities\CapabilitiesChecker'                                         => array(
500
+				'EE_Capabilities' => EE_Dependency_Map::load_from_cache,
501
+			),
502
+			'EventEspresso\core\domain\services\capabilities\RegistrationsCapChecker'                                     => array(
503
+				'EE_Capabilities' => EE_Dependency_Map::load_from_cache,
504
+			),
505
+			'EventEspresso\core\services\commands\registration\CreateRegistrationCommandHandler'                          => array(
506
+				'EventEspresso\core\domain\services\registration\CreateRegistrationService' => EE_Dependency_Map::load_from_cache,
507
+			),
508
+			'EventEspresso\core\services\commands\registration\CopyRegistrationDetailsCommandHandler'                     => array(
509
+				'EventEspresso\core\domain\services\registration\CopyRegistrationService' => EE_Dependency_Map::load_from_cache,
510
+			),
511
+			'EventEspresso\core\services\commands\registration\CopyRegistrationPaymentsCommandHandler'                    => array(
512
+				'EventEspresso\core\domain\services\registration\CopyRegistrationService' => EE_Dependency_Map::load_from_cache,
513
+			),
514
+			'EventEspresso\core\services\commands\registration\CancelRegistrationAndTicketLineItemCommandHandler'         => array(
515
+				'EventEspresso\core\domain\services\registration\CancelTicketLineItemService' => EE_Dependency_Map::load_from_cache,
516
+			),
517
+			'EventEspresso\core\services\commands\registration\UpdateRegistrationAndTransactionAfterChangeCommandHandler' => array(
518
+				'EventEspresso\core\domain\services\registration\UpdateRegistrationService' => EE_Dependency_Map::load_from_cache,
519
+			),
520
+			'EventEspresso\core\services\commands\ticket\CreateTicketLineItemCommandHandler'                              => array(
521
+				'EventEspresso\core\domain\services\ticket\CreateTicketLineItemService' => EE_Dependency_Map::load_from_cache,
522
+			),
523
+			'EventEspresso\core\services\commands\ticket\CancelTicketLineItemCommandHandler'                              => array(
524
+				'EventEspresso\core\domain\services\ticket\CancelTicketLineItemService' => EE_Dependency_Map::load_from_cache,
525
+			),
526
+			'EventEspresso\core\domain\services\registration\CancelRegistrationService'                                   => array(
527
+				'EventEspresso\core\domain\services\ticket\CancelTicketLineItemService' => EE_Dependency_Map::load_from_cache,
528
+			),
529
+			'EventEspresso\core\services\commands\attendee\CreateAttendeeCommandHandler'                                  => array(
530
+				'EEM_Attendee' => EE_Dependency_Map::load_from_cache,
531
+			),
532
+			'EventEspresso\core\services\database\TableManager'                                                           => array(
533
+				'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
534
+			),
535
+			'EE_Data_Migration_Class_Base'                                                                                => array(
536
+				'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
537
+				'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
538
+			),
539
+			'EE_DMS_Core_4_1_0'                                                                                           => array(
540
+				'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
541
+				'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
542
+			),
543
+			'EE_DMS_Core_4_2_0'                                                                                           => array(
544
+				'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
545
+				'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
546
+			),
547
+			'EE_DMS_Core_4_3_0'                                                                                           => array(
548
+				'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
549
+				'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
550
+			),
551
+			'EE_DMS_Core_4_4_0'                                                                                           => array(
552
+				'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
553
+				'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
554
+			),
555
+			'EE_DMS_Core_4_5_0'                                                                                           => array(
556
+				'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
557
+				'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
558
+			),
559
+			'EE_DMS_Core_4_6_0'                                                                                           => array(
560
+				'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
561
+				'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
562
+			),
563
+			'EE_DMS_Core_4_7_0'                                                                                           => array(
564
+				'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
565
+				'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
566
+			),
567
+			'EE_DMS_Core_4_8_0'                                                                                           => array(
568
+				'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
569
+				'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
570
+			),
571
+			'EE_DMS_Core_4_9_0'                                                                                           => array(
572
+				'EventEspresso\core\services\database\TableAnalysis' => EE_Dependency_Map::load_from_cache,
573
+				'EventEspresso\core\services\database\TableManager'  => EE_Dependency_Map::load_from_cache,
574
+			),
575
+			'EventEspresso\core\services\assets\Registry'                                                                 => array(
576
+				'EE_Template_Config' => EE_Dependency_Map::load_from_cache,
577
+				'EE_Currency_Config' => EE_Dependency_Map::load_from_cache,
578
+			),
579
+			'EventEspresso\core\domain\entities\shortcodes\EspressoCancelled'                                             => array(
580
+				'EventEspresso\core\services\cache\PostRelatedCacheManager' => EE_Dependency_Map::load_from_cache,
581
+			),
582
+			'EventEspresso\core\domain\entities\shortcodes\EspressoCheckout'                                              => array(
583
+				'EventEspresso\core\services\cache\PostRelatedCacheManager' => EE_Dependency_Map::load_from_cache,
584
+			),
585
+			'EventEspresso\core\domain\entities\shortcodes\EspressoEventAttendees'                                        => array(
586
+				'EventEspresso\core\services\cache\PostRelatedCacheManager' => EE_Dependency_Map::load_from_cache,
587
+			),
588
+			'EventEspresso\core\domain\entities\shortcodes\EspressoEvents'                                                => array(
589
+				'EventEspresso\core\services\cache\PostRelatedCacheManager' => EE_Dependency_Map::load_from_cache,
590
+			),
591
+			'EventEspresso\core\domain\entities\shortcodes\EspressoThankYou'                                              => array(
592
+				'EventEspresso\core\services\cache\PostRelatedCacheManager' => EE_Dependency_Map::load_from_cache,
593
+			),
594
+			'EventEspresso\core\domain\entities\shortcodes\EspressoTicketSelector'                                        => array(
595
+				'EventEspresso\core\services\cache\PostRelatedCacheManager' => EE_Dependency_Map::load_from_cache,
596
+			),
597
+			'EventEspresso\core\domain\entities\shortcodes\EspressoTxnPage'                                               => array(
598
+				'EventEspresso\core\services\cache\PostRelatedCacheManager' => EE_Dependency_Map::load_from_cache,
599
+			),
600
+			'EventEspresso\core\services\cache\BasicCacheManager'                                                         => array(
601
+				'EventEspresso\core\services\cache\TransientCacheStorage' => EE_Dependency_Map::load_from_cache,
602
+			),
603
+			'EventEspresso\core\services\cache\PostRelatedCacheManager'            => array(
604
+				'EventEspresso\core\services\cache\TransientCacheStorage' => EE_Dependency_Map::load_from_cache,
605
+			),
606
+			'EventEspresso\core\services\activation\ActivationsAndUpgradesManager' => array(
607
+				'EventEspresso\core\services\activation\ActivationHandler'   => EE_Dependency_Map::load_from_cache,
608
+				'EventEspresso\core\services\activation\RequestTypeDetector' => EE_Dependency_Map::load_from_cache,
609
+			),
610
+			'EventEspresso\core\services\activation\ActivationHandler'             => array(
611
+				'EE_Maintenance_Mode' => EE_Dependency_Map::load_from_cache,
612
+			),
613
+			'EventEspresso\core\services\activation\InitializeCore'                => array(
614
+				null,
615
+				'EE_Capabilities'           => EE_Dependency_Map::load_from_cache,
616
+				'EE_Data_Migration_Manager' => EE_Dependency_Map::load_from_cache,
617
+				'EE_Maintenance_Mode'       => EE_Dependency_Map::load_from_cache,
618
+			),
619
+			'EventEspresso\core\services\activation\InitializeAddon' => array(
620
+				null,
621
+				'EE_Data_Migration_Manager' => EE_Dependency_Map::load_from_cache,
622
+				'EE_Maintenance_Mode'       => EE_Dependency_Map::load_from_cache,
623
+				'EE_Registry'               => EE_Dependency_Map::load_from_cache,
624
+			),
625
+		);
626
+	}
627
+
628
+
629
+
630
+	/**
631
+	 * Registers how core classes are loaded.
632
+	 * This can either be done by simply providing the name of one of the EE_Registry loader methods such as:
633
+	 *        'EE_Request_Handler' => 'load_core'
634
+	 *        'EE_Messages_Queue'  => 'load_lib'
635
+	 *        'EEH_Debug_Tools'    => 'load_helper'
636
+	 * or, if greater control is required, by providing a custom closure. For example:
637
+	 *        'Some_Class' => function () {
638
+	 *            return new Some_Class();
639
+	 *        },
640
+	 * This is required for instantiating dependencies
641
+	 * where an interface has been type hinted in a class constructor. For example:
642
+	 *        'Required_Interface' => function () {
643
+	 *            return new A_Class_That_Implements_Required_Interface();
644
+	 *        },
645
+	 */
646
+	protected function _register_core_class_loaders()
647
+	{
648
+		//for PHP5.3 compat, we need to register any properties called here in a variable because `$this` cannot
649
+		//be used in a closure.
650
+		$request = &$this->_request;
651
+		$response = &$this->_response;
652
+		$loader = &$this->loader;
653
+		$this->_class_loaders = array(
654
+			//load_core
655
+			'EE_Capabilities'                      => 'load_core',
656
+			'EE_Encryption'                        => 'load_core',
657
+			'EE_Front_Controller'                  => 'load_core',
658
+			'EE_Module_Request_Router'             => 'load_core',
659
+			'EE_Registry'                          => 'load_core',
660
+			'EE_Request'                           => function () use (&$request) {
661
+				return $request;
662
+			},
663
+			'EE_Response'                          => function () use (&$response) {
664
+				return $response;
665
+			},
666
+			'EE_Request_Handler'                   => 'load_core',
667
+			'EE_Session'                           => 'load_core',
668
+			'EE_System'                            => 'load_core',
669
+			'EE_Maintenance_Mode'                  => 'load_core',
670
+			'EE_Register_CPTs'                     => 'load_core',
671
+			'EE_Admin'                             => 'load_core',
672
+			'EE_Data_Migration_Manager'            => 'load_core',
673
+			//load_lib
674
+			'EE_Message_Resource_Manager'          => 'load_lib',
675
+			'EE_Message_Type_Collection'           => 'load_lib',
676
+			'EE_Message_Type_Collection_Loader'    => 'load_lib',
677
+			'EE_Messenger_Collection'              => 'load_lib',
678
+			'EE_Messenger_Collection_Loader'       => 'load_lib',
679
+			'EE_Messages_Processor'                => 'load_lib',
680
+			'EE_Message_Repository'                => 'load_lib',
681
+			'EE_Messages_Queue'                    => 'load_lib',
682
+			'EE_Messages_Data_Handler_Collection'  => 'load_lib',
683
+			'EE_Message_Template_Group_Collection' => 'load_lib',
684
+			'EE_Messages_Generator'                => function () {
685
+				return EE_Registry::instance()->load_lib(
686
+					'Messages_Generator',
687
+					array(),
688
+					false,
689
+					false
690
+				);
691
+			},
692
+			'EE_Messages_Template_Defaults'        => function ($arguments = array()) {
693
+				return EE_Registry::instance()->load_lib(
694
+					'Messages_Template_Defaults',
695
+					$arguments,
696
+					false,
697
+					false
698
+				);
699
+			},
700
+			//load_model
701
+			'EEM_Attendee'                         => 'load_model',
702
+			'EEM_Message_Template_Group'           => 'load_model',
703
+			'EEM_Message_Template'                 => 'load_model',
704
+			//load_helper
705
+			'EEH_Parse_Shortcodes'                 => function () {
706
+				if (EE_Registry::instance()->load_helper('Parse_Shortcodes')) {
707
+					return new EEH_Parse_Shortcodes();
708
+				}
709
+				return null;
710
+			},
711
+			'EE_Template_Config'                   => function () {
712
+				return EE_Config::instance()->template_settings;
713
+			},
714
+			'EE_Currency_Config'                   => function () {
715
+				return EE_Config::instance()->currency;
716
+			},
717
+			'EventEspresso\core\services\loaders\Loader' => function () use (&$loader) {
718
+				return $loader;
719
+			},
720
+		);
721
+	}
722
+
723
+
724
+
725
+	/**
726
+	 * can be used for supplying alternate names for classes,
727
+	 * or for connecting interface names to instantiable classes
728
+	 */
729
+	protected function _register_core_aliases()
730
+	{
731
+		$this->_aliases = array(
732
+			'CommandBusInterface'                                                 => 'EventEspresso\core\services\commands\CommandBusInterface',
733
+			'EventEspresso\core\services\commands\CommandBusInterface'            => 'EventEspresso\core\services\commands\CommandBus',
734
+			'CommandHandlerManagerInterface'                                      => 'EventEspresso\core\services\commands\CommandHandlerManagerInterface',
735
+			'EventEspresso\core\services\commands\CommandHandlerManagerInterface' => 'EventEspresso\core\services\commands\CommandHandlerManager',
736
+			'CapChecker'                                                          => 'EventEspresso\core\services\commands\middleware\CapChecker',
737
+			'AddActionHook'                                                       => 'EventEspresso\core\services\commands\middleware\AddActionHook',
738
+			'CapabilitiesChecker'                                                 => 'EventEspresso\core\domain\services\capabilities\CapabilitiesChecker',
739
+			'CapabilitiesCheckerInterface'                                        => 'EventEspresso\core\domain\services\capabilities\CapabilitiesCheckerInterface',
740
+			'EventEspresso\core\domain\services\capabilities\CapabilitiesCheckerInterface' => 'EventEspresso\core\domain\services\capabilities\CapabilitiesChecker',
741
+			'CreateRegistrationService'                                           => 'EventEspresso\core\domain\services\registration\CreateRegistrationService',
742
+			'CreateRegCodeCommandHandler'                                         => 'EventEspresso\core\services\commands\registration\CreateRegCodeCommand',
743
+			'CreateRegUrlLinkCommandHandler'                                      => 'EventEspresso\core\services\commands\registration\CreateRegUrlLinkCommand',
744
+			'CreateRegistrationCommandHandler'                                    => 'EventEspresso\core\services\commands\registration\CreateRegistrationCommand',
745
+			'CopyRegistrationDetailsCommandHandler'                               => 'EventEspresso\core\services\commands\registration\CopyRegistrationDetailsCommand',
746
+			'CopyRegistrationPaymentsCommandHandler'                              => 'EventEspresso\core\services\commands\registration\CopyRegistrationPaymentsCommand',
747
+			'CancelRegistrationAndTicketLineItemCommandHandler'                   => 'EventEspresso\core\services\commands\registration\CancelRegistrationAndTicketLineItemCommandHandler',
748
+			'UpdateRegistrationAndTransactionAfterChangeCommandHandler'           => 'EventEspresso\core\services\commands\registration\UpdateRegistrationAndTransactionAfterChangeCommandHandler',
749
+			'CreateTicketLineItemCommandHandler'                                  => 'EventEspresso\core\services\commands\ticket\CreateTicketLineItemCommand',
750
+			'TableManager'                                                        => 'EventEspresso\core\services\database\TableManager',
751
+			'TableAnalysis'                                                       => 'EventEspresso\core\services\database\TableAnalysis',
752
+			'CreateTransactionCommandHandler'                                     => 'EventEspresso\core\services\commands\transaction\CreateTransactionCommandHandler',
753
+			'CreateAttendeeCommandHandler'                                        => 'EventEspresso\core\services\commands\attendee\CreateAttendeeCommandHandler',
754
+			'EspressoShortcode'                                                   => 'EventEspresso\core\services\shortcodes\EspressoShortcode',
755
+			'ShortcodeInterface'                                                  => 'EventEspresso\core\services\shortcodes\ShortcodeInterface',
756
+			'EventEspresso\core\services\shortcodes\ShortcodeInterface'           => 'EventEspresso\core\services\shortcodes\EspressoShortcode',
757
+			'EventEspresso\core\services\cache\CacheStorageInterface'             => 'EventEspresso\core\services\cache\TransientCacheStorage',
758
+			'LoaderInterface'                                                     => 'EventEspresso\core\services\loaders\LoaderInterface',
759
+			'EventEspresso\core\services\loaders\LoaderInterface'                 => 'EventEspresso\core\services\loaders\Loader',
760
+			'CommandFactoryInterface'                                             => 'EventEspresso\core\services\commands\CommandFactoryInterface',
761
+			'EventEspresso\core\services\commands\CommandFactoryInterface'        => 'EventEspresso\core\services\commands\CommandFactory',
762
+			'EventEspresso\core\domain\services\session\SessionIdentifierInterface' => 'EE_Session',
763
+			'NoticeConverterInterface'                                            => 'EventEspresso\core\services\notices\NoticeConverterInterface',
764
+			'EventEspresso\core\services\notices\NoticeConverterInterface'        => 'EventEspresso\core\services\notices\ConvertNoticesToEeErrors',
765
+			'NoticesContainerInterface'                                            => 'EventEspresso\core\services\notices\NoticesContainerInterface',
766
+			'EventEspresso\core\services\notices\NoticesContainerInterface'        => 'EventEspresso\core\services\notices\NoticesContainer',
767
+		);
768
+	}
769
+
770
+
771
+
772
+	/**
773
+	 * This is used to reset the internal map and class_loaders to their original default state at the beginning of the
774
+	 * request Primarily used by unit tests.
775
+	 */
776
+	public function reset()
777
+	{
778
+		$this->_register_core_class_loaders();
779
+		$this->_register_core_dependencies();
780
+	}
781 781
 
782 782
 
783 783
 }
Please login to merge, or discard this patch.
core/admin/EE_Admin_Page_CPT.core.php 2 patches
Indentation   +1417 added lines, -1417 removed lines patch added patch discarded remove patch
@@ -1,5 +1,5 @@  discard block
 block discarded – undo
1 1
 <?php if ( ! defined('EVENT_ESPRESSO_VERSION')) {
2
-    exit('No direct script access allowed');
2
+	exit('No direct script access allowed');
3 3
 }
4 4
 
5 5
 /**
@@ -24,470 +24,470 @@  discard block
 block discarded – undo
24 24
 {
25 25
 
26 26
 
27
-    /**
28
-     * This gets set in _setup_cpt
29
-     * It will contain the object for the custom post type.
30
-     *
31
-     * @var EE_CPT_Base
32
-     */
33
-    protected $_cpt_object;
34
-
35
-
36
-
37
-    /**
38
-     * a boolean flag to set whether the current route is a cpt route or not.
39
-     *
40
-     * @var bool
41
-     */
42
-    protected $_cpt_route = false;
43
-
44
-
45
-
46
-    /**
47
-     * This property allows cpt classes to define multiple routes as cpt routes.
48
-     * //in this array we define what the custom post type for this route is.
49
-     * array(
50
-     * 'route_name' => 'custom_post_type_slug'
51
-     * )
52
-     *
53
-     * @var array
54
-     */
55
-    protected $_cpt_routes = array();
56
-
27
+	/**
28
+	 * This gets set in _setup_cpt
29
+	 * It will contain the object for the custom post type.
30
+	 *
31
+	 * @var EE_CPT_Base
32
+	 */
33
+	protected $_cpt_object;
34
+
35
+
36
+
37
+	/**
38
+	 * a boolean flag to set whether the current route is a cpt route or not.
39
+	 *
40
+	 * @var bool
41
+	 */
42
+	protected $_cpt_route = false;
43
+
44
+
45
+
46
+	/**
47
+	 * This property allows cpt classes to define multiple routes as cpt routes.
48
+	 * //in this array we define what the custom post type for this route is.
49
+	 * array(
50
+	 * 'route_name' => 'custom_post_type_slug'
51
+	 * )
52
+	 *
53
+	 * @var array
54
+	 */
55
+	protected $_cpt_routes = array();
56
+
57 57
 
58 58
 
59
-    /**
60
-     * This simply defines what the corresponding routes WP will be redirected to after completing a post save/update.
61
-     * in this format:
62
-     * array(
63
-     * 'post_type_slug' => 'edit_route'
64
-     * )
65
-     *
66
-     * @var array
67
-     */
68
-    protected $_cpt_edit_routes = array();
69
-
70
-
71
-
72
-    /**
73
-     * If child classes set the name of their main model via the $_cpt_obj_models property, EE_Admin_Page_CPT will
74
-     * attempt to retrieve the related object model for the edit pages and assign it to _cpt_page_object. the
75
-     * _cpt_model_names property should be in the following format: array(
76
-     * 'route_defined_by_action_param' => 'Model_Name')
77
-     *
78
-     * @var array $_cpt_model_names
79
-     */
80
-    protected $_cpt_model_names = array();
81
-
82
-
83
-    /**
84
-     * @var EE_CPT_Base
85
-     */
86
-    protected $_cpt_model_obj = false;
87
-
88
-
89
-
90
-    /**
91
-     * This will hold an array of autosave containers that will be used to obtain input values and hook into the WP
92
-     * autosave so we can save our inputs on the save_post hook!  Children classes should add to this array by using
93
-     * the _register_autosave_containers() method so that we don't override any other containers already registered.
94
-     * Registration of containers should be done before load_page_dependencies() is run.
95
-     *
96
-     * @var array()
97
-     */
98
-    protected $_autosave_containers = array();
99
-    protected $_autosave_fields = array();
100
-
101
-    /**
102
-     * Array mapping from admin actions to their equivalent wp core pages for custom post types. So when a user visits
103
-     * a page for an action, it will appear as if they were visiting the wp core page for that custom post type
104
-     *
105
-     * @var array
106
-     */
107
-    protected $_pagenow_map;
108
-
109
-
110
-
111
-    /**
112
-     * This is hooked into the WordPress do_action('save_post') hook and runs after the custom post type has been
113
-     * saved.  Child classes are required to declare this method.  Typically you would use this to save any additional
114
-     * data. Keep in mind also that "save_post" runs on EVERY post update to the database. ALSO very important.  When a
115
-     * post transitions from scheduled to published, the save_post action is fired but you will NOT have any _POST data
116
-     * containing any extra info you may have from other meta saves.  So MAKE sure that you handle this accordingly.
117
-     *
118
-     * @access protected
119
-     * @abstract
120
-     * @param  string $post_id The ID of the cpt that was saved (so you can link relationally)
121
-     * @param  EE_CPT_Base $post    The post object of the cpt that was saved.
122
-     * @return void
123
-     */
124
-    abstract protected function _insert_update_cpt_item($post_id, $post);
125
-
126
-
127
-
128
-    /**
129
-     * This is hooked into the WordPress do_action('trashed_post') hook and runs after a cpt has been trashed.
130
-     *
131
-     * @abstract
132
-     * @access public
133
-     * @param  string $post_id The ID of the cpt that was trashed
134
-     * @return void
135
-     */
136
-    abstract public function trash_cpt_item($post_id);
137
-
138
-
139
-
140
-    /**
141
-     * This is hooked into the WordPress do_action('untrashed_post') hook and runs after a cpt has been untrashed
142
-     *
143
-     * @param  string $post_id theID of the cpt that was untrashed
144
-     * @return void
145
-     */
146
-    abstract public function restore_cpt_item($post_id);
147
-
148
-
149
-
150
-    /**
151
-     * This is hooked into the WordPress do_action('delete_cpt_item') hook and runs after a cpt has been fully deleted
152
-     * from the db
153
-     *
154
-     * @param  string $post_id the ID of the cpt that was deleted
155
-     * @return void
156
-     */
157
-    abstract public function delete_cpt_item($post_id);
158
-
159
-
160
-
161
-    /**
162
-     * Just utilizing the method EE_Admin exposes for doing things before page setup.
163
-     *
164
-     * @access protected
165
-     * @return void
166
-     */
167
-    protected function _before_page_setup()
168
-    {
169
-        $page = isset($this->_req_data['page']) ? $this->_req_data['page'] : $this->page_slug;
170
-        $this->_cpt_routes = array_merge(array(
171
-            'create_new' => $this->page_slug,
172
-            'edit'       => $this->page_slug,
173
-            'trash'      => $this->page_slug,
174
-        ), $this->_cpt_routes);
175
-        //let's see if the current route has a value for cpt_object_slug if it does we use that instead of the page
176
-        $this->_cpt_object = isset($this->_req_data['action']) && isset($this->_cpt_routes[$this->_req_data['action']])
177
-            ? get_post_type_object($this->_cpt_routes[$this->_req_data['action']])
178
-            : get_post_type_object($page);
179
-        //tweak pagenow for page loading.
180
-        if ( ! $this->_pagenow_map) {
181
-            $this->_pagenow_map = array(
182
-                'create_new' => 'post-new.php',
183
-                'edit'       => 'post.php',
184
-                'trash'      => 'post.php',
185
-            );
186
-        }
187
-        add_action('current_screen', array($this, 'modify_pagenow'));
188
-        //TODO the below will need to be reworked to account for the cpt routes that are NOT based off of page but action param.
189
-        //get current page from autosave
190
-        $current_page = isset($this->_req_data['ee_autosave_data']['ee-cpt-hidden-inputs']['current_page'])
191
-            ? $this->_req_data['ee_autosave_data']['ee-cpt-hidden-inputs']['current_page']
192
-            : null;
193
-        $this->_current_page = isset($this->_req_data['current_page'])
194
-            ? $this->_req_data['current_page']
195
-            : $current_page;
196
-        //autosave... make sure its only for the correct page
197
-        //if ( ! empty($this->_current_page) && $this->_current_page == $this->page_slug) {
198
-            //setup autosave ajax hook
199
-            //add_action('wp_ajax_ee-autosave', array( $this, 'do_extra_autosave_stuff' ), 10 ); //TODO reactivate when 4.2 autosave is implemented
200
-        //}
201
-    }
202
-
203
-
204
-
205
-    /**
206
-     * Simply ensure that we simulate the correct post route for cpt screens
207
-     *
208
-     * @param WP_Screen $current_screen
209
-     * @return void
210
-     */
211
-    public function modify_pagenow($current_screen)
212
-    {
213
-        global $pagenow, $hook_suffix;
214
-        //possibly reset pagenow.
215
-        if ( ! empty($this->_req_data['page'])
216
-             && $this->_req_data['page'] == $this->page_slug
217
-             && ! empty($this->_req_data['action'])
218
-             && isset($this->_pagenow_map[$this->_req_data['action']])
219
-        ) {
220
-            $pagenow = $this->_pagenow_map[$this->_req_data['action']];
221
-            $hook_suffix = $pagenow;
222
-        }
223
-    }
224
-
225
-
226
-
227
-    /**
228
-     * This method is used to register additional autosave containers to the _autosave_containers property.
229
-     *
230
-     * @todo We should automate this at some point by creating a wrapper for add_post_metabox and in our wrapper we
231
-     *       automatically register the id for the post metabox as a container.
232
-     * @param  array $ids an array of ids for containers that hold form inputs we want autosave to pickup.  Typically
233
-     *                    you would send along the id of a metabox container.
234
-     * @return void
235
-     */
236
-    protected function _register_autosave_containers($ids)
237
-    {
238
-        $this->_autosave_containers = array_merge($this->_autosave_fields, (array)$ids);
239
-    }
240
-
241
-
242
-
243
-    /**
244
-     * Something nifty.  We're going to loop through all the registered metaboxes and if the CALLBACK is an instance of
245
-     * EE_Admin_Page OR EE_Admin_Hooks, then we'll add the id to our _autosave_containers array.
246
-     */
247
-    protected function _set_autosave_containers()
248
-    {
249
-        global $wp_meta_boxes;
250
-        $containers = array();
251
-        if (empty($wp_meta_boxes)) {
252
-            return;
253
-        }
254
-        $current_metaboxes = isset($wp_meta_boxes[$this->page_slug]) ? $wp_meta_boxes[$this->page_slug] : array();
255
-        foreach ($current_metaboxes as $box_context) {
256
-            foreach ($box_context as $box_details) {
257
-                foreach ($box_details as $box) {
258
-                    if (
259
-                        is_array($box['callback'])
260
-                        && (
261
-                            $box['callback'][0] instanceof EE_Admin_Page
262
-                            || $box['callback'][0] instanceof EE_Admin_Hooks
263
-                        )
264
-                    ) {
265
-                        $containers[] = $box['id'];
266
-                    }
267
-                }
268
-            }
269
-        }
270
-        $this->_autosave_containers = array_merge($this->_autosave_containers, $containers);
271
-        //add hidden inputs container
272
-        $this->_autosave_containers[] = 'ee-cpt-hidden-inputs';
273
-    }
274
-
275
-
276
-
277
-    protected function _load_autosave_scripts_styles()
278
-    {
279
-        /*wp_register_script('cpt-autosave', EE_ADMIN_URL . 'assets/ee-cpt-autosave.js', array('ee-serialize-full-array', 'event_editor_js'), EVENT_ESPRESSO_VERSION, TRUE );
59
+	/**
60
+	 * This simply defines what the corresponding routes WP will be redirected to after completing a post save/update.
61
+	 * in this format:
62
+	 * array(
63
+	 * 'post_type_slug' => 'edit_route'
64
+	 * )
65
+	 *
66
+	 * @var array
67
+	 */
68
+	protected $_cpt_edit_routes = array();
69
+
70
+
71
+
72
+	/**
73
+	 * If child classes set the name of their main model via the $_cpt_obj_models property, EE_Admin_Page_CPT will
74
+	 * attempt to retrieve the related object model for the edit pages and assign it to _cpt_page_object. the
75
+	 * _cpt_model_names property should be in the following format: array(
76
+	 * 'route_defined_by_action_param' => 'Model_Name')
77
+	 *
78
+	 * @var array $_cpt_model_names
79
+	 */
80
+	protected $_cpt_model_names = array();
81
+
82
+
83
+	/**
84
+	 * @var EE_CPT_Base
85
+	 */
86
+	protected $_cpt_model_obj = false;
87
+
88
+
89
+
90
+	/**
91
+	 * This will hold an array of autosave containers that will be used to obtain input values and hook into the WP
92
+	 * autosave so we can save our inputs on the save_post hook!  Children classes should add to this array by using
93
+	 * the _register_autosave_containers() method so that we don't override any other containers already registered.
94
+	 * Registration of containers should be done before load_page_dependencies() is run.
95
+	 *
96
+	 * @var array()
97
+	 */
98
+	protected $_autosave_containers = array();
99
+	protected $_autosave_fields = array();
100
+
101
+	/**
102
+	 * Array mapping from admin actions to their equivalent wp core pages for custom post types. So when a user visits
103
+	 * a page for an action, it will appear as if they were visiting the wp core page for that custom post type
104
+	 *
105
+	 * @var array
106
+	 */
107
+	protected $_pagenow_map;
108
+
109
+
110
+
111
+	/**
112
+	 * This is hooked into the WordPress do_action('save_post') hook and runs after the custom post type has been
113
+	 * saved.  Child classes are required to declare this method.  Typically you would use this to save any additional
114
+	 * data. Keep in mind also that "save_post" runs on EVERY post update to the database. ALSO very important.  When a
115
+	 * post transitions from scheduled to published, the save_post action is fired but you will NOT have any _POST data
116
+	 * containing any extra info you may have from other meta saves.  So MAKE sure that you handle this accordingly.
117
+	 *
118
+	 * @access protected
119
+	 * @abstract
120
+	 * @param  string $post_id The ID of the cpt that was saved (so you can link relationally)
121
+	 * @param  EE_CPT_Base $post    The post object of the cpt that was saved.
122
+	 * @return void
123
+	 */
124
+	abstract protected function _insert_update_cpt_item($post_id, $post);
125
+
126
+
127
+
128
+	/**
129
+	 * This is hooked into the WordPress do_action('trashed_post') hook and runs after a cpt has been trashed.
130
+	 *
131
+	 * @abstract
132
+	 * @access public
133
+	 * @param  string $post_id The ID of the cpt that was trashed
134
+	 * @return void
135
+	 */
136
+	abstract public function trash_cpt_item($post_id);
137
+
138
+
139
+
140
+	/**
141
+	 * This is hooked into the WordPress do_action('untrashed_post') hook and runs after a cpt has been untrashed
142
+	 *
143
+	 * @param  string $post_id theID of the cpt that was untrashed
144
+	 * @return void
145
+	 */
146
+	abstract public function restore_cpt_item($post_id);
147
+
148
+
149
+
150
+	/**
151
+	 * This is hooked into the WordPress do_action('delete_cpt_item') hook and runs after a cpt has been fully deleted
152
+	 * from the db
153
+	 *
154
+	 * @param  string $post_id the ID of the cpt that was deleted
155
+	 * @return void
156
+	 */
157
+	abstract public function delete_cpt_item($post_id);
158
+
159
+
160
+
161
+	/**
162
+	 * Just utilizing the method EE_Admin exposes for doing things before page setup.
163
+	 *
164
+	 * @access protected
165
+	 * @return void
166
+	 */
167
+	protected function _before_page_setup()
168
+	{
169
+		$page = isset($this->_req_data['page']) ? $this->_req_data['page'] : $this->page_slug;
170
+		$this->_cpt_routes = array_merge(array(
171
+			'create_new' => $this->page_slug,
172
+			'edit'       => $this->page_slug,
173
+			'trash'      => $this->page_slug,
174
+		), $this->_cpt_routes);
175
+		//let's see if the current route has a value for cpt_object_slug if it does we use that instead of the page
176
+		$this->_cpt_object = isset($this->_req_data['action']) && isset($this->_cpt_routes[$this->_req_data['action']])
177
+			? get_post_type_object($this->_cpt_routes[$this->_req_data['action']])
178
+			: get_post_type_object($page);
179
+		//tweak pagenow for page loading.
180
+		if ( ! $this->_pagenow_map) {
181
+			$this->_pagenow_map = array(
182
+				'create_new' => 'post-new.php',
183
+				'edit'       => 'post.php',
184
+				'trash'      => 'post.php',
185
+			);
186
+		}
187
+		add_action('current_screen', array($this, 'modify_pagenow'));
188
+		//TODO the below will need to be reworked to account for the cpt routes that are NOT based off of page but action param.
189
+		//get current page from autosave
190
+		$current_page = isset($this->_req_data['ee_autosave_data']['ee-cpt-hidden-inputs']['current_page'])
191
+			? $this->_req_data['ee_autosave_data']['ee-cpt-hidden-inputs']['current_page']
192
+			: null;
193
+		$this->_current_page = isset($this->_req_data['current_page'])
194
+			? $this->_req_data['current_page']
195
+			: $current_page;
196
+		//autosave... make sure its only for the correct page
197
+		//if ( ! empty($this->_current_page) && $this->_current_page == $this->page_slug) {
198
+			//setup autosave ajax hook
199
+			//add_action('wp_ajax_ee-autosave', array( $this, 'do_extra_autosave_stuff' ), 10 ); //TODO reactivate when 4.2 autosave is implemented
200
+		//}
201
+	}
202
+
203
+
204
+
205
+	/**
206
+	 * Simply ensure that we simulate the correct post route for cpt screens
207
+	 *
208
+	 * @param WP_Screen $current_screen
209
+	 * @return void
210
+	 */
211
+	public function modify_pagenow($current_screen)
212
+	{
213
+		global $pagenow, $hook_suffix;
214
+		//possibly reset pagenow.
215
+		if ( ! empty($this->_req_data['page'])
216
+			 && $this->_req_data['page'] == $this->page_slug
217
+			 && ! empty($this->_req_data['action'])
218
+			 && isset($this->_pagenow_map[$this->_req_data['action']])
219
+		) {
220
+			$pagenow = $this->_pagenow_map[$this->_req_data['action']];
221
+			$hook_suffix = $pagenow;
222
+		}
223
+	}
224
+
225
+
226
+
227
+	/**
228
+	 * This method is used to register additional autosave containers to the _autosave_containers property.
229
+	 *
230
+	 * @todo We should automate this at some point by creating a wrapper for add_post_metabox and in our wrapper we
231
+	 *       automatically register the id for the post metabox as a container.
232
+	 * @param  array $ids an array of ids for containers that hold form inputs we want autosave to pickup.  Typically
233
+	 *                    you would send along the id of a metabox container.
234
+	 * @return void
235
+	 */
236
+	protected function _register_autosave_containers($ids)
237
+	{
238
+		$this->_autosave_containers = array_merge($this->_autosave_fields, (array)$ids);
239
+	}
240
+
241
+
242
+
243
+	/**
244
+	 * Something nifty.  We're going to loop through all the registered metaboxes and if the CALLBACK is an instance of
245
+	 * EE_Admin_Page OR EE_Admin_Hooks, then we'll add the id to our _autosave_containers array.
246
+	 */
247
+	protected function _set_autosave_containers()
248
+	{
249
+		global $wp_meta_boxes;
250
+		$containers = array();
251
+		if (empty($wp_meta_boxes)) {
252
+			return;
253
+		}
254
+		$current_metaboxes = isset($wp_meta_boxes[$this->page_slug]) ? $wp_meta_boxes[$this->page_slug] : array();
255
+		foreach ($current_metaboxes as $box_context) {
256
+			foreach ($box_context as $box_details) {
257
+				foreach ($box_details as $box) {
258
+					if (
259
+						is_array($box['callback'])
260
+						&& (
261
+							$box['callback'][0] instanceof EE_Admin_Page
262
+							|| $box['callback'][0] instanceof EE_Admin_Hooks
263
+						)
264
+					) {
265
+						$containers[] = $box['id'];
266
+					}
267
+				}
268
+			}
269
+		}
270
+		$this->_autosave_containers = array_merge($this->_autosave_containers, $containers);
271
+		//add hidden inputs container
272
+		$this->_autosave_containers[] = 'ee-cpt-hidden-inputs';
273
+	}
274
+
275
+
276
+
277
+	protected function _load_autosave_scripts_styles()
278
+	{
279
+		/*wp_register_script('cpt-autosave', EE_ADMIN_URL . 'assets/ee-cpt-autosave.js', array('ee-serialize-full-array', 'event_editor_js'), EVENT_ESPRESSO_VERSION, TRUE );
280 280
         wp_enqueue_script('cpt-autosave');/**/ //todo re-enable when we start doing autosave again in 4.2
281 281
 
282
-        //filter _autosave_containers
283
-        $containers = apply_filters('FHEE__EE_Admin_Page_CPT___load_autosave_scripts_styles__containers',
284
-            $this->_autosave_containers, $this);
285
-        $containers = apply_filters('FHEE__EE_Admin_Page_CPT__' . get_class($this) . '___load_autosave_scripts_styles__containers',
286
-            $containers, $this);
287
-
288
-        wp_localize_script('event_editor_js', 'EE_AUTOSAVE_IDS',
289
-            $containers); //todo once we enable autosaves, this needs to be switched to localize with "cpt-autosave"
290
-
291
-        $unsaved_data_msg = array(
292
-            'eventmsg'     => sprintf(__("The changes you made to this %s will be lost if you navigate away from this page.",
293
-                'event_espresso'), $this->_cpt_object->labels->singular_name),
294
-            'inputChanged' => 0,
295
-        );
296
-        wp_localize_script('event_editor_js', 'UNSAVED_DATA_MSG', $unsaved_data_msg);
297
-    }
298
-
299
-
300
-
301
-    public function load_page_dependencies()
302
-    {
303
-        try {
304
-            $this->_load_page_dependencies();
305
-        } catch (EE_Error $e) {
306
-            $e->get_error();
307
-        }
308
-    }
309
-
310
-
311
-
312
-    /**
313
-     * overloading the EE_Admin_Page parent load_page_dependencies so we can get the cpt stuff added in appropriately
314
-     *
315
-     * @access protected
316
-     * @return void
317
-     */
318
-    protected function _load_page_dependencies()
319
-    {
320
-        //we only add stuff if this is a cpt_route!
321
-        if ( ! $this->_cpt_route) {
322
-            parent::_load_page_dependencies();
323
-            return;
324
-        }
325
-        // now let's do some automatic filters into the wp_system
326
-        // and we'll check to make sure the CHILD class
327
-        // automatically has the required methods in place.
328
-        // the following filters are for setting all the redirects
329
-        // on DEFAULT WP custom post type actions
330
-        // let's add a hidden input to the post-edit form
331
-        // so we know when we have to trigger our custom redirects!
332
-        // Otherwise the redirects will happen on ALL post saves which wouldn't be good of course!
333
-        add_action('edit_form_after_title', array($this, 'cpt_post_form_hidden_input'));
334
-        // inject our Admin page nav tabs...
335
-        // let's make sure the nav tabs are set if they aren't already
336
-        // if ( empty( $this->_nav_tabs ) ) $this->_set_nav_tabs();
337
-        add_action('post_edit_form_tag', array($this, 'inject_nav_tabs'));
338
-        // modify the post_updated messages array
339
-        add_action('post_updated_messages', array($this, 'post_update_messages'), 10);
340
-        // add shortlink button to cpt edit screens.  We can do this as a universal thing BECAUSE,
341
-        // cpts use the same format for shortlinks as posts!
342
-        add_filter('pre_get_shortlink', array($this, 'add_shortlink_button_to_editor'), 10, 4);
343
-        // This basically allows us to change the title of the "publish" metabox area
344
-        // on CPT pages by setting a 'publishbox' value in the $_labels property array in the child class.
345
-        if ( ! empty($this->_labels['publishbox'])) {
346
-            $box_label = is_array($this->_labels['publishbox'])
347
-                         && isset($this->_labels['publishbox'][$this->_req_action])
348
-                    ? $this->_labels['publishbox'][$this->_req_action]
349
-                    : $this->_labels['publishbox'];
350
-            add_meta_box(
351
-                'submitdiv',
352
-                $box_label,
353
-                'post_submit_meta_box',
354
-                $this->_cpt_routes[$this->_req_action],
355
-                'side',
356
-                'core'
357
-            );
358
-        }
359
-        //let's add page_templates metabox if this cpt added support for it.
360
-        if ($this->_supports_page_templates($this->_cpt_object->name)) {
361
-            add_meta_box(
362
-                'page_templates',
363
-                __('Page Template', 'event_espresso'),
364
-                array($this, 'page_template_meta_box'),
365
-                $this->_cpt_routes[$this->_req_action],
366
-                'side',
367
-                'default'
368
-            );
369
-        }
370
-        //this is a filter that allows the addition of extra html after the permalink field on the wp post edit-form
371
-        if (method_exists($this, 'extra_permalink_field_buttons')) {
372
-            add_filter('get_sample_permalink_html', array($this, 'extra_permalink_field_buttons'), 10, 4);
373
-        }
374
-        //add preview button
375
-        add_filter('get_sample_permalink_html', array($this, 'preview_button_html'), 5, 4);
376
-        //insert our own post_stati dropdown
377
-        add_action('post_submitbox_misc_actions', array($this, 'custom_post_stati_dropdown'), 10);
378
-        //This allows adding additional information to the publish post submitbox on the wp post edit form
379
-        if (method_exists($this, 'extra_misc_actions_publish_box')) {
380
-            add_action('post_submitbox_misc_actions', array($this, 'extra_misc_actions_publish_box'), 10);
381
-        }
382
-        // This allows for adding additional stuff after the title field on the wp post edit form.
383
-        // This is also before the wp_editor for post description field.
384
-        if (method_exists($this, 'edit_form_after_title')) {
385
-            add_action('edit_form_after_title', array($this, 'edit_form_after_title'), 10);
386
-        }
387
-        /**
388
-         * Filtering WP's esc_url to capture urls pointing to core wp routes so they point to our route.
389
-         */
390
-        add_filter('clean_url', array($this, 'switch_core_wp_urls_with_ours'), 10, 3);
391
-        parent::_load_page_dependencies();
392
-        // notice we are ALSO going to load the pagenow hook set for this route
393
-        // (see _before_page_setup for the reset of the pagenow global ).
394
-        // This is for any plugins that are doing things properly
395
-        // and hooking into the load page hook for core wp cpt routes.
396
-        global $pagenow;
397
-        do_action('load-' . $pagenow);
398
-        $this->modify_current_screen();
399
-        add_action('admin_enqueue_scripts', array($this, 'setup_autosave_hooks'), 30);
400
-        //we route REALLY early.
401
-        try {
402
-            $this->_route_admin_request();
403
-        } catch (EE_Error $e) {
404
-            $e->get_error();
405
-        }
406
-    }
407
-
408
-
409
-
410
-    /**
411
-     * Since we don't want users going to default core wp routes, this will check any wp urls run through the
412
-     * esc_url() method and if we see a url matching a pattern for our routes, we'll modify it to point to OUR
413
-     * route instead.
414
-     *
415
-     * @param string $good_protocol_url The escaped url.
416
-     * @param string $original_url      The original url.
417
-     * @param string $_context          The context sent to the esc_url method.
418
-     * @return string possibly a new url for our route.
419
-     */
420
-    public function switch_core_wp_urls_with_ours($good_protocol_url, $original_url, $_context)
421
-    {
422
-        $routes_to_match = array(
423
-            0 => array(
424
-                'edit.php?post_type=espresso_attendees',
425
-                'admin.php?page=espresso_registrations&action=contact_list',
426
-            ),
427
-            1 => array(
428
-                'edit.php?post_type=' . $this->_cpt_object->name,
429
-                'admin.php?page=' . $this->_cpt_object->name,
430
-            ),
431
-        );
432
-        foreach ($routes_to_match as $route_matches) {
433
-            if (strpos($good_protocol_url, $route_matches[0]) !== false) {
434
-                return str_replace($route_matches[0], $route_matches[1], $good_protocol_url);
435
-            }
436
-        }
437
-        return $good_protocol_url;
438
-    }
439
-
440
-
441
-
442
-    /**
443
-     * Determine whether the current cpt supports page templates or not.
444
-     *
445
-     * @since %VER%
446
-     * @param string $cpt_name The cpt slug we're checking on.
447
-     * @return bool True supported, false not.
448
-     */
449
-    private function _supports_page_templates($cpt_name)
450
-    {
451
-
452
-        $cpt_args = EE_Register_CPTs::get_CPTs();
453
-        $cpt_args = isset($cpt_args[$cpt_name]) ? $cpt_args[$cpt_name]['args'] : array();
454
-        $cpt_has_support = ! empty($cpt_args['page_templates']);
455
-
456
-        //if the installed version of WP is > 4.7 we do some additional checks.
457
-        if (EE_Recommended_Versions::check_wp_version('4.7','>=')) {
458
-            $post_templates = wp_get_theme()->get_post_templates();
459
-            //if there are $post_templates for this cpt, then we return false for this method because
460
-            //that means we aren't going to load our page template manager and leave that up to the native
461
-            //cpt template manager.
462
-            $cpt_has_support = ! isset($post_templates[$cpt_name]) ? $cpt_has_support : false;
463
-        }
464
-
465
-        return $cpt_has_support;
466
-    }
467
-
468
-
469
-    /**
470
-     * Callback for the page_templates metabox selector.
471
-     *
472
-     * @since %VER%
473
-     * @return void
474
-     */
475
-    public function page_template_meta_box()
476
-    {
477
-        global $post;
478
-        $template = '';
479
-
480
-        if (EE_Recommended_Versions::check_wp_version('4.7','>=')) {
481
-            $page_template_count = count(get_page_templates());
482
-        } else {
483
-            $page_template_count = count(get_page_templates($post));
484
-        };
485
-
486
-        if ($page_template_count) {
487
-            $page_template = get_post_meta($post->ID, '_wp_page_template', true);
488
-            $template      = ! empty($page_template) ? $page_template : '';
489
-        }
490
-        ?>
282
+		//filter _autosave_containers
283
+		$containers = apply_filters('FHEE__EE_Admin_Page_CPT___load_autosave_scripts_styles__containers',
284
+			$this->_autosave_containers, $this);
285
+		$containers = apply_filters('FHEE__EE_Admin_Page_CPT__' . get_class($this) . '___load_autosave_scripts_styles__containers',
286
+			$containers, $this);
287
+
288
+		wp_localize_script('event_editor_js', 'EE_AUTOSAVE_IDS',
289
+			$containers); //todo once we enable autosaves, this needs to be switched to localize with "cpt-autosave"
290
+
291
+		$unsaved_data_msg = array(
292
+			'eventmsg'     => sprintf(__("The changes you made to this %s will be lost if you navigate away from this page.",
293
+				'event_espresso'), $this->_cpt_object->labels->singular_name),
294
+			'inputChanged' => 0,
295
+		);
296
+		wp_localize_script('event_editor_js', 'UNSAVED_DATA_MSG', $unsaved_data_msg);
297
+	}
298
+
299
+
300
+
301
+	public function load_page_dependencies()
302
+	{
303
+		try {
304
+			$this->_load_page_dependencies();
305
+		} catch (EE_Error $e) {
306
+			$e->get_error();
307
+		}
308
+	}
309
+
310
+
311
+
312
+	/**
313
+	 * overloading the EE_Admin_Page parent load_page_dependencies so we can get the cpt stuff added in appropriately
314
+	 *
315
+	 * @access protected
316
+	 * @return void
317
+	 */
318
+	protected function _load_page_dependencies()
319
+	{
320
+		//we only add stuff if this is a cpt_route!
321
+		if ( ! $this->_cpt_route) {
322
+			parent::_load_page_dependencies();
323
+			return;
324
+		}
325
+		// now let's do some automatic filters into the wp_system
326
+		// and we'll check to make sure the CHILD class
327
+		// automatically has the required methods in place.
328
+		// the following filters are for setting all the redirects
329
+		// on DEFAULT WP custom post type actions
330
+		// let's add a hidden input to the post-edit form
331
+		// so we know when we have to trigger our custom redirects!
332
+		// Otherwise the redirects will happen on ALL post saves which wouldn't be good of course!
333
+		add_action('edit_form_after_title', array($this, 'cpt_post_form_hidden_input'));
334
+		// inject our Admin page nav tabs...
335
+		// let's make sure the nav tabs are set if they aren't already
336
+		// if ( empty( $this->_nav_tabs ) ) $this->_set_nav_tabs();
337
+		add_action('post_edit_form_tag', array($this, 'inject_nav_tabs'));
338
+		// modify the post_updated messages array
339
+		add_action('post_updated_messages', array($this, 'post_update_messages'), 10);
340
+		// add shortlink button to cpt edit screens.  We can do this as a universal thing BECAUSE,
341
+		// cpts use the same format for shortlinks as posts!
342
+		add_filter('pre_get_shortlink', array($this, 'add_shortlink_button_to_editor'), 10, 4);
343
+		// This basically allows us to change the title of the "publish" metabox area
344
+		// on CPT pages by setting a 'publishbox' value in the $_labels property array in the child class.
345
+		if ( ! empty($this->_labels['publishbox'])) {
346
+			$box_label = is_array($this->_labels['publishbox'])
347
+						 && isset($this->_labels['publishbox'][$this->_req_action])
348
+					? $this->_labels['publishbox'][$this->_req_action]
349
+					: $this->_labels['publishbox'];
350
+			add_meta_box(
351
+				'submitdiv',
352
+				$box_label,
353
+				'post_submit_meta_box',
354
+				$this->_cpt_routes[$this->_req_action],
355
+				'side',
356
+				'core'
357
+			);
358
+		}
359
+		//let's add page_templates metabox if this cpt added support for it.
360
+		if ($this->_supports_page_templates($this->_cpt_object->name)) {
361
+			add_meta_box(
362
+				'page_templates',
363
+				__('Page Template', 'event_espresso'),
364
+				array($this, 'page_template_meta_box'),
365
+				$this->_cpt_routes[$this->_req_action],
366
+				'side',
367
+				'default'
368
+			);
369
+		}
370
+		//this is a filter that allows the addition of extra html after the permalink field on the wp post edit-form
371
+		if (method_exists($this, 'extra_permalink_field_buttons')) {
372
+			add_filter('get_sample_permalink_html', array($this, 'extra_permalink_field_buttons'), 10, 4);
373
+		}
374
+		//add preview button
375
+		add_filter('get_sample_permalink_html', array($this, 'preview_button_html'), 5, 4);
376
+		//insert our own post_stati dropdown
377
+		add_action('post_submitbox_misc_actions', array($this, 'custom_post_stati_dropdown'), 10);
378
+		//This allows adding additional information to the publish post submitbox on the wp post edit form
379
+		if (method_exists($this, 'extra_misc_actions_publish_box')) {
380
+			add_action('post_submitbox_misc_actions', array($this, 'extra_misc_actions_publish_box'), 10);
381
+		}
382
+		// This allows for adding additional stuff after the title field on the wp post edit form.
383
+		// This is also before the wp_editor for post description field.
384
+		if (method_exists($this, 'edit_form_after_title')) {
385
+			add_action('edit_form_after_title', array($this, 'edit_form_after_title'), 10);
386
+		}
387
+		/**
388
+		 * Filtering WP's esc_url to capture urls pointing to core wp routes so they point to our route.
389
+		 */
390
+		add_filter('clean_url', array($this, 'switch_core_wp_urls_with_ours'), 10, 3);
391
+		parent::_load_page_dependencies();
392
+		// notice we are ALSO going to load the pagenow hook set for this route
393
+		// (see _before_page_setup for the reset of the pagenow global ).
394
+		// This is for any plugins that are doing things properly
395
+		// and hooking into the load page hook for core wp cpt routes.
396
+		global $pagenow;
397
+		do_action('load-' . $pagenow);
398
+		$this->modify_current_screen();
399
+		add_action('admin_enqueue_scripts', array($this, 'setup_autosave_hooks'), 30);
400
+		//we route REALLY early.
401
+		try {
402
+			$this->_route_admin_request();
403
+		} catch (EE_Error $e) {
404
+			$e->get_error();
405
+		}
406
+	}
407
+
408
+
409
+
410
+	/**
411
+	 * Since we don't want users going to default core wp routes, this will check any wp urls run through the
412
+	 * esc_url() method and if we see a url matching a pattern for our routes, we'll modify it to point to OUR
413
+	 * route instead.
414
+	 *
415
+	 * @param string $good_protocol_url The escaped url.
416
+	 * @param string $original_url      The original url.
417
+	 * @param string $_context          The context sent to the esc_url method.
418
+	 * @return string possibly a new url for our route.
419
+	 */
420
+	public function switch_core_wp_urls_with_ours($good_protocol_url, $original_url, $_context)
421
+	{
422
+		$routes_to_match = array(
423
+			0 => array(
424
+				'edit.php?post_type=espresso_attendees',
425
+				'admin.php?page=espresso_registrations&action=contact_list',
426
+			),
427
+			1 => array(
428
+				'edit.php?post_type=' . $this->_cpt_object->name,
429
+				'admin.php?page=' . $this->_cpt_object->name,
430
+			),
431
+		);
432
+		foreach ($routes_to_match as $route_matches) {
433
+			if (strpos($good_protocol_url, $route_matches[0]) !== false) {
434
+				return str_replace($route_matches[0], $route_matches[1], $good_protocol_url);
435
+			}
436
+		}
437
+		return $good_protocol_url;
438
+	}
439
+
440
+
441
+
442
+	/**
443
+	 * Determine whether the current cpt supports page templates or not.
444
+	 *
445
+	 * @since %VER%
446
+	 * @param string $cpt_name The cpt slug we're checking on.
447
+	 * @return bool True supported, false not.
448
+	 */
449
+	private function _supports_page_templates($cpt_name)
450
+	{
451
+
452
+		$cpt_args = EE_Register_CPTs::get_CPTs();
453
+		$cpt_args = isset($cpt_args[$cpt_name]) ? $cpt_args[$cpt_name]['args'] : array();
454
+		$cpt_has_support = ! empty($cpt_args['page_templates']);
455
+
456
+		//if the installed version of WP is > 4.7 we do some additional checks.
457
+		if (EE_Recommended_Versions::check_wp_version('4.7','>=')) {
458
+			$post_templates = wp_get_theme()->get_post_templates();
459
+			//if there are $post_templates for this cpt, then we return false for this method because
460
+			//that means we aren't going to load our page template manager and leave that up to the native
461
+			//cpt template manager.
462
+			$cpt_has_support = ! isset($post_templates[$cpt_name]) ? $cpt_has_support : false;
463
+		}
464
+
465
+		return $cpt_has_support;
466
+	}
467
+
468
+
469
+	/**
470
+	 * Callback for the page_templates metabox selector.
471
+	 *
472
+	 * @since %VER%
473
+	 * @return void
474
+	 */
475
+	public function page_template_meta_box()
476
+	{
477
+		global $post;
478
+		$template = '';
479
+
480
+		if (EE_Recommended_Versions::check_wp_version('4.7','>=')) {
481
+			$page_template_count = count(get_page_templates());
482
+		} else {
483
+			$page_template_count = count(get_page_templates($post));
484
+		};
485
+
486
+		if ($page_template_count) {
487
+			$page_template = get_post_meta($post->ID, '_wp_page_template', true);
488
+			$template      = ! empty($page_template) ? $page_template : '';
489
+		}
490
+		?>
491 491
         <p><strong><?php _e('Template') ?></strong></p>
492 492
         <label class="screen-reader-text" for="page_template"><?php _e('Page Template') ?></label><select
493 493
             name="page_template" id="page_template">
@@ -495,450 +495,450 @@  discard block
 block discarded – undo
495 495
         <?php page_template_dropdown($template); ?>
496 496
     </select>
497 497
         <?php
498
-    }
499
-
500
-
501
-
502
-    /**
503
-     * if this post is a draft or scheduled post then we provide a preview button for user to click
504
-     * Method is called from parent and is hooked into the wp 'get_sample_permalink_html' filter.
505
-     *
506
-     * @param  string $return    the current html
507
-     * @param  int    $id        the post id for the page
508
-     * @param  string $new_title What the title is
509
-     * @param  string $new_slug  what the slug is
510
-     * @return string            The new html string for the permalink area
511
-     */
512
-    public function preview_button_html($return, $id, $new_title, $new_slug)
513
-    {
514
-        $post = get_post($id);
515
-        if ('publish' !== get_post_status($post)) {
516
-            //include shims for the `get_preview_post_link` function
517
-            require_once( EE_CORE . 'wordpress-shims.php' );
518
-            $return .= '<span_id="view-post-btn"><a target="_blank" href="'
519
-                       . get_preview_post_link($id)
520
-                       . '" class="button button-small">'
521
-                       . __('Preview', 'event_espresso')
522
-                       . '</a></span>'
523
-                       . "\n";
524
-        }
525
-        return $return;
526
-    }
527
-
528
-
529
-
530
-    /**
531
-     * add our custom post stati dropdown on the wp post page for this cpt
532
-     *
533
-     * @return void
534
-     */
535
-    public function custom_post_stati_dropdown()
536
-    {
537
-
538
-        $statuses         = $this->_cpt_model_obj->get_custom_post_statuses();
539
-        $cur_status_label = array_key_exists($this->_cpt_model_obj->status(), $statuses)
540
-            ? $statuses[$this->_cpt_model_obj->status()]
541
-            : '';
542
-        $template_args    = array(
543
-            'cur_status'            => $this->_cpt_model_obj->status(),
544
-            'statuses'              => $statuses,
545
-            'cur_status_label'      => $cur_status_label,
546
-            'localized_status_save' => sprintf(__('Save %s', 'event_espresso'), $cur_status_label),
547
-        );
548
-        //we'll add a trash post status (WP doesn't add one for some reason)
549
-        if ($this->_cpt_model_obj->status() === 'trash') {
550
-            $template_args['cur_status_label'] = __('Trashed', 'event_espresso');
551
-            $statuses['trash']                 = __('Trashed', 'event_espresso');
552
-            $template_args['statuses']         = $statuses;
553
-        }
554
-
555
-        $template = EE_ADMIN_TEMPLATE . 'status_dropdown.template.php';
556
-        EEH_Template::display_template($template, $template_args);
557
-    }
558
-
559
-
560
-
561
-    public function setup_autosave_hooks()
562
-    {
563
-        $this->_set_autosave_containers();
564
-        $this->_load_autosave_scripts_styles();
565
-    }
566
-
567
-
568
-
569
-    /**
570
-     * This is run on all WordPress autosaves AFTER the autosave is complete and sends along a $_POST object (available
571
-     * in $this->_req_data) containing: post_ID of the saved post autosavenonce for the saved post We'll do the check
572
-     * for the nonce in here, but then this method looks for two things:
573
-     * 1. Execute a method (if exists) matching 'ee_autosave_' and appended with the given route. OR
574
-     * 2. do_actions() for global or class specific actions that have been registered (for plugins/addons not in an
575
-     * EE_Admin_Page class. PLEASE NOTE: Data will be returned using the _return_json() object and so the
576
-     * $_template_args property should be used to hold the $data array.  We're expecting the following things set in
577
-     * template args.
578
-     *    1. $template_args['error'] = IF there is an error you can add the message in here.
579
-     *    2. $template_args['data']['items'] = an array of items that are setup in key index pairs of 'where_values_go'
580
-     *    => 'values_to_add'.  In other words, for the datetime metabox we'll have something like
581
-     *    $this->_template_args['data']['items'] = array(
582
-     *        'event-datetime-ids' => '1,2,3';
583
-     *    );
584
-     *    Keep in mind the following things:
585
-     *    - "where" index is for the input with the id as that string.
586
-     *    - "what" index is what will be used for the value of that input.
587
-     *
588
-     * @return void
589
-     */
590
-    public function do_extra_autosave_stuff()
591
-    {
592
-        //next let's check for the autosave nonce (we'll use _verify_nonce )
593
-        $nonce = isset($this->_req_data['autosavenonce'])
594
-                ? $this->_req_data['autosavenonce']
595
-                : null;
596
-        $this->_verify_nonce($nonce, 'autosave');
597
-        //make sure we define doing autosave (cause WP isn't triggering this we want to make sure we define it)
598
-        if ( ! defined('DOING_AUTOSAVE')) {
599
-            define('DOING_AUTOSAVE', true);
600
-        }
601
-        //if we made it here then the nonce checked out.  Let's run our methods and actions
602
-        $autosave = "_ee_autosave_{$this->_current_view}";
603
-        if (method_exists($this, $autosave)) {
604
-            $this->$autosave();
605
-        } else {
606
-            $this->_template_args['success'] = true;
607
-        }
608
-        do_action('AHEE__EE_Admin_Page_CPT__do_extra_autosave_stuff__global_after', $this);
609
-        do_action('AHEE__EE_Admin_Page_CPT__do_extra_autosave_stuff__after_' . get_class($this), $this);
610
-        //now let's return json
611
-        $this->_return_json();
612
-    }
613
-
614
-
615
-
616
-    /**
617
-     * This takes care of setting up default routes and pages that utilize the core WP admin pages.
618
-     * Child classes can override the defaults (in cases for adding metaboxes etc.)
619
-     * but take care that you include the defaults here otherwise your core WP admin pages for the cpt won't work!
620
-     *
621
-     * @access protected
622
-     * @throws EE_Error
623
-     * @return void
624
-     */
625
-    protected function _extend_page_config_for_cpt()
626
-    {
627
-        //before doing anything we need to make sure this runs ONLY when the loaded page matches the set page_slug
628
-        if (isset($this->_req_data['page']) && $this->_req_data['page'] !== $this->page_slug) {
629
-            return;
630
-        }
631
-        //set page routes and page config but ONLY if we're not viewing a custom setup cpt route as defined in _cpt_routes
632
-        if ( ! empty($this->_cpt_object)) {
633
-            $this->_page_routes = array_merge(array(
634
-                'create_new' => '_create_new_cpt_item',
635
-                'edit'       => '_edit_cpt_item',
636
-            ), $this->_page_routes);
637
-            $this->_page_config = array_merge(array(
638
-                'create_new' => array(
639
-                    'nav'           => array(
640
-                        'label' => $this->_cpt_object->labels->add_new_item,
641
-                        'order' => 5,
642
-                    ),
643
-                    'require_nonce' => false,
644
-                ),
645
-                'edit'       => array(
646
-                    'nav'           => array(
647
-                        'label'      => $this->_cpt_object->labels->edit_item,
648
-                        'order'      => 5,
649
-                        'persistent' => false,
650
-                        'url'        => '',
651
-                    ),
652
-                    'require_nonce' => false,
653
-                ),
654
-            ),
655
-                $this->_page_config
656
-            );
657
-        }
658
-        //load the next section only if this is a matching cpt route as set in the cpt routes array.
659
-        if ( ! isset($this->_cpt_routes[$this->_req_action])) {
660
-            return;
661
-        }
662
-        $this->_cpt_route = isset($this->_cpt_routes[$this->_req_action]) ? true : false;
663
-        //add_action('FHEE__EE_Admin_Page___load_page_dependencies__after_load', array( $this, 'modify_current_screen') );
664
-        if (empty($this->_cpt_object)) {
665
-            $msg = sprintf(__('This page has been set as being related to a registered custom post type, however, the custom post type object could not be retrieved. There are two possible reasons for this:  1. The "%s" does not match a registered post type. or 2. The custom post type is not registered for the "%s" action as indexed in the "$_cpt_routes" property on this class (%s).'),
666
-                $this->page_slug, $this->_req_action, get_class($this));
667
-            throw new EE_Error($msg);
668
-        }
669
-        if ($this->_cpt_route) {
670
-            $id = isset($this->_req_data['post']) ? $this->_req_data['post'] : null;
671
-            $this->_set_model_object($id);
672
-        }
673
-    }
674
-
675
-
676
-
677
-    /**
678
-     * Sets the _cpt_model_object property using what has been set for the _cpt_model_name and a given id.
679
-     *
680
-     * @access protected
681
-     * @param int  $id The id to retrieve the model object for. If empty we set a default object.
682
-     * @param bool $ignore_route_check
683
-     * @param string $req_type whether the current route is for inserting, updating, or deleting the CPT
684
-     * @throws EE_Error
685
-     */
686
-    protected function _set_model_object($id = null, $ignore_route_check = false, $req_type = '')
687
-    {
688
-        $model = null;
689
-        if (
690
-            empty($this->_cpt_model_names)
691
-            || (
692
-                ! $ignore_route_check
693
-                && ! isset($this->_cpt_routes[$this->_req_action])
694
-            ) || (
695
-                $this->_cpt_model_obj instanceof EE_CPT_Base
696
-                && $this->_cpt_model_obj->ID() === $id
697
-            )
698
-        ) {
699
-            //get out cuz we either don't have a model name OR the object has already been set and it has the same id as what has been sent.
700
-            return;
701
-        }
702
-        //if ignore_route_check is true, then get the model name via EE_Register_CPTs
703
-        if ($ignore_route_check) {
704
-            $model_names = EE_Register_CPTs::get_cpt_model_names();
705
-            $post_type   = get_post_type($id);
706
-            if (isset($model_names[$post_type])) {
707
-                $model = EE_Registry::instance()->load_model($model_names[$post_type]);
708
-            }
709
-        } else {
710
-            $model = EE_Registry::instance()->load_model($this->_cpt_model_names[$this->_req_action]);
711
-        }
712
-        if ($model instanceof EEM_Base) {
713
-            $this->_cpt_model_obj = ! empty($id) ? $model->get_one_by_ID($id) : $model->create_default_object();
714
-        }
715
-        do_action(
716
-            'AHEE__EE_Admin_Page_CPT__set_model_object__after_set_object',
717
-            $this->_cpt_model_obj,
718
-            $req_type
719
-        );
720
-    }
721
-
722
-
723
-
724
-    /**
725
-     * admin_init_global
726
-     * This runs all the code that we want executed within the WP admin_init hook.
727
-     * This method executes for ALL EE Admin pages.
728
-     *
729
-     * @access public
730
-     * @return void
731
-     */
732
-    public function admin_init_global()
733
-    {
734
-        $post = isset($this->_req_data['post']) ? get_post($this->_req_data['post']) : null;
735
-        //its possible this is a new save so let's catch that instead
736
-        $post = isset($this->_req_data['post_ID']) ? get_post($this->_req_data['post_ID']) : $post;
737
-        $post_type = $post ? $post->post_type : false;
738
-        $current_route = isset($this->_req_data['current_route'])
739
-            ? $this->_req_data['current_route']
740
-            : 'shouldneverwork';
741
-        $route_to_check = $post_type && isset($this->_cpt_routes[$current_route])
742
-            ? $this->_cpt_routes[$current_route]
743
-            : '';
744
-        add_filter('get_delete_post_link', array($this, 'modify_delete_post_link'), 10, 3);
745
-        add_filter('get_edit_post_link', array($this, 'modify_edit_post_link'), 10, 3);
746
-        if ($post_type === $route_to_check) {
747
-            add_filter('redirect_post_location', array($this, 'cpt_post_location_redirect'), 10, 2);
748
-        }
749
-        //now let's filter redirect if we're on a revision page and the revision is for an event CPT.
750
-        $revision = isset($this->_req_data['revision']) ? $this->_req_data['revision'] : null;
751
-        if ( ! empty($revision)) {
752
-            $action = isset($this->_req_data['action']) ? $this->_req_data['action'] : null;
753
-            //doing a restore?
754
-            if ( ! empty($action) && $action === 'restore') {
755
-                //get post for revision
756
-                $rev_post = get_post($revision);
757
-                $rev_parent = get_post($rev_post->post_parent);
758
-                //only do our redirect filter AND our restore revision action if the post_type for the parent is one of our cpts.
759
-                if ($rev_parent && $rev_parent->post_type === $this->page_slug) {
760
-                    add_filter('wp_redirect', array($this, 'revision_redirect'), 10, 2);
761
-                    //restores of revisions
762
-                    add_action('wp_restore_post_revision', array($this, 'restore_revision'), 10, 2);
763
-                }
764
-            }
765
-        }
766
-        //NOTE we ONLY want to run these hooks if we're on the right class for the given post type.  Otherwise we could see some really freaky things happen!
767
-        if ($post_type && $post_type === $route_to_check) {
768
-            //$post_id, $post
769
-            add_action('save_post', array($this, 'insert_update'), 10, 3);
770
-            //$post_id
771
-            add_action('trashed_post', array($this, 'before_trash_cpt_item'), 10);
772
-            add_action('trashed_post', array($this, 'dont_permanently_delete_ee_cpts'), 10);
773
-            add_action('untrashed_post', array($this, 'before_restore_cpt_item'), 10);
774
-            add_action('after_delete_post', array($this, 'before_delete_cpt_item'), 10);
775
-        }
776
-    }
777
-
778
-
779
-
780
-    /**
781
-     * Callback for the WordPress trashed_post hook.
782
-     * Execute some basic checks before calling the trash_cpt_item declared in the child class.
783
-     *
784
-     * @param int $post_id
785
-     * @throws \EE_Error
786
-     */
787
-    public function before_trash_cpt_item($post_id)
788
-    {
789
-        $this->_set_model_object($post_id, true, 'trash');
790
-        //if our cpt object isn't existent then get out immediately.
791
-        if ( ! $this->_cpt_model_obj instanceof EE_CPT_Base || $this->_cpt_model_obj->ID() !== $post_id) {
792
-            return;
793
-        }
794
-        $this->trash_cpt_item($post_id);
795
-    }
796
-
797
-
798
-
799
-    /**
800
-     * Callback for the WordPress untrashed_post hook.
801
-     * Execute some basic checks before calling the restore_cpt_method in the child class.
802
-     *
803
-     * @param $post_id
804
-     * @throws \EE_Error
805
-     */
806
-    public function before_restore_cpt_item($post_id)
807
-    {
808
-        $this->_set_model_object($post_id, true, 'restore');
809
-        //if our cpt object isn't existent then get out immediately.
810
-        if ( ! $this->_cpt_model_obj instanceof EE_CPT_Base || $this->_cpt_model_obj->ID() !== $post_id) {
811
-            return;
812
-        }
813
-        $this->restore_cpt_item($post_id);
814
-    }
815
-
816
-
817
-
818
-    /**
819
-     * Callback for the WordPress after_delete_post hook.
820
-     * Execute some basic checks before calling the delete_cpt_item method in the child class.
821
-     *
822
-     * @param $post_id
823
-     * @throws \EE_Error
824
-     */
825
-    public function before_delete_cpt_item($post_id)
826
-    {
827
-        $this->_set_model_object($post_id, true, 'delete');
828
-        //if our cpt object isn't existent then get out immediately.
829
-        if ( ! $this->_cpt_model_obj instanceof EE_CPT_Base || $this->_cpt_model_obj->ID() !== $post_id) {
830
-            return;
831
-        }
832
-        $this->delete_cpt_item($post_id);
833
-    }
834
-
835
-
836
-
837
-    /**
838
-     * This simply verifies if the cpt_model_object is instantiated for the given page and throws an error message
839
-     * accordingly.
840
-     *
841
-     * @access public
842
-     * @throws EE_Error
843
-     * @return void
844
-     */
845
-    public function verify_cpt_object()
846
-    {
847
-        $label = ! empty($this->_cpt_object) ? $this->_cpt_object->labels->singular_name : $this->page_label;
848
-        // verify event object
849
-        if ( ! $this->_cpt_model_obj instanceof EE_CPT_Base) {
850
-            throw new EE_Error(sprintf(__('Something has gone wrong with the page load because we are unable to set up the object for the %1$s.  This usually happens when the given id for the page route is NOT for the correct custom post type for this page',
851
-                    'event_espresso'), $label));
852
-        }
853
-        //if auto-draft then throw an error
854
-        if ($this->_cpt_model_obj->get('status') === 'auto-draft') {
855
-            EE_Error::overwrite_errors();
856
-            EE_Error::add_error(sprintf(__('This %1$s was saved without a title, description, or excerpt which means that none of the extra details you added were saved properly.  All autodrafts will show up in the "draft" view of your event list table.  You can delete them from there. Please click the "Add %1$s" button to refresh and restart.'),
857
-                    $label), __FILE__, __FUNCTION__, __LINE__);
858
-        }
859
-    }
860
-
861
-
862
-
863
-    /**
864
-     * admin_footer_scripts_global
865
-     * Anything triggered by the 'admin_print_footer_scripts' WP hook should be put in here. This particular method
866
-     * will apply on ALL EE_Admin pages.
867
-     *
868
-     * @access public
869
-     * @return void
870
-     */
871
-    public function admin_footer_scripts_global()
872
-    {
873
-        $this->_add_admin_page_ajax_loading_img();
874
-        $this->_add_admin_page_overlay();
875
-    }
876
-
877
-
878
-
879
-    /**
880
-     * add in any global scripts for cpt routes
881
-     *
882
-     * @return void
883
-     */
884
-    public function load_global_scripts_styles()
885
-    {
886
-        parent::load_global_scripts_styles();
887
-        if ($this->_cpt_model_obj instanceof EE_CPT_Base) {
888
-            //setup custom post status object for localize script but only if we've got a cpt object
889
-            $statuses = $this->_cpt_model_obj->get_custom_post_statuses();
890
-            if ( ! empty($statuses)) {
891
-                //get ALL statuses!
892
-                $statuses = $this->_cpt_model_obj->get_all_post_statuses();
893
-                //setup object
894
-                $ee_cpt_statuses = array();
895
-                foreach ($statuses as $status => $label) {
896
-                    $ee_cpt_statuses[$status] = array(
897
-                        'label'      => $label,
898
-                        'save_label' => sprintf(__('Save as %s', 'event_espresso'), $label),
899
-                    );
900
-                }
901
-                wp_localize_script('ee_admin_js', 'eeCPTstatuses', $ee_cpt_statuses);
902
-            }
903
-        }
904
-    }
905
-
906
-
907
-
908
-    /**
909
-     * This is a wrapper for the insert/update routes for cpt items so we can add things that are common to ALL
910
-     * insert/updates
911
-     *
912
-     * @param  int     $post_id ID of post being updated
913
-     * @param  WP_Post $post    Post object from WP
914
-     * @param  bool    $update  Whether this is an update or a new save.
915
-     * @return void
916
-     * @throws \EE_Error
917
-     */
918
-    public function insert_update($post_id, $post, $update)
919
-    {
920
-        //make sure that if this is a revision OR trash action that we don't do any updates!
921
-        if (
922
-            isset($this->_req_data['action'])
923
-            && (
924
-                $this->_req_data['action'] === 'restore'
925
-                || $this->_req_data['action'] === 'trash'
926
-            )
927
-        ) {
928
-            return;
929
-        }
930
-        $this->_set_model_object($post_id, true, 'insert_update');
931
-        //if our cpt object is not instantiated and its NOT the same post_id as what is triggering this callback, then exit.
932
-        if ($update
933
-            && (
934
-                ! $this->_cpt_model_obj instanceof EE_CPT_Base
935
-                || $this->_cpt_model_obj->ID() !== $post_id
936
-            )
937
-        ) {
938
-            return;
939
-        }
940
-        //check for autosave and update our req_data property accordingly.
941
-        /*if ( defined('DOING_AUTOSAVE') && DOING_AUTOSAVE && isset( $this->_req_data['ee_autosave_data'] ) ) {
498
+	}
499
+
500
+
501
+
502
+	/**
503
+	 * if this post is a draft or scheduled post then we provide a preview button for user to click
504
+	 * Method is called from parent and is hooked into the wp 'get_sample_permalink_html' filter.
505
+	 *
506
+	 * @param  string $return    the current html
507
+	 * @param  int    $id        the post id for the page
508
+	 * @param  string $new_title What the title is
509
+	 * @param  string $new_slug  what the slug is
510
+	 * @return string            The new html string for the permalink area
511
+	 */
512
+	public function preview_button_html($return, $id, $new_title, $new_slug)
513
+	{
514
+		$post = get_post($id);
515
+		if ('publish' !== get_post_status($post)) {
516
+			//include shims for the `get_preview_post_link` function
517
+			require_once( EE_CORE . 'wordpress-shims.php' );
518
+			$return .= '<span_id="view-post-btn"><a target="_blank" href="'
519
+					   . get_preview_post_link($id)
520
+					   . '" class="button button-small">'
521
+					   . __('Preview', 'event_espresso')
522
+					   . '</a></span>'
523
+					   . "\n";
524
+		}
525
+		return $return;
526
+	}
527
+
528
+
529
+
530
+	/**
531
+	 * add our custom post stati dropdown on the wp post page for this cpt
532
+	 *
533
+	 * @return void
534
+	 */
535
+	public function custom_post_stati_dropdown()
536
+	{
537
+
538
+		$statuses         = $this->_cpt_model_obj->get_custom_post_statuses();
539
+		$cur_status_label = array_key_exists($this->_cpt_model_obj->status(), $statuses)
540
+			? $statuses[$this->_cpt_model_obj->status()]
541
+			: '';
542
+		$template_args    = array(
543
+			'cur_status'            => $this->_cpt_model_obj->status(),
544
+			'statuses'              => $statuses,
545
+			'cur_status_label'      => $cur_status_label,
546
+			'localized_status_save' => sprintf(__('Save %s', 'event_espresso'), $cur_status_label),
547
+		);
548
+		//we'll add a trash post status (WP doesn't add one for some reason)
549
+		if ($this->_cpt_model_obj->status() === 'trash') {
550
+			$template_args['cur_status_label'] = __('Trashed', 'event_espresso');
551
+			$statuses['trash']                 = __('Trashed', 'event_espresso');
552
+			$template_args['statuses']         = $statuses;
553
+		}
554
+
555
+		$template = EE_ADMIN_TEMPLATE . 'status_dropdown.template.php';
556
+		EEH_Template::display_template($template, $template_args);
557
+	}
558
+
559
+
560
+
561
+	public function setup_autosave_hooks()
562
+	{
563
+		$this->_set_autosave_containers();
564
+		$this->_load_autosave_scripts_styles();
565
+	}
566
+
567
+
568
+
569
+	/**
570
+	 * This is run on all WordPress autosaves AFTER the autosave is complete and sends along a $_POST object (available
571
+	 * in $this->_req_data) containing: post_ID of the saved post autosavenonce for the saved post We'll do the check
572
+	 * for the nonce in here, but then this method looks for two things:
573
+	 * 1. Execute a method (if exists) matching 'ee_autosave_' and appended with the given route. OR
574
+	 * 2. do_actions() for global or class specific actions that have been registered (for plugins/addons not in an
575
+	 * EE_Admin_Page class. PLEASE NOTE: Data will be returned using the _return_json() object and so the
576
+	 * $_template_args property should be used to hold the $data array.  We're expecting the following things set in
577
+	 * template args.
578
+	 *    1. $template_args['error'] = IF there is an error you can add the message in here.
579
+	 *    2. $template_args['data']['items'] = an array of items that are setup in key index pairs of 'where_values_go'
580
+	 *    => 'values_to_add'.  In other words, for the datetime metabox we'll have something like
581
+	 *    $this->_template_args['data']['items'] = array(
582
+	 *        'event-datetime-ids' => '1,2,3';
583
+	 *    );
584
+	 *    Keep in mind the following things:
585
+	 *    - "where" index is for the input with the id as that string.
586
+	 *    - "what" index is what will be used for the value of that input.
587
+	 *
588
+	 * @return void
589
+	 */
590
+	public function do_extra_autosave_stuff()
591
+	{
592
+		//next let's check for the autosave nonce (we'll use _verify_nonce )
593
+		$nonce = isset($this->_req_data['autosavenonce'])
594
+				? $this->_req_data['autosavenonce']
595
+				: null;
596
+		$this->_verify_nonce($nonce, 'autosave');
597
+		//make sure we define doing autosave (cause WP isn't triggering this we want to make sure we define it)
598
+		if ( ! defined('DOING_AUTOSAVE')) {
599
+			define('DOING_AUTOSAVE', true);
600
+		}
601
+		//if we made it here then the nonce checked out.  Let's run our methods and actions
602
+		$autosave = "_ee_autosave_{$this->_current_view}";
603
+		if (method_exists($this, $autosave)) {
604
+			$this->$autosave();
605
+		} else {
606
+			$this->_template_args['success'] = true;
607
+		}
608
+		do_action('AHEE__EE_Admin_Page_CPT__do_extra_autosave_stuff__global_after', $this);
609
+		do_action('AHEE__EE_Admin_Page_CPT__do_extra_autosave_stuff__after_' . get_class($this), $this);
610
+		//now let's return json
611
+		$this->_return_json();
612
+	}
613
+
614
+
615
+
616
+	/**
617
+	 * This takes care of setting up default routes and pages that utilize the core WP admin pages.
618
+	 * Child classes can override the defaults (in cases for adding metaboxes etc.)
619
+	 * but take care that you include the defaults here otherwise your core WP admin pages for the cpt won't work!
620
+	 *
621
+	 * @access protected
622
+	 * @throws EE_Error
623
+	 * @return void
624
+	 */
625
+	protected function _extend_page_config_for_cpt()
626
+	{
627
+		//before doing anything we need to make sure this runs ONLY when the loaded page matches the set page_slug
628
+		if (isset($this->_req_data['page']) && $this->_req_data['page'] !== $this->page_slug) {
629
+			return;
630
+		}
631
+		//set page routes and page config but ONLY if we're not viewing a custom setup cpt route as defined in _cpt_routes
632
+		if ( ! empty($this->_cpt_object)) {
633
+			$this->_page_routes = array_merge(array(
634
+				'create_new' => '_create_new_cpt_item',
635
+				'edit'       => '_edit_cpt_item',
636
+			), $this->_page_routes);
637
+			$this->_page_config = array_merge(array(
638
+				'create_new' => array(
639
+					'nav'           => array(
640
+						'label' => $this->_cpt_object->labels->add_new_item,
641
+						'order' => 5,
642
+					),
643
+					'require_nonce' => false,
644
+				),
645
+				'edit'       => array(
646
+					'nav'           => array(
647
+						'label'      => $this->_cpt_object->labels->edit_item,
648
+						'order'      => 5,
649
+						'persistent' => false,
650
+						'url'        => '',
651
+					),
652
+					'require_nonce' => false,
653
+				),
654
+			),
655
+				$this->_page_config
656
+			);
657
+		}
658
+		//load the next section only if this is a matching cpt route as set in the cpt routes array.
659
+		if ( ! isset($this->_cpt_routes[$this->_req_action])) {
660
+			return;
661
+		}
662
+		$this->_cpt_route = isset($this->_cpt_routes[$this->_req_action]) ? true : false;
663
+		//add_action('FHEE__EE_Admin_Page___load_page_dependencies__after_load', array( $this, 'modify_current_screen') );
664
+		if (empty($this->_cpt_object)) {
665
+			$msg = sprintf(__('This page has been set as being related to a registered custom post type, however, the custom post type object could not be retrieved. There are two possible reasons for this:  1. The "%s" does not match a registered post type. or 2. The custom post type is not registered for the "%s" action as indexed in the "$_cpt_routes" property on this class (%s).'),
666
+				$this->page_slug, $this->_req_action, get_class($this));
667
+			throw new EE_Error($msg);
668
+		}
669
+		if ($this->_cpt_route) {
670
+			$id = isset($this->_req_data['post']) ? $this->_req_data['post'] : null;
671
+			$this->_set_model_object($id);
672
+		}
673
+	}
674
+
675
+
676
+
677
+	/**
678
+	 * Sets the _cpt_model_object property using what has been set for the _cpt_model_name and a given id.
679
+	 *
680
+	 * @access protected
681
+	 * @param int  $id The id to retrieve the model object for. If empty we set a default object.
682
+	 * @param bool $ignore_route_check
683
+	 * @param string $req_type whether the current route is for inserting, updating, or deleting the CPT
684
+	 * @throws EE_Error
685
+	 */
686
+	protected function _set_model_object($id = null, $ignore_route_check = false, $req_type = '')
687
+	{
688
+		$model = null;
689
+		if (
690
+			empty($this->_cpt_model_names)
691
+			|| (
692
+				! $ignore_route_check
693
+				&& ! isset($this->_cpt_routes[$this->_req_action])
694
+			) || (
695
+				$this->_cpt_model_obj instanceof EE_CPT_Base
696
+				&& $this->_cpt_model_obj->ID() === $id
697
+			)
698
+		) {
699
+			//get out cuz we either don't have a model name OR the object has already been set and it has the same id as what has been sent.
700
+			return;
701
+		}
702
+		//if ignore_route_check is true, then get the model name via EE_Register_CPTs
703
+		if ($ignore_route_check) {
704
+			$model_names = EE_Register_CPTs::get_cpt_model_names();
705
+			$post_type   = get_post_type($id);
706
+			if (isset($model_names[$post_type])) {
707
+				$model = EE_Registry::instance()->load_model($model_names[$post_type]);
708
+			}
709
+		} else {
710
+			$model = EE_Registry::instance()->load_model($this->_cpt_model_names[$this->_req_action]);
711
+		}
712
+		if ($model instanceof EEM_Base) {
713
+			$this->_cpt_model_obj = ! empty($id) ? $model->get_one_by_ID($id) : $model->create_default_object();
714
+		}
715
+		do_action(
716
+			'AHEE__EE_Admin_Page_CPT__set_model_object__after_set_object',
717
+			$this->_cpt_model_obj,
718
+			$req_type
719
+		);
720
+	}
721
+
722
+
723
+
724
+	/**
725
+	 * admin_init_global
726
+	 * This runs all the code that we want executed within the WP admin_init hook.
727
+	 * This method executes for ALL EE Admin pages.
728
+	 *
729
+	 * @access public
730
+	 * @return void
731
+	 */
732
+	public function admin_init_global()
733
+	{
734
+		$post = isset($this->_req_data['post']) ? get_post($this->_req_data['post']) : null;
735
+		//its possible this is a new save so let's catch that instead
736
+		$post = isset($this->_req_data['post_ID']) ? get_post($this->_req_data['post_ID']) : $post;
737
+		$post_type = $post ? $post->post_type : false;
738
+		$current_route = isset($this->_req_data['current_route'])
739
+			? $this->_req_data['current_route']
740
+			: 'shouldneverwork';
741
+		$route_to_check = $post_type && isset($this->_cpt_routes[$current_route])
742
+			? $this->_cpt_routes[$current_route]
743
+			: '';
744
+		add_filter('get_delete_post_link', array($this, 'modify_delete_post_link'), 10, 3);
745
+		add_filter('get_edit_post_link', array($this, 'modify_edit_post_link'), 10, 3);
746
+		if ($post_type === $route_to_check) {
747
+			add_filter('redirect_post_location', array($this, 'cpt_post_location_redirect'), 10, 2);
748
+		}
749
+		//now let's filter redirect if we're on a revision page and the revision is for an event CPT.
750
+		$revision = isset($this->_req_data['revision']) ? $this->_req_data['revision'] : null;
751
+		if ( ! empty($revision)) {
752
+			$action = isset($this->_req_data['action']) ? $this->_req_data['action'] : null;
753
+			//doing a restore?
754
+			if ( ! empty($action) && $action === 'restore') {
755
+				//get post for revision
756
+				$rev_post = get_post($revision);
757
+				$rev_parent = get_post($rev_post->post_parent);
758
+				//only do our redirect filter AND our restore revision action if the post_type for the parent is one of our cpts.
759
+				if ($rev_parent && $rev_parent->post_type === $this->page_slug) {
760
+					add_filter('wp_redirect', array($this, 'revision_redirect'), 10, 2);
761
+					//restores of revisions
762
+					add_action('wp_restore_post_revision', array($this, 'restore_revision'), 10, 2);
763
+				}
764
+			}
765
+		}
766
+		//NOTE we ONLY want to run these hooks if we're on the right class for the given post type.  Otherwise we could see some really freaky things happen!
767
+		if ($post_type && $post_type === $route_to_check) {
768
+			//$post_id, $post
769
+			add_action('save_post', array($this, 'insert_update'), 10, 3);
770
+			//$post_id
771
+			add_action('trashed_post', array($this, 'before_trash_cpt_item'), 10);
772
+			add_action('trashed_post', array($this, 'dont_permanently_delete_ee_cpts'), 10);
773
+			add_action('untrashed_post', array($this, 'before_restore_cpt_item'), 10);
774
+			add_action('after_delete_post', array($this, 'before_delete_cpt_item'), 10);
775
+		}
776
+	}
777
+
778
+
779
+
780
+	/**
781
+	 * Callback for the WordPress trashed_post hook.
782
+	 * Execute some basic checks before calling the trash_cpt_item declared in the child class.
783
+	 *
784
+	 * @param int $post_id
785
+	 * @throws \EE_Error
786
+	 */
787
+	public function before_trash_cpt_item($post_id)
788
+	{
789
+		$this->_set_model_object($post_id, true, 'trash');
790
+		//if our cpt object isn't existent then get out immediately.
791
+		if ( ! $this->_cpt_model_obj instanceof EE_CPT_Base || $this->_cpt_model_obj->ID() !== $post_id) {
792
+			return;
793
+		}
794
+		$this->trash_cpt_item($post_id);
795
+	}
796
+
797
+
798
+
799
+	/**
800
+	 * Callback for the WordPress untrashed_post hook.
801
+	 * Execute some basic checks before calling the restore_cpt_method in the child class.
802
+	 *
803
+	 * @param $post_id
804
+	 * @throws \EE_Error
805
+	 */
806
+	public function before_restore_cpt_item($post_id)
807
+	{
808
+		$this->_set_model_object($post_id, true, 'restore');
809
+		//if our cpt object isn't existent then get out immediately.
810
+		if ( ! $this->_cpt_model_obj instanceof EE_CPT_Base || $this->_cpt_model_obj->ID() !== $post_id) {
811
+			return;
812
+		}
813
+		$this->restore_cpt_item($post_id);
814
+	}
815
+
816
+
817
+
818
+	/**
819
+	 * Callback for the WordPress after_delete_post hook.
820
+	 * Execute some basic checks before calling the delete_cpt_item method in the child class.
821
+	 *
822
+	 * @param $post_id
823
+	 * @throws \EE_Error
824
+	 */
825
+	public function before_delete_cpt_item($post_id)
826
+	{
827
+		$this->_set_model_object($post_id, true, 'delete');
828
+		//if our cpt object isn't existent then get out immediately.
829
+		if ( ! $this->_cpt_model_obj instanceof EE_CPT_Base || $this->_cpt_model_obj->ID() !== $post_id) {
830
+			return;
831
+		}
832
+		$this->delete_cpt_item($post_id);
833
+	}
834
+
835
+
836
+
837
+	/**
838
+	 * This simply verifies if the cpt_model_object is instantiated for the given page and throws an error message
839
+	 * accordingly.
840
+	 *
841
+	 * @access public
842
+	 * @throws EE_Error
843
+	 * @return void
844
+	 */
845
+	public function verify_cpt_object()
846
+	{
847
+		$label = ! empty($this->_cpt_object) ? $this->_cpt_object->labels->singular_name : $this->page_label;
848
+		// verify event object
849
+		if ( ! $this->_cpt_model_obj instanceof EE_CPT_Base) {
850
+			throw new EE_Error(sprintf(__('Something has gone wrong with the page load because we are unable to set up the object for the %1$s.  This usually happens when the given id for the page route is NOT for the correct custom post type for this page',
851
+					'event_espresso'), $label));
852
+		}
853
+		//if auto-draft then throw an error
854
+		if ($this->_cpt_model_obj->get('status') === 'auto-draft') {
855
+			EE_Error::overwrite_errors();
856
+			EE_Error::add_error(sprintf(__('This %1$s was saved without a title, description, or excerpt which means that none of the extra details you added were saved properly.  All autodrafts will show up in the "draft" view of your event list table.  You can delete them from there. Please click the "Add %1$s" button to refresh and restart.'),
857
+					$label), __FILE__, __FUNCTION__, __LINE__);
858
+		}
859
+	}
860
+
861
+
862
+
863
+	/**
864
+	 * admin_footer_scripts_global
865
+	 * Anything triggered by the 'admin_print_footer_scripts' WP hook should be put in here. This particular method
866
+	 * will apply on ALL EE_Admin pages.
867
+	 *
868
+	 * @access public
869
+	 * @return void
870
+	 */
871
+	public function admin_footer_scripts_global()
872
+	{
873
+		$this->_add_admin_page_ajax_loading_img();
874
+		$this->_add_admin_page_overlay();
875
+	}
876
+
877
+
878
+
879
+	/**
880
+	 * add in any global scripts for cpt routes
881
+	 *
882
+	 * @return void
883
+	 */
884
+	public function load_global_scripts_styles()
885
+	{
886
+		parent::load_global_scripts_styles();
887
+		if ($this->_cpt_model_obj instanceof EE_CPT_Base) {
888
+			//setup custom post status object for localize script but only if we've got a cpt object
889
+			$statuses = $this->_cpt_model_obj->get_custom_post_statuses();
890
+			if ( ! empty($statuses)) {
891
+				//get ALL statuses!
892
+				$statuses = $this->_cpt_model_obj->get_all_post_statuses();
893
+				//setup object
894
+				$ee_cpt_statuses = array();
895
+				foreach ($statuses as $status => $label) {
896
+					$ee_cpt_statuses[$status] = array(
897
+						'label'      => $label,
898
+						'save_label' => sprintf(__('Save as %s', 'event_espresso'), $label),
899
+					);
900
+				}
901
+				wp_localize_script('ee_admin_js', 'eeCPTstatuses', $ee_cpt_statuses);
902
+			}
903
+		}
904
+	}
905
+
906
+
907
+
908
+	/**
909
+	 * This is a wrapper for the insert/update routes for cpt items so we can add things that are common to ALL
910
+	 * insert/updates
911
+	 *
912
+	 * @param  int     $post_id ID of post being updated
913
+	 * @param  WP_Post $post    Post object from WP
914
+	 * @param  bool    $update  Whether this is an update or a new save.
915
+	 * @return void
916
+	 * @throws \EE_Error
917
+	 */
918
+	public function insert_update($post_id, $post, $update)
919
+	{
920
+		//make sure that if this is a revision OR trash action that we don't do any updates!
921
+		if (
922
+			isset($this->_req_data['action'])
923
+			&& (
924
+				$this->_req_data['action'] === 'restore'
925
+				|| $this->_req_data['action'] === 'trash'
926
+			)
927
+		) {
928
+			return;
929
+		}
930
+		$this->_set_model_object($post_id, true, 'insert_update');
931
+		//if our cpt object is not instantiated and its NOT the same post_id as what is triggering this callback, then exit.
932
+		if ($update
933
+			&& (
934
+				! $this->_cpt_model_obj instanceof EE_CPT_Base
935
+				|| $this->_cpt_model_obj->ID() !== $post_id
936
+			)
937
+		) {
938
+			return;
939
+		}
940
+		//check for autosave and update our req_data property accordingly.
941
+		/*if ( defined('DOING_AUTOSAVE') && DOING_AUTOSAVE && isset( $this->_req_data['ee_autosave_data'] ) ) {
942 942
             foreach( (array) $this->_req_data['ee_autosave_data'] as $id => $values ) {
943 943
 
944 944
                 foreach ( (array) $values as $key => $value ) {
@@ -948,527 +948,527 @@  discard block
 block discarded – undo
948 948
 
949 949
         }/**/ //TODO reactivate after autosave is implemented in 4.2
950 950
 
951
-        //take care of updating any selected page_template IF this cpt supports it.
952
-        if ($this->_supports_page_templates($post->post_type) && ! empty($this->_req_data['page_template'])) {
953
-            //wp version aware.
954
-            if (EE_Recommended_Versions::check_wp_version('4.7', '>=')) {
955
-                $page_templates = wp_get_theme()->get_page_templates();
956
-            } else {
957
-                $post->page_template = $this->_req_data['page_template'];
958
-                $page_templates      = wp_get_theme()->get_page_templates($post);
959
-            }
960
-            if ('default' != $this->_req_data['page_template'] && ! isset($page_templates[$this->_req_data['page_template']])) {
961
-                EE_Error::add_error(__('Invalid Page Template.', 'event_espresso'), __FILE__, __FUNCTION__, __LINE__);
962
-            } else {
963
-                update_post_meta($post_id, '_wp_page_template', $this->_req_data['page_template']);
964
-            }
965
-        }
966
-        if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
967
-            return;
968
-        } //TODO we'll remove this after reimplementing autosave in 4.2
969
-        $this->_insert_update_cpt_item($post_id, $post);
970
-    }
971
-
972
-
973
-
974
-    /**
975
-     * This hooks into the wp_trash_post() function and removes the `_wp_trash_meta_status` and `_wp_trash_meta_time`
976
-     * post meta IF the trashed post is one of our CPT's - note this method should only be called with our cpt routes
977
-     * so we don't have to check for our CPT.
978
-     *
979
-     * @param  int $post_id ID of the post
980
-     * @return void
981
-     */
982
-    public function dont_permanently_delete_ee_cpts($post_id)
983
-    {
984
-        //only do this if we're actually processing one of our CPTs
985
-        //if our cpt object isn't existent then get out immediately.
986
-        if ( ! $this->_cpt_model_obj instanceof EE_CPT_Base) {
987
-            return;
988
-        }
989
-        delete_post_meta($post_id, '_wp_trash_meta_status');
990
-        delete_post_meta($post_id, '_wp_trash_meta_time');
991
-        //our cpts may have comments so let's take care of that too
992
-        delete_post_meta($post_id, '_wp_trash_meta_comments_status');
993
-    }
994
-
995
-
996
-
997
-    /**
998
-     * This is a wrapper for the restore_cpt_revision route for cpt items so we can make sure that when a revision is
999
-     * triggered that we restore related items.  In order to work cpt classes MUST have a restore_cpt_revision method
1000
-     * in them. We also have our OWN action in here so addons can hook into the restore process easily.
1001
-     *
1002
-     * @param  int $post_id     ID of cpt item
1003
-     * @param  int $revision_id ID of revision being restored
1004
-     * @return void
1005
-     */
1006
-    public function restore_revision($post_id, $revision_id)
1007
-    {
1008
-        $this->_restore_cpt_item($post_id, $revision_id);
1009
-        //global action
1010
-        do_action('AHEE_EE_Admin_Page_CPT__restore_revision', $post_id, $revision_id);
1011
-        //class specific action so you can limit hooking into a specific page.
1012
-        do_action('AHEE_EE_Admin_Page_CPT_' . get_class($this) . '__restore_revision', $post_id, $revision_id);
1013
-    }
1014
-
1015
-
1016
-
1017
-    /**
1018
-     * @see restore_revision() for details
1019
-     * @param  int $post_id     ID of cpt item
1020
-     * @param  int $revision_id ID of revision for item
1021
-     * @return void
1022
-     */
1023
-    abstract protected function _restore_cpt_item($post_id, $revision_id);
1024
-
1025
-
1026
-
1027
-    /**
1028
-     * Execution of this method is added to the end of the load_page_dependencies method in the parent
1029
-     * so that we can fix a bug where default core metaboxes were not being called in the sidebar.
1030
-     * To fix we have to reset the current_screen using the page_slug
1031
-     * (which is identical - or should be - to our registered_post_type id.)
1032
-     * Also, since the core WP file loads the admin_header.php for WP
1033
-     * (and there are a bunch of other things edit-form-advanced.php loads that need to happen really early)
1034
-     * we need to load it NOW, hence our _route_admin_request in here. (Otherwise screen options won't be set).
1035
-     *
1036
-     * @return void
1037
-     */
1038
-    public function modify_current_screen()
1039
-    {
1040
-        //ONLY do this if the current page_route IS a cpt route
1041
-        if ( ! $this->_cpt_route) {
1042
-            return;
1043
-        }
1044
-        //routing things REALLY early b/c this is a cpt admin page
1045
-        set_current_screen($this->_cpt_routes[$this->_req_action]);
1046
-        $this->_current_screen       = get_current_screen();
1047
-        $this->_current_screen->base = 'event-espresso';
1048
-        $this->_add_help_tabs(); //we make sure we add any help tabs back in!
1049
-        /*try {
951
+		//take care of updating any selected page_template IF this cpt supports it.
952
+		if ($this->_supports_page_templates($post->post_type) && ! empty($this->_req_data['page_template'])) {
953
+			//wp version aware.
954
+			if (EE_Recommended_Versions::check_wp_version('4.7', '>=')) {
955
+				$page_templates = wp_get_theme()->get_page_templates();
956
+			} else {
957
+				$post->page_template = $this->_req_data['page_template'];
958
+				$page_templates      = wp_get_theme()->get_page_templates($post);
959
+			}
960
+			if ('default' != $this->_req_data['page_template'] && ! isset($page_templates[$this->_req_data['page_template']])) {
961
+				EE_Error::add_error(__('Invalid Page Template.', 'event_espresso'), __FILE__, __FUNCTION__, __LINE__);
962
+			} else {
963
+				update_post_meta($post_id, '_wp_page_template', $this->_req_data['page_template']);
964
+			}
965
+		}
966
+		if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
967
+			return;
968
+		} //TODO we'll remove this after reimplementing autosave in 4.2
969
+		$this->_insert_update_cpt_item($post_id, $post);
970
+	}
971
+
972
+
973
+
974
+	/**
975
+	 * This hooks into the wp_trash_post() function and removes the `_wp_trash_meta_status` and `_wp_trash_meta_time`
976
+	 * post meta IF the trashed post is one of our CPT's - note this method should only be called with our cpt routes
977
+	 * so we don't have to check for our CPT.
978
+	 *
979
+	 * @param  int $post_id ID of the post
980
+	 * @return void
981
+	 */
982
+	public function dont_permanently_delete_ee_cpts($post_id)
983
+	{
984
+		//only do this if we're actually processing one of our CPTs
985
+		//if our cpt object isn't existent then get out immediately.
986
+		if ( ! $this->_cpt_model_obj instanceof EE_CPT_Base) {
987
+			return;
988
+		}
989
+		delete_post_meta($post_id, '_wp_trash_meta_status');
990
+		delete_post_meta($post_id, '_wp_trash_meta_time');
991
+		//our cpts may have comments so let's take care of that too
992
+		delete_post_meta($post_id, '_wp_trash_meta_comments_status');
993
+	}
994
+
995
+
996
+
997
+	/**
998
+	 * This is a wrapper for the restore_cpt_revision route for cpt items so we can make sure that when a revision is
999
+	 * triggered that we restore related items.  In order to work cpt classes MUST have a restore_cpt_revision method
1000
+	 * in them. We also have our OWN action in here so addons can hook into the restore process easily.
1001
+	 *
1002
+	 * @param  int $post_id     ID of cpt item
1003
+	 * @param  int $revision_id ID of revision being restored
1004
+	 * @return void
1005
+	 */
1006
+	public function restore_revision($post_id, $revision_id)
1007
+	{
1008
+		$this->_restore_cpt_item($post_id, $revision_id);
1009
+		//global action
1010
+		do_action('AHEE_EE_Admin_Page_CPT__restore_revision', $post_id, $revision_id);
1011
+		//class specific action so you can limit hooking into a specific page.
1012
+		do_action('AHEE_EE_Admin_Page_CPT_' . get_class($this) . '__restore_revision', $post_id, $revision_id);
1013
+	}
1014
+
1015
+
1016
+
1017
+	/**
1018
+	 * @see restore_revision() for details
1019
+	 * @param  int $post_id     ID of cpt item
1020
+	 * @param  int $revision_id ID of revision for item
1021
+	 * @return void
1022
+	 */
1023
+	abstract protected function _restore_cpt_item($post_id, $revision_id);
1024
+
1025
+
1026
+
1027
+	/**
1028
+	 * Execution of this method is added to the end of the load_page_dependencies method in the parent
1029
+	 * so that we can fix a bug where default core metaboxes were not being called in the sidebar.
1030
+	 * To fix we have to reset the current_screen using the page_slug
1031
+	 * (which is identical - or should be - to our registered_post_type id.)
1032
+	 * Also, since the core WP file loads the admin_header.php for WP
1033
+	 * (and there are a bunch of other things edit-form-advanced.php loads that need to happen really early)
1034
+	 * we need to load it NOW, hence our _route_admin_request in here. (Otherwise screen options won't be set).
1035
+	 *
1036
+	 * @return void
1037
+	 */
1038
+	public function modify_current_screen()
1039
+	{
1040
+		//ONLY do this if the current page_route IS a cpt route
1041
+		if ( ! $this->_cpt_route) {
1042
+			return;
1043
+		}
1044
+		//routing things REALLY early b/c this is a cpt admin page
1045
+		set_current_screen($this->_cpt_routes[$this->_req_action]);
1046
+		$this->_current_screen       = get_current_screen();
1047
+		$this->_current_screen->base = 'event-espresso';
1048
+		$this->_add_help_tabs(); //we make sure we add any help tabs back in!
1049
+		/*try {
1050 1050
             $this->_route_admin_request();
1051 1051
         } catch ( EE_Error $e ) {
1052 1052
             $e->get_error();
1053 1053
         }/**/
1054
-    }
1055
-
1056
-
1057
-
1058
-    /**
1059
-     * This allows child classes to modify the default editor title that appears when people add a new or edit an
1060
-     * existing CPT item.     * This uses the _labels property set by the child class via _define_page_props. Just make
1061
-     * sure you have a key in _labels property that equals 'editor_title' and the value can be whatever you want the
1062
-     * default to be.
1063
-     *
1064
-     * @param string $title The new title (or existing if there is no editor_title defined)
1065
-     * @return string
1066
-     */
1067
-    public function add_custom_editor_default_title($title)
1068
-    {
1069
-        return isset($this->_labels['editor_title'][$this->_cpt_routes[$this->_req_action]])
1070
-            ? $this->_labels['editor_title'][$this->_cpt_routes[$this->_req_action]]
1071
-            : $title;
1072
-    }
1073
-
1074
-
1075
-
1076
-    /**
1077
-     * hooks into the wp_get_shortlink button and makes sure that the shortlink gets generated
1078
-     *
1079
-     * @param string $shortlink   The already generated shortlink
1080
-     * @param int    $id          Post ID for this item
1081
-     * @param string $context     The context for the link
1082
-     * @param bool   $allow_slugs Whether to allow post slugs in the shortlink.
1083
-     * @return string
1084
-     */
1085
-    public function add_shortlink_button_to_editor($shortlink, $id, $context, $allow_slugs)
1086
-    {
1087
-        if ( ! empty($id) && get_option('permalink_structure') !== '') {
1088
-            $post = get_post($id);
1089
-            if (isset($post->post_type) && $this->page_slug === $post->post_type) {
1090
-                $shortlink = home_url('?p=' . $post->ID);
1091
-            }
1092
-        }
1093
-        return $shortlink;
1094
-    }
1095
-
1096
-
1097
-
1098
-    /**
1099
-     * overriding the parent route_admin_request method so we DON'T run the route twice on cpt core page loads (it's
1100
-     * already run in modify_current_screen())
1101
-     *
1102
-     * @return void
1103
-     */
1104
-    public function route_admin_request()
1105
-    {
1106
-        if ($this->_cpt_route) {
1107
-            return;
1108
-        }
1109
-        try {
1110
-            $this->_route_admin_request();
1111
-        } catch (EE_Error $e) {
1112
-            $e->get_error();
1113
-        }
1114
-    }
1115
-
1116
-
1117
-
1118
-    /**
1119
-     * Add a hidden form input to cpt core pages so that we know to do redirects to our routes on saves
1120
-     *
1121
-     * @return void
1122
-     */
1123
-    public function cpt_post_form_hidden_input()
1124
-    {
1125
-        echo '<input type="hidden" name="ee_cpt_item_redirect_url" value="' . $this->_admin_base_url . '" />';
1126
-        //we're also going to add the route value and the current page so we can direct autosave parsing correctly
1127
-        echo '<div id="ee-cpt-hidden-inputs">';
1128
-        echo '<input type="hidden" id="current_route" name="current_route" value="' . $this->_current_view . '" />';
1129
-        echo '<input type="hidden" id="current_page" name="current_page" value="' . $this->page_slug . '" />';
1130
-        echo '</div>';
1131
-    }
1132
-
1133
-
1134
-
1135
-    /**
1136
-     * This allows us to redirect the location of revision restores when they happen so it goes to our CPT routes.
1137
-     *
1138
-     * @param  string $location Original location url
1139
-     * @param  int    $status   Status for http header
1140
-     * @return string           new (or original) url to redirect to.
1141
-     */
1142
-    public function revision_redirect($location, $status)
1143
-    {
1144
-        //get revision
1145
-        $rev_id = isset($this->_req_data['revision']) ? $this->_req_data['revision'] : null;
1146
-        //can't do anything without revision so let's get out if not present
1147
-        if (empty($rev_id)) {
1148
-            return $location;
1149
-        }
1150
-        //get rev_post_data
1151
-        $rev = get_post($rev_id);
1152
-        $admin_url = $this->_admin_base_url;
1153
-        $query_args = array(
1154
-            'action'   => 'edit',
1155
-            'post'     => $rev->post_parent,
1156
-            'revision' => $rev_id,
1157
-            'message'  => 5,
1158
-        );
1159
-        $this->_process_notices($query_args, true);
1160
-        return self::add_query_args_and_nonce($query_args, $admin_url);
1161
-    }
1162
-
1163
-
1164
-
1165
-    /**
1166
-     * Modify the edit post link generated by wp core function so that EE CPTs get setup differently.
1167
-     *
1168
-     * @param  string $link    the original generated link
1169
-     * @param  int    $id      post id
1170
-     * @param  string $context optional, defaults to display.  How to write the '&'
1171
-     * @return string          the link
1172
-     */
1173
-    public function modify_edit_post_link($link, $id, $context)
1174
-    {
1175
-        $post = get_post($id);
1176
-        if ( ! isset($this->_req_data['action'])
1177
-             || ! isset($this->_cpt_routes[$this->_req_data['action']])
1178
-             || $post->post_type !== $this->_cpt_routes[$this->_req_data['action']]
1179
-        ) {
1180
-            return $link;
1181
-        }
1182
-        $query_args = array(
1183
-            'action' => isset($this->_cpt_edit_routes[$post->post_type])
1184
-                ? $this->_cpt_edit_routes[$post->post_type]
1185
-                : 'edit',
1186
-            'post'   => $id,
1187
-        );
1188
-        return self::add_query_args_and_nonce($query_args, $this->_admin_base_url);
1189
-    }
1190
-
1191
-
1192
-    /**
1193
-     * Modify the trash link on our cpt edit pages so it has the required query var for triggering redirect properly on
1194
-     * our routes.
1195
-     *
1196
-     * @param  string $delete_link  original delete link
1197
-     * @param  int    $post_id      id of cpt object
1198
-     * @param  bool   $force_delete whether this is forcing a hard delete instead of trash
1199
-     * @return string new delete link
1200
-     * @throws EE_Error
1201
-     */
1202
-    public function modify_delete_post_link($delete_link, $post_id, $force_delete)
1203
-    {
1204
-        $post = get_post($post_id);
1205
-
1206
-        if (empty($this->_req_data['action'])
1207
-            || ! isset($this->_cpt_routes[$this->_req_data['action']])
1208
-            || ! $post instanceof WP_Post
1209
-            || $post->post_type !== $this->_cpt_routes[$this->_req_data['action']]
1210
-        ) {
1211
-            return $delete_link;
1212
-        }
1213
-        $this->_set_model_object($post->ID, true);
1214
-
1215
-        //returns something like `trash_event` or `trash_attendee` or `trash_venue`
1216
-        $action = 'trash_' . str_replace('ee_', '', strtolower(get_class($this->_cpt_model_obj)));
1217
-
1218
-        return EE_Admin_Page::add_query_args_and_nonce(
1219
-            array(
1220
-                'page' => $this->_req_data['page'],
1221
-                'action' => $action,
1222
-                $this->_cpt_model_obj->get_model()->get_primary_key_field()->get_name()
1223
-                    => $post->ID
1224
-            ),
1225
-            admin_url()
1226
-        );
1227
-    }
1228
-
1229
-
1230
-
1231
-    /**
1232
-     * This is the callback for the 'redirect_post_location' filter in wp-admin/post.php
1233
-     * so that we can hijack the default redirect locations for wp custom post types
1234
-     * that WE'RE using and send back to OUR routes.  This should only be hooked in on the right route.
1235
-     *
1236
-     * @param  string $location This is the incoming currently set redirect location
1237
-     * @param  string $post_id  This is the 'ID' value of the wp_posts table
1238
-     * @return string           the new location to redirect to
1239
-     */
1240
-    public function cpt_post_location_redirect($location, $post_id)
1241
-    {
1242
-        //we DO have a match so let's setup the url
1243
-        //we have to get the post to determine our route
1244
-        $post       = get_post($post_id);
1245
-        $edit_route = $this->_cpt_edit_routes[$post->post_type];
1246
-        //shared query_args
1247
-        $query_args = array('action' => $edit_route, 'post' => $post_id);
1248
-        $admin_url  = $this->_admin_base_url;
1249
-        if (isset($this->_req_data['save']) || isset($this->_req_data['publish'])) {
1250
-            $status = get_post_status($post_id);
1251
-            if (isset($this->_req_data['publish'])) {
1252
-                switch ($status) {
1253
-                    case 'pending':
1254
-                        $message = 8;
1255
-                        break;
1256
-                    case 'future':
1257
-                        $message = 9;
1258
-                        break;
1259
-                    default:
1260
-                        $message = 6;
1261
-                }
1262
-            } else {
1263
-                $message = 'draft' === $status ? 10 : 1;
1264
-            }
1265
-        } else if (isset($this->_req_data['addmeta']) && $this->_req_data['addmeta']) {
1266
-            $message = 2;
1267
-            //			$append = '#postcustom';
1268
-        } else if (isset($this->_req_data['deletemeta']) && $this->_req_data['deletemeta']) {
1269
-            $message = 3;
1270
-            //			$append = '#postcustom';
1271
-        } elseif ($this->_req_data['action'] === 'post-quickpress-save-cont') {
1272
-            $message = 7;
1273
-        } else {
1274
-            $message = 4;
1275
-        }
1276
-        //change the message if the post type is not viewable on the frontend
1277
-        $this->_cpt_object = get_post_type_object($post->post_type);
1278
-        $message           = $message === 1 && ! $this->_cpt_object->publicly_queryable ? 4 : $message;
1279
-        $query_args = array_merge(array('message' => $message), $query_args);
1280
-        $this->_process_notices($query_args, true);
1281
-        return self::add_query_args_and_nonce($query_args, $admin_url);
1282
-    }
1283
-
1284
-
1285
-
1286
-    /**
1287
-     * This method is called to inject nav tabs on core WP cpt pages
1288
-     *
1289
-     * @access public
1290
-     * @return void
1291
-     */
1292
-    public function inject_nav_tabs()
1293
-    {
1294
-        //can we hijack and insert the nav_tabs?
1295
-        $nav_tabs = $this->_get_main_nav_tabs();
1296
-        //first close off existing form tag
1297
-        $html = '>';
1298
-        $html .= $nav_tabs;
1299
-        //now let's handle the remaining tag ( missing ">" is CORRECT )
1300
-        $html .= '<span></span';
1301
-        echo $html;
1302
-    }
1303
-
1304
-
1305
-
1306
-    /**
1307
-     * This just sets up the post update messages when an update form is loaded
1308
-     *
1309
-     * @access public
1310
-     * @param  array $messages the original messages array
1311
-     * @return array           the new messages array
1312
-     */
1313
-    public function post_update_messages($messages)
1314
-    {
1315
-        global $post;
1316
-        $id = isset($this->_req_data['post']) ? $this->_req_data['post'] : null;
1317
-        $id = empty($id) && is_object($post) ? $post->ID : null;
1318
-        //		$post_type = $post ? $post->post_type : false;
1319
-        /*$current_route = isset($this->_req_data['current_route']) ? $this->_req_data['current_route'] : 'shouldneverwork';
1054
+	}
1055
+
1056
+
1057
+
1058
+	/**
1059
+	 * This allows child classes to modify the default editor title that appears when people add a new or edit an
1060
+	 * existing CPT item.     * This uses the _labels property set by the child class via _define_page_props. Just make
1061
+	 * sure you have a key in _labels property that equals 'editor_title' and the value can be whatever you want the
1062
+	 * default to be.
1063
+	 *
1064
+	 * @param string $title The new title (or existing if there is no editor_title defined)
1065
+	 * @return string
1066
+	 */
1067
+	public function add_custom_editor_default_title($title)
1068
+	{
1069
+		return isset($this->_labels['editor_title'][$this->_cpt_routes[$this->_req_action]])
1070
+			? $this->_labels['editor_title'][$this->_cpt_routes[$this->_req_action]]
1071
+			: $title;
1072
+	}
1073
+
1074
+
1075
+
1076
+	/**
1077
+	 * hooks into the wp_get_shortlink button and makes sure that the shortlink gets generated
1078
+	 *
1079
+	 * @param string $shortlink   The already generated shortlink
1080
+	 * @param int    $id          Post ID for this item
1081
+	 * @param string $context     The context for the link
1082
+	 * @param bool   $allow_slugs Whether to allow post slugs in the shortlink.
1083
+	 * @return string
1084
+	 */
1085
+	public function add_shortlink_button_to_editor($shortlink, $id, $context, $allow_slugs)
1086
+	{
1087
+		if ( ! empty($id) && get_option('permalink_structure') !== '') {
1088
+			$post = get_post($id);
1089
+			if (isset($post->post_type) && $this->page_slug === $post->post_type) {
1090
+				$shortlink = home_url('?p=' . $post->ID);
1091
+			}
1092
+		}
1093
+		return $shortlink;
1094
+	}
1095
+
1096
+
1097
+
1098
+	/**
1099
+	 * overriding the parent route_admin_request method so we DON'T run the route twice on cpt core page loads (it's
1100
+	 * already run in modify_current_screen())
1101
+	 *
1102
+	 * @return void
1103
+	 */
1104
+	public function route_admin_request()
1105
+	{
1106
+		if ($this->_cpt_route) {
1107
+			return;
1108
+		}
1109
+		try {
1110
+			$this->_route_admin_request();
1111
+		} catch (EE_Error $e) {
1112
+			$e->get_error();
1113
+		}
1114
+	}
1115
+
1116
+
1117
+
1118
+	/**
1119
+	 * Add a hidden form input to cpt core pages so that we know to do redirects to our routes on saves
1120
+	 *
1121
+	 * @return void
1122
+	 */
1123
+	public function cpt_post_form_hidden_input()
1124
+	{
1125
+		echo '<input type="hidden" name="ee_cpt_item_redirect_url" value="' . $this->_admin_base_url . '" />';
1126
+		//we're also going to add the route value and the current page so we can direct autosave parsing correctly
1127
+		echo '<div id="ee-cpt-hidden-inputs">';
1128
+		echo '<input type="hidden" id="current_route" name="current_route" value="' . $this->_current_view . '" />';
1129
+		echo '<input type="hidden" id="current_page" name="current_page" value="' . $this->page_slug . '" />';
1130
+		echo '</div>';
1131
+	}
1132
+
1133
+
1134
+
1135
+	/**
1136
+	 * This allows us to redirect the location of revision restores when they happen so it goes to our CPT routes.
1137
+	 *
1138
+	 * @param  string $location Original location url
1139
+	 * @param  int    $status   Status for http header
1140
+	 * @return string           new (or original) url to redirect to.
1141
+	 */
1142
+	public function revision_redirect($location, $status)
1143
+	{
1144
+		//get revision
1145
+		$rev_id = isset($this->_req_data['revision']) ? $this->_req_data['revision'] : null;
1146
+		//can't do anything without revision so let's get out if not present
1147
+		if (empty($rev_id)) {
1148
+			return $location;
1149
+		}
1150
+		//get rev_post_data
1151
+		$rev = get_post($rev_id);
1152
+		$admin_url = $this->_admin_base_url;
1153
+		$query_args = array(
1154
+			'action'   => 'edit',
1155
+			'post'     => $rev->post_parent,
1156
+			'revision' => $rev_id,
1157
+			'message'  => 5,
1158
+		);
1159
+		$this->_process_notices($query_args, true);
1160
+		return self::add_query_args_and_nonce($query_args, $admin_url);
1161
+	}
1162
+
1163
+
1164
+
1165
+	/**
1166
+	 * Modify the edit post link generated by wp core function so that EE CPTs get setup differently.
1167
+	 *
1168
+	 * @param  string $link    the original generated link
1169
+	 * @param  int    $id      post id
1170
+	 * @param  string $context optional, defaults to display.  How to write the '&'
1171
+	 * @return string          the link
1172
+	 */
1173
+	public function modify_edit_post_link($link, $id, $context)
1174
+	{
1175
+		$post = get_post($id);
1176
+		if ( ! isset($this->_req_data['action'])
1177
+			 || ! isset($this->_cpt_routes[$this->_req_data['action']])
1178
+			 || $post->post_type !== $this->_cpt_routes[$this->_req_data['action']]
1179
+		) {
1180
+			return $link;
1181
+		}
1182
+		$query_args = array(
1183
+			'action' => isset($this->_cpt_edit_routes[$post->post_type])
1184
+				? $this->_cpt_edit_routes[$post->post_type]
1185
+				: 'edit',
1186
+			'post'   => $id,
1187
+		);
1188
+		return self::add_query_args_and_nonce($query_args, $this->_admin_base_url);
1189
+	}
1190
+
1191
+
1192
+	/**
1193
+	 * Modify the trash link on our cpt edit pages so it has the required query var for triggering redirect properly on
1194
+	 * our routes.
1195
+	 *
1196
+	 * @param  string $delete_link  original delete link
1197
+	 * @param  int    $post_id      id of cpt object
1198
+	 * @param  bool   $force_delete whether this is forcing a hard delete instead of trash
1199
+	 * @return string new delete link
1200
+	 * @throws EE_Error
1201
+	 */
1202
+	public function modify_delete_post_link($delete_link, $post_id, $force_delete)
1203
+	{
1204
+		$post = get_post($post_id);
1205
+
1206
+		if (empty($this->_req_data['action'])
1207
+			|| ! isset($this->_cpt_routes[$this->_req_data['action']])
1208
+			|| ! $post instanceof WP_Post
1209
+			|| $post->post_type !== $this->_cpt_routes[$this->_req_data['action']]
1210
+		) {
1211
+			return $delete_link;
1212
+		}
1213
+		$this->_set_model_object($post->ID, true);
1214
+
1215
+		//returns something like `trash_event` or `trash_attendee` or `trash_venue`
1216
+		$action = 'trash_' . str_replace('ee_', '', strtolower(get_class($this->_cpt_model_obj)));
1217
+
1218
+		return EE_Admin_Page::add_query_args_and_nonce(
1219
+			array(
1220
+				'page' => $this->_req_data['page'],
1221
+				'action' => $action,
1222
+				$this->_cpt_model_obj->get_model()->get_primary_key_field()->get_name()
1223
+					=> $post->ID
1224
+			),
1225
+			admin_url()
1226
+		);
1227
+	}
1228
+
1229
+
1230
+
1231
+	/**
1232
+	 * This is the callback for the 'redirect_post_location' filter in wp-admin/post.php
1233
+	 * so that we can hijack the default redirect locations for wp custom post types
1234
+	 * that WE'RE using and send back to OUR routes.  This should only be hooked in on the right route.
1235
+	 *
1236
+	 * @param  string $location This is the incoming currently set redirect location
1237
+	 * @param  string $post_id  This is the 'ID' value of the wp_posts table
1238
+	 * @return string           the new location to redirect to
1239
+	 */
1240
+	public function cpt_post_location_redirect($location, $post_id)
1241
+	{
1242
+		//we DO have a match so let's setup the url
1243
+		//we have to get the post to determine our route
1244
+		$post       = get_post($post_id);
1245
+		$edit_route = $this->_cpt_edit_routes[$post->post_type];
1246
+		//shared query_args
1247
+		$query_args = array('action' => $edit_route, 'post' => $post_id);
1248
+		$admin_url  = $this->_admin_base_url;
1249
+		if (isset($this->_req_data['save']) || isset($this->_req_data['publish'])) {
1250
+			$status = get_post_status($post_id);
1251
+			if (isset($this->_req_data['publish'])) {
1252
+				switch ($status) {
1253
+					case 'pending':
1254
+						$message = 8;
1255
+						break;
1256
+					case 'future':
1257
+						$message = 9;
1258
+						break;
1259
+					default:
1260
+						$message = 6;
1261
+				}
1262
+			} else {
1263
+				$message = 'draft' === $status ? 10 : 1;
1264
+			}
1265
+		} else if (isset($this->_req_data['addmeta']) && $this->_req_data['addmeta']) {
1266
+			$message = 2;
1267
+			//			$append = '#postcustom';
1268
+		} else if (isset($this->_req_data['deletemeta']) && $this->_req_data['deletemeta']) {
1269
+			$message = 3;
1270
+			//			$append = '#postcustom';
1271
+		} elseif ($this->_req_data['action'] === 'post-quickpress-save-cont') {
1272
+			$message = 7;
1273
+		} else {
1274
+			$message = 4;
1275
+		}
1276
+		//change the message if the post type is not viewable on the frontend
1277
+		$this->_cpt_object = get_post_type_object($post->post_type);
1278
+		$message           = $message === 1 && ! $this->_cpt_object->publicly_queryable ? 4 : $message;
1279
+		$query_args = array_merge(array('message' => $message), $query_args);
1280
+		$this->_process_notices($query_args, true);
1281
+		return self::add_query_args_and_nonce($query_args, $admin_url);
1282
+	}
1283
+
1284
+
1285
+
1286
+	/**
1287
+	 * This method is called to inject nav tabs on core WP cpt pages
1288
+	 *
1289
+	 * @access public
1290
+	 * @return void
1291
+	 */
1292
+	public function inject_nav_tabs()
1293
+	{
1294
+		//can we hijack and insert the nav_tabs?
1295
+		$nav_tabs = $this->_get_main_nav_tabs();
1296
+		//first close off existing form tag
1297
+		$html = '>';
1298
+		$html .= $nav_tabs;
1299
+		//now let's handle the remaining tag ( missing ">" is CORRECT )
1300
+		$html .= '<span></span';
1301
+		echo $html;
1302
+	}
1303
+
1304
+
1305
+
1306
+	/**
1307
+	 * This just sets up the post update messages when an update form is loaded
1308
+	 *
1309
+	 * @access public
1310
+	 * @param  array $messages the original messages array
1311
+	 * @return array           the new messages array
1312
+	 */
1313
+	public function post_update_messages($messages)
1314
+	{
1315
+		global $post;
1316
+		$id = isset($this->_req_data['post']) ? $this->_req_data['post'] : null;
1317
+		$id = empty($id) && is_object($post) ? $post->ID : null;
1318
+		//		$post_type = $post ? $post->post_type : false;
1319
+		/*$current_route = isset($this->_req_data['current_route']) ? $this->_req_data['current_route'] : 'shouldneverwork';
1320 1320
 
1321 1321
         $route_to_check = $post_type && isset( $this->_cpt_routes[$current_route]) ? $this->_cpt_routes[$current_route] : '';/**/
1322
-        $messages[$post->post_type] = array(
1323
-            0 => '', //Unused. Messages start at index 1.
1324
-            1 => sprintf(
1325
-                __('%1$s updated. %2$sView %1$s%3$s', 'event_espresso'),
1326
-                $this->_cpt_object->labels->singular_name,
1327
-                '<a href="' . esc_url(get_permalink($id)) . '">',
1328
-                '</a>'
1329
-            ),
1330
-            2 => __('Custom field updated'),
1331
-            3 => __('Custom field deleted.'),
1332
-            4 => sprintf(__('%1$s updated.', 'event_espresso'), $this->_cpt_object->labels->singular_name),
1333
-            5 => isset($_GET['revision']) ? sprintf(__('%s restored to revision from %s', 'event_espresso'),
1334
-                $this->_cpt_object->labels->singular_name, wp_post_revision_title((int)$_GET['revision'], false))
1335
-                : false,
1336
-            6 => sprintf(
1337
-                __('%1$s published. %2$sView %1$s%3$s', 'event_espresso'),
1338
-                $this->_cpt_object->labels->singular_name,
1339
-                '<a href="' . esc_url(get_permalink($id)) . '">',
1340
-                '</a>'
1341
-            ),
1342
-            7 => sprintf(__('%1$s saved.', 'event_espresso'), $this->_cpt_object->labels->singular_name),
1343
-            8 => sprintf(
1344
-                __('%1$s submitted. %2$sPreview %1$s%3$s', 'event_espresso'),
1345
-                $this->_cpt_object->labels->singular_name,
1346
-                '<a target="_blank" href="' . esc_url(add_query_arg('preview', 'true', get_permalink($id))) . '">',
1347
-                '</a>'
1348
-            ),
1349
-            9 => sprintf(
1350
-                __('%1$s scheduled for: %2$s. %3$s">Preview %1$s%3$s', 'event_espresso'),
1351
-                $this->_cpt_object->labels->singular_name,
1352
-                '<strong>' . date_i18n(__('M j, Y @ G:i'), strtotime($post->post_date)) . '</strong>',
1353
-                '<a target="_blank" href="' . esc_url(get_permalink($id)),
1354
-                '</a>'
1355
-            ),
1356
-            10 => sprintf(
1357
-                __('%1$s draft updated. %2$s">Preview page%3$s', 'event_espresso'),
1358
-                $this->_cpt_object->labels->singular_name,
1359
-                '<a target="_blank" href="' . esc_url(add_query_arg('preview', 'true', get_permalink($id))),
1360
-                '</a>'
1361
-            ),
1362
-        );
1363
-        return $messages;
1364
-    }
1365
-
1366
-
1367
-
1368
-    /**
1369
-     * default method for the 'create_new' route for cpt admin pages.
1370
-     * For reference what to include in here, see wp-admin/post-new.php
1371
-     *
1372
-     * @access  protected
1373
-     * @return void
1374
-     */
1375
-    protected function _create_new_cpt_item()
1376
-    {
1377
-        // gather template vars for WP_ADMIN_PATH . 'edit-form-advanced.php'
1378
-        global $post, $title, $is_IE, $post_type, $post_type_object;
1379
-        $post_type        = $this->_cpt_routes[$this->_req_action];
1380
-        $post_type_object = $this->_cpt_object;
1381
-        $title            = $post_type_object->labels->add_new_item;
1382
-        $editing          = true;
1383
-        wp_enqueue_script('autosave');
1384
-        $post    = $post = get_default_post_to_edit($this->_cpt_routes[$this->_req_action], true);
1385
-        $post_ID = $post->ID;
1386
-        add_action('admin_print_styles', array($this, 'add_new_admin_page_global'));
1387
-        //modify the default editor title field with default title.
1388
-        add_filter('enter_title_here', array($this, 'add_custom_editor_default_title'), 10);
1389
-        include_once WP_ADMIN_PATH . 'edit-form-advanced.php';
1390
-    }
1391
-
1392
-
1393
-
1394
-    public function add_new_admin_page_global()
1395
-    {
1396
-        $admin_page = ! empty($this->_req_data['post']) ? 'post-php' : 'post-new-php';
1397
-        ?>
1322
+		$messages[$post->post_type] = array(
1323
+			0 => '', //Unused. Messages start at index 1.
1324
+			1 => sprintf(
1325
+				__('%1$s updated. %2$sView %1$s%3$s', 'event_espresso'),
1326
+				$this->_cpt_object->labels->singular_name,
1327
+				'<a href="' . esc_url(get_permalink($id)) . '">',
1328
+				'</a>'
1329
+			),
1330
+			2 => __('Custom field updated'),
1331
+			3 => __('Custom field deleted.'),
1332
+			4 => sprintf(__('%1$s updated.', 'event_espresso'), $this->_cpt_object->labels->singular_name),
1333
+			5 => isset($_GET['revision']) ? sprintf(__('%s restored to revision from %s', 'event_espresso'),
1334
+				$this->_cpt_object->labels->singular_name, wp_post_revision_title((int)$_GET['revision'], false))
1335
+				: false,
1336
+			6 => sprintf(
1337
+				__('%1$s published. %2$sView %1$s%3$s', 'event_espresso'),
1338
+				$this->_cpt_object->labels->singular_name,
1339
+				'<a href="' . esc_url(get_permalink($id)) . '">',
1340
+				'</a>'
1341
+			),
1342
+			7 => sprintf(__('%1$s saved.', 'event_espresso'), $this->_cpt_object->labels->singular_name),
1343
+			8 => sprintf(
1344
+				__('%1$s submitted. %2$sPreview %1$s%3$s', 'event_espresso'),
1345
+				$this->_cpt_object->labels->singular_name,
1346
+				'<a target="_blank" href="' . esc_url(add_query_arg('preview', 'true', get_permalink($id))) . '">',
1347
+				'</a>'
1348
+			),
1349
+			9 => sprintf(
1350
+				__('%1$s scheduled for: %2$s. %3$s">Preview %1$s%3$s', 'event_espresso'),
1351
+				$this->_cpt_object->labels->singular_name,
1352
+				'<strong>' . date_i18n(__('M j, Y @ G:i'), strtotime($post->post_date)) . '</strong>',
1353
+				'<a target="_blank" href="' . esc_url(get_permalink($id)),
1354
+				'</a>'
1355
+			),
1356
+			10 => sprintf(
1357
+				__('%1$s draft updated. %2$s">Preview page%3$s', 'event_espresso'),
1358
+				$this->_cpt_object->labels->singular_name,
1359
+				'<a target="_blank" href="' . esc_url(add_query_arg('preview', 'true', get_permalink($id))),
1360
+				'</a>'
1361
+			),
1362
+		);
1363
+		return $messages;
1364
+	}
1365
+
1366
+
1367
+
1368
+	/**
1369
+	 * default method for the 'create_new' route for cpt admin pages.
1370
+	 * For reference what to include in here, see wp-admin/post-new.php
1371
+	 *
1372
+	 * @access  protected
1373
+	 * @return void
1374
+	 */
1375
+	protected function _create_new_cpt_item()
1376
+	{
1377
+		// gather template vars for WP_ADMIN_PATH . 'edit-form-advanced.php'
1378
+		global $post, $title, $is_IE, $post_type, $post_type_object;
1379
+		$post_type        = $this->_cpt_routes[$this->_req_action];
1380
+		$post_type_object = $this->_cpt_object;
1381
+		$title            = $post_type_object->labels->add_new_item;
1382
+		$editing          = true;
1383
+		wp_enqueue_script('autosave');
1384
+		$post    = $post = get_default_post_to_edit($this->_cpt_routes[$this->_req_action], true);
1385
+		$post_ID = $post->ID;
1386
+		add_action('admin_print_styles', array($this, 'add_new_admin_page_global'));
1387
+		//modify the default editor title field with default title.
1388
+		add_filter('enter_title_here', array($this, 'add_custom_editor_default_title'), 10);
1389
+		include_once WP_ADMIN_PATH . 'edit-form-advanced.php';
1390
+	}
1391
+
1392
+
1393
+
1394
+	public function add_new_admin_page_global()
1395
+	{
1396
+		$admin_page = ! empty($this->_req_data['post']) ? 'post-php' : 'post-new-php';
1397
+		?>
1398 1398
         <script type="text/javascript">
1399 1399
             adminpage = '<?php echo $admin_page; ?>';
1400 1400
         </script>
1401 1401
         <?php
1402
-    }
1403
-
1404
-
1405
-
1406
-    /**
1407
-     * default method for the 'edit' route for cpt admin pages
1408
-     * For reference on what to put in here, refer to wp-admin/post.php
1409
-     *
1410
-     * @access protected
1411
-     * @return string   template for edit cpt form
1412
-     */
1413
-    protected function _edit_cpt_item()
1414
-    {
1415
-        global $post, $title, $is_IE, $post_type, $post_type_object;
1416
-        $post_id = isset($this->_req_data['post']) ? $this->_req_data['post'] : null;
1417
-        $post = ! empty($post_id) ? get_post($post_id, OBJECT, 'edit') : null;
1418
-        if (empty ($post)) {
1419
-            wp_die(__('You attempted to edit an item that doesn&#8217;t exist. Perhaps it was deleted?'));
1420
-        }
1421
-        if ( ! empty($_GET['get-post-lock'])) {
1422
-            wp_set_post_lock($post_id);
1423
-            wp_redirect(get_edit_post_link($post_id, 'url'));
1424
-            exit();
1425
-        }
1426
-
1427
-        // template vars for WP_ADMIN_PATH . 'edit-form-advanced.php'
1428
-        $editing          = true;
1429
-        $post_ID          = $post_id;
1430
-        $post_type        = $this->_cpt_routes[$this->_req_action];
1431
-        $post_type_object = $this->_cpt_object;
1432
-
1433
-        if ( ! wp_check_post_lock($post->ID)) {
1434
-            $active_post_lock = wp_set_post_lock($post->ID);
1435
-            //wp_enqueue_script('autosave');
1436
-        }
1437
-        $title = $this->_cpt_object->labels->edit_item;
1438
-        add_action('admin_footer', '_admin_notice_post_locked');
1439
-        if (isset($this->_cpt_routes[$this->_req_data['action']])
1440
-            && ! isset($this->_labels['hide_add_button_on_cpt_route'][$this->_req_data['action']])
1441
-        ) {
1442
-            $create_new_action = apply_filters('FHEE__EE_Admin_Page_CPT___edit_cpt_item__create_new_action',
1443
-                'create_new', $this);
1444
-            $post_new_file = EE_Admin_Page::add_query_args_and_nonce(array(
1445
-                'action' => $create_new_action,
1446
-                'page'   => $this->page_slug,
1447
-            ), 'admin.php');
1448
-        }
1449
-        if (post_type_supports($this->_cpt_routes[$this->_req_action], 'comments')) {
1450
-            wp_enqueue_script('admin-comments');
1451
-            enqueue_comment_hotkeys_js();
1452
-        }
1453
-        add_action('admin_print_styles', array($this, 'add_new_admin_page_global'));
1454
-        //modify the default editor title field with default title.
1455
-        add_filter('enter_title_here', array($this, 'add_custom_editor_default_title'), 10);
1456
-        include_once WP_ADMIN_PATH . 'edit-form-advanced.php';
1457
-    }
1458
-
1459
-
1460
-
1461
-    /**
1462
-     * some getters
1463
-     */
1464
-    /**
1465
-     * This returns the protected _cpt_model_obj property
1466
-     *
1467
-     * @return EE_CPT_Base
1468
-     */
1469
-    public function get_cpt_model_obj()
1470
-    {
1471
-        return $this->_cpt_model_obj;
1472
-    }
1402
+	}
1403
+
1404
+
1405
+
1406
+	/**
1407
+	 * default method for the 'edit' route for cpt admin pages
1408
+	 * For reference on what to put in here, refer to wp-admin/post.php
1409
+	 *
1410
+	 * @access protected
1411
+	 * @return string   template for edit cpt form
1412
+	 */
1413
+	protected function _edit_cpt_item()
1414
+	{
1415
+		global $post, $title, $is_IE, $post_type, $post_type_object;
1416
+		$post_id = isset($this->_req_data['post']) ? $this->_req_data['post'] : null;
1417
+		$post = ! empty($post_id) ? get_post($post_id, OBJECT, 'edit') : null;
1418
+		if (empty ($post)) {
1419
+			wp_die(__('You attempted to edit an item that doesn&#8217;t exist. Perhaps it was deleted?'));
1420
+		}
1421
+		if ( ! empty($_GET['get-post-lock'])) {
1422
+			wp_set_post_lock($post_id);
1423
+			wp_redirect(get_edit_post_link($post_id, 'url'));
1424
+			exit();
1425
+		}
1426
+
1427
+		// template vars for WP_ADMIN_PATH . 'edit-form-advanced.php'
1428
+		$editing          = true;
1429
+		$post_ID          = $post_id;
1430
+		$post_type        = $this->_cpt_routes[$this->_req_action];
1431
+		$post_type_object = $this->_cpt_object;
1432
+
1433
+		if ( ! wp_check_post_lock($post->ID)) {
1434
+			$active_post_lock = wp_set_post_lock($post->ID);
1435
+			//wp_enqueue_script('autosave');
1436
+		}
1437
+		$title = $this->_cpt_object->labels->edit_item;
1438
+		add_action('admin_footer', '_admin_notice_post_locked');
1439
+		if (isset($this->_cpt_routes[$this->_req_data['action']])
1440
+			&& ! isset($this->_labels['hide_add_button_on_cpt_route'][$this->_req_data['action']])
1441
+		) {
1442
+			$create_new_action = apply_filters('FHEE__EE_Admin_Page_CPT___edit_cpt_item__create_new_action',
1443
+				'create_new', $this);
1444
+			$post_new_file = EE_Admin_Page::add_query_args_and_nonce(array(
1445
+				'action' => $create_new_action,
1446
+				'page'   => $this->page_slug,
1447
+			), 'admin.php');
1448
+		}
1449
+		if (post_type_supports($this->_cpt_routes[$this->_req_action], 'comments')) {
1450
+			wp_enqueue_script('admin-comments');
1451
+			enqueue_comment_hotkeys_js();
1452
+		}
1453
+		add_action('admin_print_styles', array($this, 'add_new_admin_page_global'));
1454
+		//modify the default editor title field with default title.
1455
+		add_filter('enter_title_here', array($this, 'add_custom_editor_default_title'), 10);
1456
+		include_once WP_ADMIN_PATH . 'edit-form-advanced.php';
1457
+	}
1458
+
1459
+
1460
+
1461
+	/**
1462
+	 * some getters
1463
+	 */
1464
+	/**
1465
+	 * This returns the protected _cpt_model_obj property
1466
+	 *
1467
+	 * @return EE_CPT_Base
1468
+	 */
1469
+	public function get_cpt_model_obj()
1470
+	{
1471
+		return $this->_cpt_model_obj;
1472
+	}
1473 1473
 
1474 1474
 }
Please login to merge, or discard this patch.
Spacing   +25 added lines, -25 removed lines patch added patch discarded remove patch
@@ -235,7 +235,7 @@  discard block
 block discarded – undo
235 235
      */
236 236
     protected function _register_autosave_containers($ids)
237 237
     {
238
-        $this->_autosave_containers = array_merge($this->_autosave_fields, (array)$ids);
238
+        $this->_autosave_containers = array_merge($this->_autosave_fields, (array) $ids);
239 239
     }
240 240
 
241 241
 
@@ -282,7 +282,7 @@  discard block
 block discarded – undo
282 282
         //filter _autosave_containers
283 283
         $containers = apply_filters('FHEE__EE_Admin_Page_CPT___load_autosave_scripts_styles__containers',
284 284
             $this->_autosave_containers, $this);
285
-        $containers = apply_filters('FHEE__EE_Admin_Page_CPT__' . get_class($this) . '___load_autosave_scripts_styles__containers',
285
+        $containers = apply_filters('FHEE__EE_Admin_Page_CPT__'.get_class($this).'___load_autosave_scripts_styles__containers',
286 286
             $containers, $this);
287 287
 
288 288
         wp_localize_script('event_editor_js', 'EE_AUTOSAVE_IDS',
@@ -394,7 +394,7 @@  discard block
 block discarded – undo
394 394
         // This is for any plugins that are doing things properly
395 395
         // and hooking into the load page hook for core wp cpt routes.
396 396
         global $pagenow;
397
-        do_action('load-' . $pagenow);
397
+        do_action('load-'.$pagenow);
398 398
         $this->modify_current_screen();
399 399
         add_action('admin_enqueue_scripts', array($this, 'setup_autosave_hooks'), 30);
400 400
         //we route REALLY early.
@@ -425,8 +425,8 @@  discard block
 block discarded – undo
425 425
                 'admin.php?page=espresso_registrations&action=contact_list',
426 426
             ),
427 427
             1 => array(
428
-                'edit.php?post_type=' . $this->_cpt_object->name,
429
-                'admin.php?page=' . $this->_cpt_object->name,
428
+                'edit.php?post_type='.$this->_cpt_object->name,
429
+                'admin.php?page='.$this->_cpt_object->name,
430 430
             ),
431 431
         );
432 432
         foreach ($routes_to_match as $route_matches) {
@@ -454,7 +454,7 @@  discard block
 block discarded – undo
454 454
         $cpt_has_support = ! empty($cpt_args['page_templates']);
455 455
 
456 456
         //if the installed version of WP is > 4.7 we do some additional checks.
457
-        if (EE_Recommended_Versions::check_wp_version('4.7','>=')) {
457
+        if (EE_Recommended_Versions::check_wp_version('4.7', '>=')) {
458 458
             $post_templates = wp_get_theme()->get_post_templates();
459 459
             //if there are $post_templates for this cpt, then we return false for this method because
460 460
             //that means we aren't going to load our page template manager and leave that up to the native
@@ -477,7 +477,7 @@  discard block
 block discarded – undo
477 477
         global $post;
478 478
         $template = '';
479 479
 
480
-        if (EE_Recommended_Versions::check_wp_version('4.7','>=')) {
480
+        if (EE_Recommended_Versions::check_wp_version('4.7', '>=')) {
481 481
             $page_template_count = count(get_page_templates());
482 482
         } else {
483 483
             $page_template_count = count(get_page_templates($post));
@@ -514,7 +514,7 @@  discard block
 block discarded – undo
514 514
         $post = get_post($id);
515 515
         if ('publish' !== get_post_status($post)) {
516 516
             //include shims for the `get_preview_post_link` function
517
-            require_once( EE_CORE . 'wordpress-shims.php' );
517
+            require_once(EE_CORE.'wordpress-shims.php');
518 518
             $return .= '<span_id="view-post-btn"><a target="_blank" href="'
519 519
                        . get_preview_post_link($id)
520 520
                        . '" class="button button-small">'
@@ -552,7 +552,7 @@  discard block
 block discarded – undo
552 552
             $template_args['statuses']         = $statuses;
553 553
         }
554 554
 
555
-        $template = EE_ADMIN_TEMPLATE . 'status_dropdown.template.php';
555
+        $template = EE_ADMIN_TEMPLATE.'status_dropdown.template.php';
556 556
         EEH_Template::display_template($template, $template_args);
557 557
     }
558 558
 
@@ -606,7 +606,7 @@  discard block
 block discarded – undo
606 606
             $this->_template_args['success'] = true;
607 607
         }
608 608
         do_action('AHEE__EE_Admin_Page_CPT__do_extra_autosave_stuff__global_after', $this);
609
-        do_action('AHEE__EE_Admin_Page_CPT__do_extra_autosave_stuff__after_' . get_class($this), $this);
609
+        do_action('AHEE__EE_Admin_Page_CPT__do_extra_autosave_stuff__after_'.get_class($this), $this);
610 610
         //now let's return json
611 611
         $this->_return_json();
612 612
     }
@@ -1009,7 +1009,7 @@  discard block
 block discarded – undo
1009 1009
         //global action
1010 1010
         do_action('AHEE_EE_Admin_Page_CPT__restore_revision', $post_id, $revision_id);
1011 1011
         //class specific action so you can limit hooking into a specific page.
1012
-        do_action('AHEE_EE_Admin_Page_CPT_' . get_class($this) . '__restore_revision', $post_id, $revision_id);
1012
+        do_action('AHEE_EE_Admin_Page_CPT_'.get_class($this).'__restore_revision', $post_id, $revision_id);
1013 1013
     }
1014 1014
 
1015 1015
 
@@ -1087,7 +1087,7 @@  discard block
 block discarded – undo
1087 1087
         if ( ! empty($id) && get_option('permalink_structure') !== '') {
1088 1088
             $post = get_post($id);
1089 1089
             if (isset($post->post_type) && $this->page_slug === $post->post_type) {
1090
-                $shortlink = home_url('?p=' . $post->ID);
1090
+                $shortlink = home_url('?p='.$post->ID);
1091 1091
             }
1092 1092
         }
1093 1093
         return $shortlink;
@@ -1122,11 +1122,11 @@  discard block
 block discarded – undo
1122 1122
      */
1123 1123
     public function cpt_post_form_hidden_input()
1124 1124
     {
1125
-        echo '<input type="hidden" name="ee_cpt_item_redirect_url" value="' . $this->_admin_base_url . '" />';
1125
+        echo '<input type="hidden" name="ee_cpt_item_redirect_url" value="'.$this->_admin_base_url.'" />';
1126 1126
         //we're also going to add the route value and the current page so we can direct autosave parsing correctly
1127 1127
         echo '<div id="ee-cpt-hidden-inputs">';
1128
-        echo '<input type="hidden" id="current_route" name="current_route" value="' . $this->_current_view . '" />';
1129
-        echo '<input type="hidden" id="current_page" name="current_page" value="' . $this->page_slug . '" />';
1128
+        echo '<input type="hidden" id="current_route" name="current_route" value="'.$this->_current_view.'" />';
1129
+        echo '<input type="hidden" id="current_page" name="current_page" value="'.$this->page_slug.'" />';
1130 1130
         echo '</div>';
1131 1131
     }
1132 1132
 
@@ -1213,7 +1213,7 @@  discard block
 block discarded – undo
1213 1213
         $this->_set_model_object($post->ID, true);
1214 1214
 
1215 1215
         //returns something like `trash_event` or `trash_attendee` or `trash_venue`
1216
-        $action = 'trash_' . str_replace('ee_', '', strtolower(get_class($this->_cpt_model_obj)));
1216
+        $action = 'trash_'.str_replace('ee_', '', strtolower(get_class($this->_cpt_model_obj)));
1217 1217
 
1218 1218
         return EE_Admin_Page::add_query_args_and_nonce(
1219 1219
             array(
@@ -1324,39 +1324,39 @@  discard block
 block discarded – undo
1324 1324
             1 => sprintf(
1325 1325
                 __('%1$s updated. %2$sView %1$s%3$s', 'event_espresso'),
1326 1326
                 $this->_cpt_object->labels->singular_name,
1327
-                '<a href="' . esc_url(get_permalink($id)) . '">',
1327
+                '<a href="'.esc_url(get_permalink($id)).'">',
1328 1328
                 '</a>'
1329 1329
             ),
1330 1330
             2 => __('Custom field updated'),
1331 1331
             3 => __('Custom field deleted.'),
1332 1332
             4 => sprintf(__('%1$s updated.', 'event_espresso'), $this->_cpt_object->labels->singular_name),
1333 1333
             5 => isset($_GET['revision']) ? sprintf(__('%s restored to revision from %s', 'event_espresso'),
1334
-                $this->_cpt_object->labels->singular_name, wp_post_revision_title((int)$_GET['revision'], false))
1334
+                $this->_cpt_object->labels->singular_name, wp_post_revision_title((int) $_GET['revision'], false))
1335 1335
                 : false,
1336 1336
             6 => sprintf(
1337 1337
                 __('%1$s published. %2$sView %1$s%3$s', 'event_espresso'),
1338 1338
                 $this->_cpt_object->labels->singular_name,
1339
-                '<a href="' . esc_url(get_permalink($id)) . '">',
1339
+                '<a href="'.esc_url(get_permalink($id)).'">',
1340 1340
                 '</a>'
1341 1341
             ),
1342 1342
             7 => sprintf(__('%1$s saved.', 'event_espresso'), $this->_cpt_object->labels->singular_name),
1343 1343
             8 => sprintf(
1344 1344
                 __('%1$s submitted. %2$sPreview %1$s%3$s', 'event_espresso'),
1345 1345
                 $this->_cpt_object->labels->singular_name,
1346
-                '<a target="_blank" href="' . esc_url(add_query_arg('preview', 'true', get_permalink($id))) . '">',
1346
+                '<a target="_blank" href="'.esc_url(add_query_arg('preview', 'true', get_permalink($id))).'">',
1347 1347
                 '</a>'
1348 1348
             ),
1349 1349
             9 => sprintf(
1350 1350
                 __('%1$s scheduled for: %2$s. %3$s">Preview %1$s%3$s', 'event_espresso'),
1351 1351
                 $this->_cpt_object->labels->singular_name,
1352
-                '<strong>' . date_i18n(__('M j, Y @ G:i'), strtotime($post->post_date)) . '</strong>',
1353
-                '<a target="_blank" href="' . esc_url(get_permalink($id)),
1352
+                '<strong>'.date_i18n(__('M j, Y @ G:i'), strtotime($post->post_date)).'</strong>',
1353
+                '<a target="_blank" href="'.esc_url(get_permalink($id)),
1354 1354
                 '</a>'
1355 1355
             ),
1356 1356
             10 => sprintf(
1357 1357
                 __('%1$s draft updated. %2$s">Preview page%3$s', 'event_espresso'),
1358 1358
                 $this->_cpt_object->labels->singular_name,
1359
-                '<a target="_blank" href="' . esc_url(add_query_arg('preview', 'true', get_permalink($id))),
1359
+                '<a target="_blank" href="'.esc_url(add_query_arg('preview', 'true', get_permalink($id))),
1360 1360
                 '</a>'
1361 1361
             ),
1362 1362
         );
@@ -1386,7 +1386,7 @@  discard block
 block discarded – undo
1386 1386
         add_action('admin_print_styles', array($this, 'add_new_admin_page_global'));
1387 1387
         //modify the default editor title field with default title.
1388 1388
         add_filter('enter_title_here', array($this, 'add_custom_editor_default_title'), 10);
1389
-        include_once WP_ADMIN_PATH . 'edit-form-advanced.php';
1389
+        include_once WP_ADMIN_PATH.'edit-form-advanced.php';
1390 1390
     }
1391 1391
 
1392 1392
 
@@ -1453,7 +1453,7 @@  discard block
 block discarded – undo
1453 1453
         add_action('admin_print_styles', array($this, 'add_new_admin_page_global'));
1454 1454
         //modify the default editor title field with default title.
1455 1455
         add_filter('enter_title_here', array($this, 'add_custom_editor_default_title'), 10);
1456
-        include_once WP_ADMIN_PATH . 'edit-form-advanced.php';
1456
+        include_once WP_ADMIN_PATH.'edit-form-advanced.php';
1457 1457
     }
1458 1458
 
1459 1459
 
Please login to merge, or discard this patch.
core/EE_System.core.php 1 patch
Indentation   +786 added lines, -786 removed lines patch added patch discarded remove patch
@@ -30,804 +30,804 @@
 block discarded – undo
30 30
 {
31 31
 
32 32
 
33
-    /**
34
-     * @deprecated 4.9.40
35
-     * @see        \EventEspresso\core\services\activation\RequestTypeDetector
36
-     */
37
-    const req_type_normal = 0;
38
-
39
-    /**
40
-     * @deprecated 4.9.40
41
-     * @see        \EventEspresso\core\services\activation\RequestTypeDetector
42
-     */
43
-    const req_type_new_activation = 1;
44
-
45
-    /**
46
-     * @deprecated 4.9.40
47
-     * @see        \EventEspresso\core\services\activation\RequestTypeDetector
48
-     */
49
-    const req_type_reactivation = 2;
50
-
51
-    /**
52
-     * @deprecated 4.9.40
53
-     * @see        \EventEspresso\core\services\activation\RequestTypeDetector
54
-     */
55
-    const req_type_upgrade = 3;
56
-
57
-    /**
58
-     * @deprecated 4.9.40
59
-     * @see        \EventEspresso\core\services\activation\RequestTypeDetector
60
-     */
61
-    const req_type_downgrade = 4;
62
-
63
-    /**
64
-     * @deprecated since version 4.6.0.dev.006
65
-     * Now whenever a new_activation is detected the request type is still just
66
-     * new_activation (same for reactivation, upgrade, downgrade etc), but if we'r ein maintenance mode
67
-     * EE_System::initialize_db_if_no_migrations_required and EE_Addon::initialize_db_if_no_migrations_required
68
-     * will instead enqueue that EE plugin's db initialization for when we're taken out of maintenance mode.
69
-     * (Specifically, when the migration manager indicates migrations are finished
70
-     * EE_Data_Migration_Manager::initialize_db_for_enqueued_ee_plugins() will be called)
71
-     */
72
-    const req_type_activation_but_not_installed = 5;
73
-
74
-    /**
75
-     * @deprecated 4.9.40
76
-     * @see        \EventEspresso\core\services\activation\RequestTypeDetector
77
-     */
78
-    const addon_activation_history_option_prefix = 'ee_addon_activation_history_';
79
-
80
-
81
-    /**
82
-     * @var EE_System $_instance
83
-     */
84
-    private static $_instance;
85
-
86
-    /**
87
-     * @var EE_Registry $registry
88
-     */
89
-    private $registry;
90
-
91
-    /**
92
-     * @var LoaderInterface $loader
93
-     */
94
-    private $loader;
95
-
96
-    /**
97
-     * @var EE_Capabilities $capabilities
98
-     */
99
-    private $capabilities;
100
-
101
-    /**
102
-     * @var EE_Maintenance_Mode $maintenance_mode
103
-     */
104
-    private $maintenance_mode;
105
-
106
-    /**
107
-     * @var ActivationsAndUpgradesManager $activations_and_upgrades_manager
108
-     */
109
-    private $activations_and_upgrades_manager;
110
-
111
-    /**
112
-     * @var ActivationHistory $activation_history
113
-     */
114
-    private $activation_history;
115
-
116
-    /**
117
-     * @var \EventEspresso\core\services\activation\RequestType $request_type
118
-     */
119
-    private $request_type;
120
-
121
-    /**
122
-     * @var bool $activation_detected
123
-     */
124
-    private $activation_detected = false;
125
-
126
-
127
-
128
-    /**
129
-     * @singleton method used to instantiate class object
130
-     * @param EE_Registry|null         $registry
131
-     * @param LoaderInterface|null     $loader
132
-     * @param EE_Maintenance_Mode|null $maintenance_mode
133
-     * @return EE_System
134
-     */
135
-    public static function instance(
136
-        EE_Registry $registry = null,
137
-        LoaderInterface $loader = null,
138
-        EE_Maintenance_Mode $maintenance_mode = null
139
-    ) {
140
-        // check if class object is instantiated
141
-        if (! self::$_instance instanceof EE_System) {
142
-            self::$_instance = new self(
143
-                $registry,
144
-                $loader,
145
-                $maintenance_mode
146
-            );
147
-        }
148
-        return self::$_instance;
149
-    }
150
-
151
-
152
-
153
-    /**
154
-     * resets the instance and returns it
155
-     *
156
-     * @return EE_System
157
-     * @throws DomainException
158
-     * @throws InvalidArgumentException
159
-     * @throws InvalidEntityException
160
-     */
161
-    public static function reset()
162
-    {
163
-        //make sure none of the old hooks are left hanging around
164
-        remove_all_actions('AHEE__EE_System__perform_activations_upgrades_and_migrations');
165
-        //we need to reset the migration manager in order for it to detect DMSs properly
166
-        EE_Data_Migration_Manager::reset();
167
-        self::instance()->detect_activations_or_upgrades();
168
-        self::instance()->activations_and_upgrades_manager->performActivationsAndUpgrades();
169
-        return self::instance();
170
-    }
171
-
172
-
173
-
174
-    /**
175
-     * sets hooks for running rest of system
176
-     * provides "AHEE__EE_System__construct__complete" hook for EE Addons to use as their starting point
177
-     * starting EE Addons from any other point may lead to problems
178
-     *
179
-     * @param EE_Registry         $registry
180
-     * @param LoaderInterface     $loader
181
-     * @param EE_Maintenance_Mode $maintenance_mode
182
-     */
183
-    private function __construct(
184
-        EE_Registry $registry,
185
-        LoaderInterface $loader,
186
-        EE_Maintenance_Mode $maintenance_mode
187
-    ) {
188
-        $this->registry = $registry;
189
-        $this->loader = $loader;
190
-        $this->maintenance_mode = $maintenance_mode;
191
-        do_action('AHEE__EE_System__construct__begin', $this);
192
-        // allow addons to load first so that they can register autoloaders, set hooks for running DMS's, etc
193
-        add_action('AHEE__EE_Bootstrap__load_espresso_addons', array($this, 'load_espresso_addons'));
194
-        // when an ee addon is activated, we want to call the core hook(s) again
195
-        // because the newly-activated addon didn't get a chance to run at all
196
-        add_action('activate_plugin', array($this, 'load_espresso_addons'), 1);
197
-        // detect whether install or upgrade
198
-        add_action(
199
-            'AHEE__EE_Bootstrap__detect_activations_or_upgrades', array($this, 'detect_activations_or_upgrades'),
200
-            3
201
-        );
202
-        // load EE_Config, EE_Textdomain, etc
203
-        add_action('AHEE__EE_Bootstrap__load_core_configuration', array($this, 'load_core_configuration'), 5);
204
-        // load EE_Config, EE_Textdomain, etc
205
-        add_action(
206
-            'AHEE__EE_Bootstrap__register_shortcodes_modules_and_widgets',
207
-            array($this, 'register_shortcodes_modules_and_widgets'), 7
208
-        );
209
-        // you wanna get going? I wanna get going... let's get going!
210
-        add_action('AHEE__EE_Bootstrap__brew_espresso', array($this, 'brew_espresso'), 9);
211
-        //other housekeeping
212
-        //exclude EE critical pages from wp_list_pages
213
-        add_filter('wp_list_pages_excludes', array($this, 'remove_pages_from_wp_list_pages'), 10);
214
-        // ALL EE Addons should use the following hook point to attach their initial setup too
215
-        // it's extremely important for EE Addons to register any class autoloaders so that they can be available when the EE_Config loads
216
-        do_action('AHEE__EE_System__construct__complete', $this);
217
-    }
218
-
219
-
220
-
221
-    /**
222
-     * Gets the ActivationHistory object for this addon
223
-     *
224
-     * @return ActivationHistory
225
-     */
226
-    public function getActivationHistory()
227
-    {
228
-        return $this->activation_history;
229
-    }
230
-
231
-
232
-
233
-    /**
234
-     * @param ActivationHistory $activation_history
235
-     */
236
-    public function setActivationHistory(ActivationHistory $activation_history)
237
-    {
238
-        $this->activation_history = $activation_history;
239
-    }
240
-
241
-
242
-
243
-    /**
244
-     * @return RequestType
245
-     */
246
-    public function getRequestType()
247
-    {
248
-        return $this->request_type;
249
-    }
250
-
251
-
252
-
253
-    /**
254
-     * @param RequestType $request_type
255
-     */
256
-    public function setRequestType(RequestType $request_type)
257
-    {
258
-        $this->request_type = $request_type;
259
-    }
260
-
261
-    /**
262
-     * load_espresso_addons
263
-     * allow addons to load first so that they can set hooks for running DMS's, etc
264
-     * this is hooked into both:
265
-     *    'AHEE__EE_Bootstrap__load_core_configuration'
266
-     *        which runs during the WP 'plugins_loaded' action at priority 5
267
-     *    and the WP 'activate_plugin' hook point
268
-     *
269
-     * @return void
270
-     * @throws EE_Error
271
-     */
272
-    public function load_espresso_addons()
273
-    {
274
-        // set autoloaders for all of the classes implementing EEI_Plugin_API
275
-        // which provide helpers for EE plugin authors to more easily register certain components with EE.
276
-        EEH_Autoloader::instance()->register_autoloaders_for_each_file_in_folder(EE_LIBRARIES . 'plugin_api');
277
-        //caps need to be initialized on every request so that capability maps are set.
278
-        //@see https://events.codebasehq.com/projects/event-espresso/tickets/8674
279
-        $this->capabilities = $this->loader->getShared('EE_Capabilities');
280
-        $this->capabilities->init_caps();
281
-        do_action('AHEE__EE_System__load_espresso_addons');
282
-        //if the WP API basic auth plugin isn't already loaded, load it now.
283
-        //We want it for mobile apps. Just include the entire plugin
284
-        //also, don't load the basic auth when a plugin is getting activated, because
285
-        //it could be the basic auth plugin, and it doesn't check if its methods are already defined
286
-        //and causes a fatal error
287
-        if (
288
-            ! (
289
-                isset($_GET['activate'])
290
-                && $_GET['activate'] === 'true'
291
-            )
292
-            && ! function_exists('json_basic_auth_handler')
293
-            && ! function_exists('json_basic_auth_error')
294
-            && ! (
295
-                isset($_GET['action'])
296
-                && in_array($_GET['action'], array('activate', 'activate-selected'), true)
297
-            )
298
-        ) {
299
-            include_once EE_THIRD_PARTY . 'wp-api-basic-auth' . DS . 'basic-auth.php';
300
-        }
301
-        do_action('AHEE__EE_System__load_espresso_addons__complete');
302
-    }
303
-
304
-
305
-
306
-    /**
307
-     * detect_activations_or_upgrades
308
-     * Checks for activation or upgrade of core first;
309
-     * then also checks if any registered addons have been activated or upgraded
310
-     * This is hooked into 'AHEE__EE_Bootstrap__detect_activations_or_upgrades'
311
-     * which runs during the WP 'plugins_loaded' action at priority 3
312
-     *
313
-     * @return void
314
-     * @throws DomainException
315
-     * @throws InvalidArgumentException
316
-     * @throws InvalidEntityException
317
-     * @throws InvalidInterfaceException
318
-     * @throws InvalidDataTypeException
319
-     */
320
-    public function detect_activations_or_upgrades()
321
-    {
322
-        if(
323
-            (defined('DOING_AJAX') && DOING_AJAX)
324
-            || (defined('REST_REQUEST') && REST_REQUEST)
325
-        ) {
326
-            return;
327
-        }
328
-        $this->activations_and_upgrades_manager = ActivationsFactory::getActivationsAndUpgradesManager();
329
-        $this->activation_detected = $this->activations_and_upgrades_manager->detectActivationsAndVersionChanges(
330
-            array_merge(
331
-                array($this),
332
-                get_object_vars($this->registry->addons)
333
-            )
334
-        );
335
-    }
336
-
337
-
338
-
339
-    /**
340
-     * load_core_configuration
341
-     * this is hooked into 'AHEE__EE_Bootstrap__load_core_configuration'
342
-     * which runs during the WP 'plugins_loaded' action at priority 5
343
-     *
344
-     * @return void
345
-     * @throws ReflectionException
346
-     */
347
-    public function load_core_configuration()
348
-    {
349
-        do_action('AHEE__EE_System__load_core_configuration__begin', $this);
350
-        $this->loader->getShared('EE_Load_Textdomain');
351
-        //load textdomain
352
-        EE_Load_Textdomain::load_textdomain();
353
-        // load and setup EE_Config and EE_Network_Config
354
-        $config = $this->loader->getShared('EE_Config');
355
-        $this->loader->getShared('EE_Network_Config');
356
-        // setup autoloaders
357
-        // enable logging?
358
-        if ($config->admin->use_full_logging) {
359
-            $this->loader->getShared('EE_Log');
360
-        }
361
-        // check for activation errors
362
-        $activation_errors = get_option('ee_plugin_activation_errors', false);
363
-        if ($activation_errors) {
364
-            EE_Error::add_error($activation_errors, __FILE__, __FUNCTION__, __LINE__);
365
-            update_option('ee_plugin_activation_errors', false);
366
-        }
367
-        // get model names
368
-        $this->_parse_model_names();
369
-        //load caf stuff a chance to play during the activation process too.
370
-        $this->_maybe_brew_regular();
371
-        do_action('AHEE__EE_System__load_core_configuration__complete', $this);
372
-    }
373
-
374
-
375
-
376
-    /**
377
-     * cycles through all of the models/*.model.php files, and assembles an array of model names
378
-     *
379
-     * @return void
380
-     * @throws ReflectionException
381
-     */
382
-    private function _parse_model_names()
383
-    {
384
-        //get all the files in the EE_MODELS folder that end in .model.php
385
-        $models = glob(EE_MODELS . '*.model.php');
386
-        $model_names = array();
387
-        $non_abstract_db_models = array();
388
-        foreach ($models as $model) {
389
-            // get model classname
390
-            $classname = EEH_File::get_classname_from_filepath_with_standard_filename($model);
391
-            $short_name = str_replace('EEM_', '', $classname);
392
-            $reflectionClass = new ReflectionClass($classname);
393
-            if ($reflectionClass->isSubclassOf('EEM_Base') && ! $reflectionClass->isAbstract()) {
394
-                $non_abstract_db_models[$short_name] = $classname;
395
-            }
396
-            $model_names[$short_name] = $classname;
397
-        }
398
-        $this->registry->models = apply_filters('FHEE__EE_System__parse_model_names', $model_names);
399
-        $this->registry->non_abstract_db_models = apply_filters(
400
-            'FHEE__EE_System__parse_implemented_model_names',
401
-            $non_abstract_db_models
402
-        );
403
-    }
404
-
405
-
406
-
407
-    /**
408
-     * The purpose of this method is to simply check for a file named "caffeinated/brewing_regular.php" for any hooks
409
-     * that need to be setup before our EE_System launches.
410
-     *
411
-     * @return void
412
-     */
413
-    private function _maybe_brew_regular()
414
-    {
415
-        if (
416
-            ! $this->activation_detected
417
-            && (! defined('EE_DECAF') || EE_DECAF !== true)
418
-            && is_readable(EE_CAFF_PATH . 'brewing_regular.php')
419
-        ) {
420
-            require_once EE_CAFF_PATH . 'brewing_regular.php';
421
-        }
422
-    }
423
-
424
-
425
-
426
-    /**
427
-     * register_shortcodes_modules_and_widgets
428
-     * generate lists of shortcodes and modules, then verify paths and classes
429
-     * This is hooked into 'AHEE__EE_Bootstrap__register_shortcodes_modules_and_widgets'
430
-     * which runs during the WP 'plugins_loaded' action at priority 7
431
-     *
432
-     * @access public
433
-     * @return void
434
-     * @throws Exception
435
-     */
436
-    public function register_shortcodes_modules_and_widgets()
437
-    {
438
-        if ($this->activation_detected) {
439
-            return;
440
-        }
441
-        // check for addons using old hook point
442
-        if (has_action('AHEE__EE_System__register_shortcodes_modules_and_addons')) {
443
-            $this->_incompatible_addon_error();
444
-        }
445
-        do_action('AHEE__EE_System__register_shortcodes_modules_and_widgets');
446
-        try {
447
-            // load, register, and add shortcodes the new way
448
-            new ShortcodesManager(
449
-            // and the old way, but we'll put it under control of the new system
450
-                EE_Config::getLegacyShortcodesManager()
451
-            );
452
-        } catch (Exception $exception) {
453
-            new ExceptionStackTraceDisplay($exception);
454
-        }
455
-    }
456
-
457
-
458
-
459
-    /**
460
-     * _incompatible_addon_error
461
-     *
462
-     * @access public
463
-     * @return void
464
-     */
465
-    private function _incompatible_addon_error()
466
-    {
467
-        // get array of classes hooking into here
468
-        $class_names = EEH_Class_Tools::get_class_names_for_all_callbacks_on_hook(
469
-            'AHEE__EE_System__register_shortcodes_modules_and_addons'
470
-        );
471
-        if (! empty($class_names)) {
472
-            $msg = __(
473
-                'The following plugins, addons, or modules appear to be incompatible with this version of Event Espresso and were automatically deactivated to avoid fatal errors:',
474
-                'event_espresso'
475
-            );
476
-            $msg .= '<ul>';
477
-            foreach ($class_names as $class_name) {
478
-                $msg .= '<li><b>Event Espresso - ' . str_replace(
479
-                        array('EE_', 'EEM_', 'EED_', 'EES_', 'EEW_'), '',
480
-                        $class_name
481
-                    ) . '</b></li>';
482
-            }
483
-            $msg .= '</ul>';
484
-            $msg .= __(
485
-                'Compatibility issues can be avoided and/or resolved by keeping addons and plugins updated to the latest version.',
486
-                'event_espresso'
487
-            );
488
-            // save list of incompatible addons to wp-options for later use
489
-            add_option('ee_incompatible_addons', $class_names, '', 'no');
490
-            if (is_admin()) {
491
-                EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
492
-            }
493
-        }
494
-    }
495
-
496
-
497
-
498
-    /**
499
-     * brew_espresso
500
-     * begins the process of setting hooks for initializing EE in the correct order
501
-     * This is happening on the 'AHEE__EE_Bootstrap__brew_espresso' hook point
502
-     * which runs during the WP 'plugins_loaded' action at priority 9
503
-     *
504
-     * @return void
505
-     */
506
-    public function brew_espresso()
507
-    {
508
-        if ($this->activation_detected) {
509
-            add_action('init', array($this, 'perform_activations_upgrades_and_migrations'), 3);
510
-            return;
511
-        }
512
-        do_action('AHEE__EE_System__brew_espresso__begin', $this);
513
-        // load some final core systems
514
-        add_action('init', array($this, 'set_hooks_for_core'), 1);
515
-        add_action('init', array($this, 'load_CPTs_and_session'), 5);
516
-        add_action('init', array($this, 'load_controllers'), 7);
517
-        add_action('init', array($this, 'core_loaded_and_ready'), 9);
518
-        add_action('init', array($this, 'initialize'), 10);
519
-        add_action('init', array($this, 'initialize_last'), 100);
520
-        if (is_admin() && apply_filters('FHEE__EE_System__brew_espresso__load_pue', true)) {
521
-            // pew pew pew
522
-            $this->loader->getShared('EE_PUE');
523
-            do_action('AHEE__EE_System__brew_espresso__after_pue_init');
524
-        }
525
-        do_action('AHEE__EE_System__brew_espresso__complete', $this);
526
-    }
527
-
528
-
529
-
530
-    /**
531
-     *    set_hooks_for_core
532
-     *
533
-     * @access public
534
-     * @return    void
535
-     */
536
-    public function set_hooks_for_core()
537
-    {
538
-        do_action('AHEE__EE_System__set_hooks_for_core');
539
-    }
540
-
541
-
542
-
543
-    /**
544
-     *    perform_activations_upgrades_and_migrations
545
-     *
546
-     * @access public
547
-     * @return    void
548
-     */
549
-    public function perform_activations_upgrades_and_migrations()
550
-    {
551
-        do_action('AHEE__EE_System__perform_activations_upgrades_and_migrations');
552
-    }
553
-
554
-
555
-
556
-    /**
557
-     *    load_CPTs_and_session
558
-     *
559
-     * @access public
560
-     * @return    void
561
-     */
562
-    public function load_CPTs_and_session()
563
-    {
564
-        do_action('AHEE__EE_System__load_CPTs_and_session__start');
565
-        // register Custom Post Types
566
-        $this->loader->getShared('EE_Register_CPTs');
567
-        do_action('AHEE__EE_System__load_CPTs_and_session__complete');
568
-    }
569
-
570
-
571
-
572
-    /**
573
-     * load_controllers
574
-     * this is the best place to load any additional controllers that needs access to EE core.
575
-     * it is expected that all basic core EE systems, that are not dependant on the current request are loaded at this
576
-     * time
577
-     *
578
-     * @access public
579
-     * @return void
580
-     */
581
-    public function load_controllers()
582
-    {
583
-        do_action('AHEE__EE_System__load_controllers__start');
584
-        // let's get it started
585
-        if (! is_admin() && ! $this->maintenance_mode->level()) {
586
-            do_action('AHEE__EE_System__load_controllers__load_front_controllers');
587
-            $this->loader->getShared('EE_Front_Controller');
588
-        } else if (! EE_FRONT_AJAX) {
589
-            do_action('AHEE__EE_System__load_controllers__load_admin_controllers');
590
-            $this->loader->getShared('EE_Admin');
591
-        }
592
-        do_action('AHEE__EE_System__load_controllers__complete');
593
-    }
594
-
595
-
596
-
597
-    /**
598
-     * core_loaded_and_ready
599
-     * all of the basic EE core should be loaded at this point and available regardless of M-Mode
600
-     *
601
-     * @access public
602
-     * @return void
603
-     */
604
-    public function core_loaded_and_ready()
605
-    {
606
-        $this->loader->getShared('EE_Session');
607
-        do_action('AHEE__EE_System__core_loaded_and_ready');
608
-        // load_espresso_template_tags
609
-        if (is_readable(EE_PUBLIC . 'template_tags.php')) {
610
-            require_once(EE_PUBLIC . 'template_tags.php');
611
-        }
612
-        do_action('AHEE__EE_System__set_hooks_for_shortcodes_modules_and_addons');
613
-        $this->loader->getShared('EventEspresso\core\services\assets\Registry');
614
-    }
615
-
616
-
617
-
618
-    /**
619
-     * initialize
620
-     * this is the best place to begin initializing client code
621
-     *
622
-     * @access public
623
-     * @return void
624
-     */
625
-    public function initialize()
626
-    {
627
-        do_action('AHEE__EE_System__initialize');
628
-    }
629
-
630
-
631
-
632
-    /**
633
-     * initialize_last
634
-     * this is run really late during the WP init hook point, and ensures that mostly everything else that needs to
635
-     * initialize has done so
636
-     *
637
-     * @access public
638
-     * @return void
639
-     */
640
-    public function initialize_last()
641
-    {
642
-        do_action('AHEE__EE_System__initialize_last');
643
-        add_action('admin_bar_init', array($this, 'addEspressoToolbar'));
644
-    }
645
-
646
-
647
-
648
-    /**
649
-     * @return void
650
-     * @throws EE_Error
651
-     */
652
-    public function addEspressoToolbar()
653
-    {
654
-        $this->registry->create(
655
-            'EventEspresso\core\domain\services\admin\AdminToolBar',
656
-            array($this->registry->CAP)
657
-        );
658
-    }
659
-
660
-
661
-
662
-    /**
663
-     * do_not_cache
664
-     * sets no cache headers and defines no cache constants for WP plugins
665
-     *
666
-     * @access public
667
-     * @return void
668
-     */
669
-    public static function do_not_cache()
670
-    {
671
-        // set no cache constants
672
-        if (! defined('DONOTCACHEPAGE')) {
673
-            define('DONOTCACHEPAGE', true);
674
-        }
675
-        if (! defined('DONOTCACHCEOBJECT')) {
676
-            define('DONOTCACHCEOBJECT', true);
677
-        }
678
-        if (! defined('DONOTCACHEDB')) {
679
-            define('DONOTCACHEDB', true);
680
-        }
681
-        // add no cache headers
682
-        add_action('send_headers', array('EE_System', 'nocache_headers'), 10);
683
-        // plus a little extra for nginx and Google Chrome
684
-        add_filter('nocache_headers', array('EE_System', 'extra_nocache_headers'), 10, 1);
685
-        // prevent browsers from prefetching of the rel='next' link, because it may contain content that interferes with the registration process
686
-        remove_action('wp_head', 'adjacent_posts_rel_link_wp_head');
687
-    }
688
-
689
-
690
-
691
-    /**
692
-     *    extra_nocache_headers
693
-     *
694
-     * @access    public
695
-     * @param $headers
696
-     * @return    array
697
-     */
698
-    public static function extra_nocache_headers($headers)
699
-    {
700
-        // for NGINX
701
-        $headers['X-Accel-Expires'] = 0;
702
-        // plus extra for Google Chrome since it doesn't seem to respect "no-cache", but WILL respect "no-store"
703
-        $headers['Cache-Control'] = 'no-store, no-cache, must-revalidate, max-age=0';
704
-        return $headers;
705
-    }
706
-
707
-
708
-
709
-    /**
710
-     *    nocache_headers
711
-     *
712
-     * @access    public
713
-     * @return    void
714
-     */
715
-    public static function nocache_headers()
716
-    {
717
-        nocache_headers();
718
-    }
719
-
720
-
721
-
722
-
723
-    /**
724
-     * simply hooks into "wp_list_pages_exclude" filter (for wp_list_pages method) and makes sure EE critical pages are
725
-     * never returned with the function.
726
-     *
727
-     * @param  array $exclude_array any existing pages being excluded are in this array.
728
-     * @return array
729
-     */
730
-    public function remove_pages_from_wp_list_pages($exclude_array)
731
-    {
732
-        return array_merge($exclude_array, $this->registry->CFG->core->get_critical_pages_array());
733
-    }
734
-
735
-
736
-
737
-    /******************************** DEPRECATED ***************************************/
738
-
739
-
740
-
741
-    /**
742
-     * @deprecated 4.9.40
743
-     * @return void
744
-     */
745
-    public function detect_if_activation_or_upgrade()
746
-    {
747
-    }
748
-
749
-
750
-
751
-    /**
752
-     * @deprecated 4.9.40
753
-     * @return void
754
-     */
755
-    public function update_list_of_installed_versions($version_history = null, $current_version_to_add = null)
756
-    {
757
-    }
758
-
759
-
760
-
761
-    /**
762
-     * @deprecated 4.9.40
763
-     * @param null $espresso_db_update
764
-     * @return int one of the constants on EE_System::req_type_
765
-     */
766
-    public function detect_req_type($espresso_db_update = null)
767
-    {
768
-        return $this->getRequestType()->getRequestType();
769
-    }
770
-
771
-
772
-
773
-    /**
774
-     * @deprecated 4.9.40
775
-     * @return bool
776
-     */
777
-    public function is_major_version_change()
778
-    {
779
-        return $this->getRequestType()->isMajorVersionChange();
780
-    }
33
+	/**
34
+	 * @deprecated 4.9.40
35
+	 * @see        \EventEspresso\core\services\activation\RequestTypeDetector
36
+	 */
37
+	const req_type_normal = 0;
38
+
39
+	/**
40
+	 * @deprecated 4.9.40
41
+	 * @see        \EventEspresso\core\services\activation\RequestTypeDetector
42
+	 */
43
+	const req_type_new_activation = 1;
44
+
45
+	/**
46
+	 * @deprecated 4.9.40
47
+	 * @see        \EventEspresso\core\services\activation\RequestTypeDetector
48
+	 */
49
+	const req_type_reactivation = 2;
50
+
51
+	/**
52
+	 * @deprecated 4.9.40
53
+	 * @see        \EventEspresso\core\services\activation\RequestTypeDetector
54
+	 */
55
+	const req_type_upgrade = 3;
56
+
57
+	/**
58
+	 * @deprecated 4.9.40
59
+	 * @see        \EventEspresso\core\services\activation\RequestTypeDetector
60
+	 */
61
+	const req_type_downgrade = 4;
62
+
63
+	/**
64
+	 * @deprecated since version 4.6.0.dev.006
65
+	 * Now whenever a new_activation is detected the request type is still just
66
+	 * new_activation (same for reactivation, upgrade, downgrade etc), but if we'r ein maintenance mode
67
+	 * EE_System::initialize_db_if_no_migrations_required and EE_Addon::initialize_db_if_no_migrations_required
68
+	 * will instead enqueue that EE plugin's db initialization for when we're taken out of maintenance mode.
69
+	 * (Specifically, when the migration manager indicates migrations are finished
70
+	 * EE_Data_Migration_Manager::initialize_db_for_enqueued_ee_plugins() will be called)
71
+	 */
72
+	const req_type_activation_but_not_installed = 5;
73
+
74
+	/**
75
+	 * @deprecated 4.9.40
76
+	 * @see        \EventEspresso\core\services\activation\RequestTypeDetector
77
+	 */
78
+	const addon_activation_history_option_prefix = 'ee_addon_activation_history_';
79
+
80
+
81
+	/**
82
+	 * @var EE_System $_instance
83
+	 */
84
+	private static $_instance;
85
+
86
+	/**
87
+	 * @var EE_Registry $registry
88
+	 */
89
+	private $registry;
90
+
91
+	/**
92
+	 * @var LoaderInterface $loader
93
+	 */
94
+	private $loader;
95
+
96
+	/**
97
+	 * @var EE_Capabilities $capabilities
98
+	 */
99
+	private $capabilities;
100
+
101
+	/**
102
+	 * @var EE_Maintenance_Mode $maintenance_mode
103
+	 */
104
+	private $maintenance_mode;
105
+
106
+	/**
107
+	 * @var ActivationsAndUpgradesManager $activations_and_upgrades_manager
108
+	 */
109
+	private $activations_and_upgrades_manager;
110
+
111
+	/**
112
+	 * @var ActivationHistory $activation_history
113
+	 */
114
+	private $activation_history;
115
+
116
+	/**
117
+	 * @var \EventEspresso\core\services\activation\RequestType $request_type
118
+	 */
119
+	private $request_type;
120
+
121
+	/**
122
+	 * @var bool $activation_detected
123
+	 */
124
+	private $activation_detected = false;
125
+
126
+
127
+
128
+	/**
129
+	 * @singleton method used to instantiate class object
130
+	 * @param EE_Registry|null         $registry
131
+	 * @param LoaderInterface|null     $loader
132
+	 * @param EE_Maintenance_Mode|null $maintenance_mode
133
+	 * @return EE_System
134
+	 */
135
+	public static function instance(
136
+		EE_Registry $registry = null,
137
+		LoaderInterface $loader = null,
138
+		EE_Maintenance_Mode $maintenance_mode = null
139
+	) {
140
+		// check if class object is instantiated
141
+		if (! self::$_instance instanceof EE_System) {
142
+			self::$_instance = new self(
143
+				$registry,
144
+				$loader,
145
+				$maintenance_mode
146
+			);
147
+		}
148
+		return self::$_instance;
149
+	}
150
+
151
+
152
+
153
+	/**
154
+	 * resets the instance and returns it
155
+	 *
156
+	 * @return EE_System
157
+	 * @throws DomainException
158
+	 * @throws InvalidArgumentException
159
+	 * @throws InvalidEntityException
160
+	 */
161
+	public static function reset()
162
+	{
163
+		//make sure none of the old hooks are left hanging around
164
+		remove_all_actions('AHEE__EE_System__perform_activations_upgrades_and_migrations');
165
+		//we need to reset the migration manager in order for it to detect DMSs properly
166
+		EE_Data_Migration_Manager::reset();
167
+		self::instance()->detect_activations_or_upgrades();
168
+		self::instance()->activations_and_upgrades_manager->performActivationsAndUpgrades();
169
+		return self::instance();
170
+	}
171
+
172
+
173
+
174
+	/**
175
+	 * sets hooks for running rest of system
176
+	 * provides "AHEE__EE_System__construct__complete" hook for EE Addons to use as their starting point
177
+	 * starting EE Addons from any other point may lead to problems
178
+	 *
179
+	 * @param EE_Registry         $registry
180
+	 * @param LoaderInterface     $loader
181
+	 * @param EE_Maintenance_Mode $maintenance_mode
182
+	 */
183
+	private function __construct(
184
+		EE_Registry $registry,
185
+		LoaderInterface $loader,
186
+		EE_Maintenance_Mode $maintenance_mode
187
+	) {
188
+		$this->registry = $registry;
189
+		$this->loader = $loader;
190
+		$this->maintenance_mode = $maintenance_mode;
191
+		do_action('AHEE__EE_System__construct__begin', $this);
192
+		// allow addons to load first so that they can register autoloaders, set hooks for running DMS's, etc
193
+		add_action('AHEE__EE_Bootstrap__load_espresso_addons', array($this, 'load_espresso_addons'));
194
+		// when an ee addon is activated, we want to call the core hook(s) again
195
+		// because the newly-activated addon didn't get a chance to run at all
196
+		add_action('activate_plugin', array($this, 'load_espresso_addons'), 1);
197
+		// detect whether install or upgrade
198
+		add_action(
199
+			'AHEE__EE_Bootstrap__detect_activations_or_upgrades', array($this, 'detect_activations_or_upgrades'),
200
+			3
201
+		);
202
+		// load EE_Config, EE_Textdomain, etc
203
+		add_action('AHEE__EE_Bootstrap__load_core_configuration', array($this, 'load_core_configuration'), 5);
204
+		// load EE_Config, EE_Textdomain, etc
205
+		add_action(
206
+			'AHEE__EE_Bootstrap__register_shortcodes_modules_and_widgets',
207
+			array($this, 'register_shortcodes_modules_and_widgets'), 7
208
+		);
209
+		// you wanna get going? I wanna get going... let's get going!
210
+		add_action('AHEE__EE_Bootstrap__brew_espresso', array($this, 'brew_espresso'), 9);
211
+		//other housekeeping
212
+		//exclude EE critical pages from wp_list_pages
213
+		add_filter('wp_list_pages_excludes', array($this, 'remove_pages_from_wp_list_pages'), 10);
214
+		// ALL EE Addons should use the following hook point to attach their initial setup too
215
+		// it's extremely important for EE Addons to register any class autoloaders so that they can be available when the EE_Config loads
216
+		do_action('AHEE__EE_System__construct__complete', $this);
217
+	}
218
+
219
+
220
+
221
+	/**
222
+	 * Gets the ActivationHistory object for this addon
223
+	 *
224
+	 * @return ActivationHistory
225
+	 */
226
+	public function getActivationHistory()
227
+	{
228
+		return $this->activation_history;
229
+	}
230
+
231
+
232
+
233
+	/**
234
+	 * @param ActivationHistory $activation_history
235
+	 */
236
+	public function setActivationHistory(ActivationHistory $activation_history)
237
+	{
238
+		$this->activation_history = $activation_history;
239
+	}
240
+
241
+
242
+
243
+	/**
244
+	 * @return RequestType
245
+	 */
246
+	public function getRequestType()
247
+	{
248
+		return $this->request_type;
249
+	}
250
+
251
+
252
+
253
+	/**
254
+	 * @param RequestType $request_type
255
+	 */
256
+	public function setRequestType(RequestType $request_type)
257
+	{
258
+		$this->request_type = $request_type;
259
+	}
260
+
261
+	/**
262
+	 * load_espresso_addons
263
+	 * allow addons to load first so that they can set hooks for running DMS's, etc
264
+	 * this is hooked into both:
265
+	 *    'AHEE__EE_Bootstrap__load_core_configuration'
266
+	 *        which runs during the WP 'plugins_loaded' action at priority 5
267
+	 *    and the WP 'activate_plugin' hook point
268
+	 *
269
+	 * @return void
270
+	 * @throws EE_Error
271
+	 */
272
+	public function load_espresso_addons()
273
+	{
274
+		// set autoloaders for all of the classes implementing EEI_Plugin_API
275
+		// which provide helpers for EE plugin authors to more easily register certain components with EE.
276
+		EEH_Autoloader::instance()->register_autoloaders_for_each_file_in_folder(EE_LIBRARIES . 'plugin_api');
277
+		//caps need to be initialized on every request so that capability maps are set.
278
+		//@see https://events.codebasehq.com/projects/event-espresso/tickets/8674
279
+		$this->capabilities = $this->loader->getShared('EE_Capabilities');
280
+		$this->capabilities->init_caps();
281
+		do_action('AHEE__EE_System__load_espresso_addons');
282
+		//if the WP API basic auth plugin isn't already loaded, load it now.
283
+		//We want it for mobile apps. Just include the entire plugin
284
+		//also, don't load the basic auth when a plugin is getting activated, because
285
+		//it could be the basic auth plugin, and it doesn't check if its methods are already defined
286
+		//and causes a fatal error
287
+		if (
288
+			! (
289
+				isset($_GET['activate'])
290
+				&& $_GET['activate'] === 'true'
291
+			)
292
+			&& ! function_exists('json_basic_auth_handler')
293
+			&& ! function_exists('json_basic_auth_error')
294
+			&& ! (
295
+				isset($_GET['action'])
296
+				&& in_array($_GET['action'], array('activate', 'activate-selected'), true)
297
+			)
298
+		) {
299
+			include_once EE_THIRD_PARTY . 'wp-api-basic-auth' . DS . 'basic-auth.php';
300
+		}
301
+		do_action('AHEE__EE_System__load_espresso_addons__complete');
302
+	}
303
+
304
+
305
+
306
+	/**
307
+	 * detect_activations_or_upgrades
308
+	 * Checks for activation or upgrade of core first;
309
+	 * then also checks if any registered addons have been activated or upgraded
310
+	 * This is hooked into 'AHEE__EE_Bootstrap__detect_activations_or_upgrades'
311
+	 * which runs during the WP 'plugins_loaded' action at priority 3
312
+	 *
313
+	 * @return void
314
+	 * @throws DomainException
315
+	 * @throws InvalidArgumentException
316
+	 * @throws InvalidEntityException
317
+	 * @throws InvalidInterfaceException
318
+	 * @throws InvalidDataTypeException
319
+	 */
320
+	public function detect_activations_or_upgrades()
321
+	{
322
+		if(
323
+			(defined('DOING_AJAX') && DOING_AJAX)
324
+			|| (defined('REST_REQUEST') && REST_REQUEST)
325
+		) {
326
+			return;
327
+		}
328
+		$this->activations_and_upgrades_manager = ActivationsFactory::getActivationsAndUpgradesManager();
329
+		$this->activation_detected = $this->activations_and_upgrades_manager->detectActivationsAndVersionChanges(
330
+			array_merge(
331
+				array($this),
332
+				get_object_vars($this->registry->addons)
333
+			)
334
+		);
335
+	}
336
+
337
+
338
+
339
+	/**
340
+	 * load_core_configuration
341
+	 * this is hooked into 'AHEE__EE_Bootstrap__load_core_configuration'
342
+	 * which runs during the WP 'plugins_loaded' action at priority 5
343
+	 *
344
+	 * @return void
345
+	 * @throws ReflectionException
346
+	 */
347
+	public function load_core_configuration()
348
+	{
349
+		do_action('AHEE__EE_System__load_core_configuration__begin', $this);
350
+		$this->loader->getShared('EE_Load_Textdomain');
351
+		//load textdomain
352
+		EE_Load_Textdomain::load_textdomain();
353
+		// load and setup EE_Config and EE_Network_Config
354
+		$config = $this->loader->getShared('EE_Config');
355
+		$this->loader->getShared('EE_Network_Config');
356
+		// setup autoloaders
357
+		// enable logging?
358
+		if ($config->admin->use_full_logging) {
359
+			$this->loader->getShared('EE_Log');
360
+		}
361
+		// check for activation errors
362
+		$activation_errors = get_option('ee_plugin_activation_errors', false);
363
+		if ($activation_errors) {
364
+			EE_Error::add_error($activation_errors, __FILE__, __FUNCTION__, __LINE__);
365
+			update_option('ee_plugin_activation_errors', false);
366
+		}
367
+		// get model names
368
+		$this->_parse_model_names();
369
+		//load caf stuff a chance to play during the activation process too.
370
+		$this->_maybe_brew_regular();
371
+		do_action('AHEE__EE_System__load_core_configuration__complete', $this);
372
+	}
373
+
374
+
375
+
376
+	/**
377
+	 * cycles through all of the models/*.model.php files, and assembles an array of model names
378
+	 *
379
+	 * @return void
380
+	 * @throws ReflectionException
381
+	 */
382
+	private function _parse_model_names()
383
+	{
384
+		//get all the files in the EE_MODELS folder that end in .model.php
385
+		$models = glob(EE_MODELS . '*.model.php');
386
+		$model_names = array();
387
+		$non_abstract_db_models = array();
388
+		foreach ($models as $model) {
389
+			// get model classname
390
+			$classname = EEH_File::get_classname_from_filepath_with_standard_filename($model);
391
+			$short_name = str_replace('EEM_', '', $classname);
392
+			$reflectionClass = new ReflectionClass($classname);
393
+			if ($reflectionClass->isSubclassOf('EEM_Base') && ! $reflectionClass->isAbstract()) {
394
+				$non_abstract_db_models[$short_name] = $classname;
395
+			}
396
+			$model_names[$short_name] = $classname;
397
+		}
398
+		$this->registry->models = apply_filters('FHEE__EE_System__parse_model_names', $model_names);
399
+		$this->registry->non_abstract_db_models = apply_filters(
400
+			'FHEE__EE_System__parse_implemented_model_names',
401
+			$non_abstract_db_models
402
+		);
403
+	}
404
+
405
+
406
+
407
+	/**
408
+	 * The purpose of this method is to simply check for a file named "caffeinated/brewing_regular.php" for any hooks
409
+	 * that need to be setup before our EE_System launches.
410
+	 *
411
+	 * @return void
412
+	 */
413
+	private function _maybe_brew_regular()
414
+	{
415
+		if (
416
+			! $this->activation_detected
417
+			&& (! defined('EE_DECAF') || EE_DECAF !== true)
418
+			&& is_readable(EE_CAFF_PATH . 'brewing_regular.php')
419
+		) {
420
+			require_once EE_CAFF_PATH . 'brewing_regular.php';
421
+		}
422
+	}
423
+
424
+
425
+
426
+	/**
427
+	 * register_shortcodes_modules_and_widgets
428
+	 * generate lists of shortcodes and modules, then verify paths and classes
429
+	 * This is hooked into 'AHEE__EE_Bootstrap__register_shortcodes_modules_and_widgets'
430
+	 * which runs during the WP 'plugins_loaded' action at priority 7
431
+	 *
432
+	 * @access public
433
+	 * @return void
434
+	 * @throws Exception
435
+	 */
436
+	public function register_shortcodes_modules_and_widgets()
437
+	{
438
+		if ($this->activation_detected) {
439
+			return;
440
+		}
441
+		// check for addons using old hook point
442
+		if (has_action('AHEE__EE_System__register_shortcodes_modules_and_addons')) {
443
+			$this->_incompatible_addon_error();
444
+		}
445
+		do_action('AHEE__EE_System__register_shortcodes_modules_and_widgets');
446
+		try {
447
+			// load, register, and add shortcodes the new way
448
+			new ShortcodesManager(
449
+			// and the old way, but we'll put it under control of the new system
450
+				EE_Config::getLegacyShortcodesManager()
451
+			);
452
+		} catch (Exception $exception) {
453
+			new ExceptionStackTraceDisplay($exception);
454
+		}
455
+	}
456
+
457
+
458
+
459
+	/**
460
+	 * _incompatible_addon_error
461
+	 *
462
+	 * @access public
463
+	 * @return void
464
+	 */
465
+	private function _incompatible_addon_error()
466
+	{
467
+		// get array of classes hooking into here
468
+		$class_names = EEH_Class_Tools::get_class_names_for_all_callbacks_on_hook(
469
+			'AHEE__EE_System__register_shortcodes_modules_and_addons'
470
+		);
471
+		if (! empty($class_names)) {
472
+			$msg = __(
473
+				'The following plugins, addons, or modules appear to be incompatible with this version of Event Espresso and were automatically deactivated to avoid fatal errors:',
474
+				'event_espresso'
475
+			);
476
+			$msg .= '<ul>';
477
+			foreach ($class_names as $class_name) {
478
+				$msg .= '<li><b>Event Espresso - ' . str_replace(
479
+						array('EE_', 'EEM_', 'EED_', 'EES_', 'EEW_'), '',
480
+						$class_name
481
+					) . '</b></li>';
482
+			}
483
+			$msg .= '</ul>';
484
+			$msg .= __(
485
+				'Compatibility issues can be avoided and/or resolved by keeping addons and plugins updated to the latest version.',
486
+				'event_espresso'
487
+			);
488
+			// save list of incompatible addons to wp-options for later use
489
+			add_option('ee_incompatible_addons', $class_names, '', 'no');
490
+			if (is_admin()) {
491
+				EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
492
+			}
493
+		}
494
+	}
495
+
496
+
497
+
498
+	/**
499
+	 * brew_espresso
500
+	 * begins the process of setting hooks for initializing EE in the correct order
501
+	 * This is happening on the 'AHEE__EE_Bootstrap__brew_espresso' hook point
502
+	 * which runs during the WP 'plugins_loaded' action at priority 9
503
+	 *
504
+	 * @return void
505
+	 */
506
+	public function brew_espresso()
507
+	{
508
+		if ($this->activation_detected) {
509
+			add_action('init', array($this, 'perform_activations_upgrades_and_migrations'), 3);
510
+			return;
511
+		}
512
+		do_action('AHEE__EE_System__brew_espresso__begin', $this);
513
+		// load some final core systems
514
+		add_action('init', array($this, 'set_hooks_for_core'), 1);
515
+		add_action('init', array($this, 'load_CPTs_and_session'), 5);
516
+		add_action('init', array($this, 'load_controllers'), 7);
517
+		add_action('init', array($this, 'core_loaded_and_ready'), 9);
518
+		add_action('init', array($this, 'initialize'), 10);
519
+		add_action('init', array($this, 'initialize_last'), 100);
520
+		if (is_admin() && apply_filters('FHEE__EE_System__brew_espresso__load_pue', true)) {
521
+			// pew pew pew
522
+			$this->loader->getShared('EE_PUE');
523
+			do_action('AHEE__EE_System__brew_espresso__after_pue_init');
524
+		}
525
+		do_action('AHEE__EE_System__brew_espresso__complete', $this);
526
+	}
527
+
528
+
529
+
530
+	/**
531
+	 *    set_hooks_for_core
532
+	 *
533
+	 * @access public
534
+	 * @return    void
535
+	 */
536
+	public function set_hooks_for_core()
537
+	{
538
+		do_action('AHEE__EE_System__set_hooks_for_core');
539
+	}
540
+
541
+
542
+
543
+	/**
544
+	 *    perform_activations_upgrades_and_migrations
545
+	 *
546
+	 * @access public
547
+	 * @return    void
548
+	 */
549
+	public function perform_activations_upgrades_and_migrations()
550
+	{
551
+		do_action('AHEE__EE_System__perform_activations_upgrades_and_migrations');
552
+	}
553
+
554
+
555
+
556
+	/**
557
+	 *    load_CPTs_and_session
558
+	 *
559
+	 * @access public
560
+	 * @return    void
561
+	 */
562
+	public function load_CPTs_and_session()
563
+	{
564
+		do_action('AHEE__EE_System__load_CPTs_and_session__start');
565
+		// register Custom Post Types
566
+		$this->loader->getShared('EE_Register_CPTs');
567
+		do_action('AHEE__EE_System__load_CPTs_and_session__complete');
568
+	}
569
+
570
+
571
+
572
+	/**
573
+	 * load_controllers
574
+	 * this is the best place to load any additional controllers that needs access to EE core.
575
+	 * it is expected that all basic core EE systems, that are not dependant on the current request are loaded at this
576
+	 * time
577
+	 *
578
+	 * @access public
579
+	 * @return void
580
+	 */
581
+	public function load_controllers()
582
+	{
583
+		do_action('AHEE__EE_System__load_controllers__start');
584
+		// let's get it started
585
+		if (! is_admin() && ! $this->maintenance_mode->level()) {
586
+			do_action('AHEE__EE_System__load_controllers__load_front_controllers');
587
+			$this->loader->getShared('EE_Front_Controller');
588
+		} else if (! EE_FRONT_AJAX) {
589
+			do_action('AHEE__EE_System__load_controllers__load_admin_controllers');
590
+			$this->loader->getShared('EE_Admin');
591
+		}
592
+		do_action('AHEE__EE_System__load_controllers__complete');
593
+	}
594
+
595
+
596
+
597
+	/**
598
+	 * core_loaded_and_ready
599
+	 * all of the basic EE core should be loaded at this point and available regardless of M-Mode
600
+	 *
601
+	 * @access public
602
+	 * @return void
603
+	 */
604
+	public function core_loaded_and_ready()
605
+	{
606
+		$this->loader->getShared('EE_Session');
607
+		do_action('AHEE__EE_System__core_loaded_and_ready');
608
+		// load_espresso_template_tags
609
+		if (is_readable(EE_PUBLIC . 'template_tags.php')) {
610
+			require_once(EE_PUBLIC . 'template_tags.php');
611
+		}
612
+		do_action('AHEE__EE_System__set_hooks_for_shortcodes_modules_and_addons');
613
+		$this->loader->getShared('EventEspresso\core\services\assets\Registry');
614
+	}
615
+
616
+
617
+
618
+	/**
619
+	 * initialize
620
+	 * this is the best place to begin initializing client code
621
+	 *
622
+	 * @access public
623
+	 * @return void
624
+	 */
625
+	public function initialize()
626
+	{
627
+		do_action('AHEE__EE_System__initialize');
628
+	}
629
+
630
+
631
+
632
+	/**
633
+	 * initialize_last
634
+	 * this is run really late during the WP init hook point, and ensures that mostly everything else that needs to
635
+	 * initialize has done so
636
+	 *
637
+	 * @access public
638
+	 * @return void
639
+	 */
640
+	public function initialize_last()
641
+	{
642
+		do_action('AHEE__EE_System__initialize_last');
643
+		add_action('admin_bar_init', array($this, 'addEspressoToolbar'));
644
+	}
645
+
646
+
647
+
648
+	/**
649
+	 * @return void
650
+	 * @throws EE_Error
651
+	 */
652
+	public function addEspressoToolbar()
653
+	{
654
+		$this->registry->create(
655
+			'EventEspresso\core\domain\services\admin\AdminToolBar',
656
+			array($this->registry->CAP)
657
+		);
658
+	}
659
+
660
+
661
+
662
+	/**
663
+	 * do_not_cache
664
+	 * sets no cache headers and defines no cache constants for WP plugins
665
+	 *
666
+	 * @access public
667
+	 * @return void
668
+	 */
669
+	public static function do_not_cache()
670
+	{
671
+		// set no cache constants
672
+		if (! defined('DONOTCACHEPAGE')) {
673
+			define('DONOTCACHEPAGE', true);
674
+		}
675
+		if (! defined('DONOTCACHCEOBJECT')) {
676
+			define('DONOTCACHCEOBJECT', true);
677
+		}
678
+		if (! defined('DONOTCACHEDB')) {
679
+			define('DONOTCACHEDB', true);
680
+		}
681
+		// add no cache headers
682
+		add_action('send_headers', array('EE_System', 'nocache_headers'), 10);
683
+		// plus a little extra for nginx and Google Chrome
684
+		add_filter('nocache_headers', array('EE_System', 'extra_nocache_headers'), 10, 1);
685
+		// prevent browsers from prefetching of the rel='next' link, because it may contain content that interferes with the registration process
686
+		remove_action('wp_head', 'adjacent_posts_rel_link_wp_head');
687
+	}
688
+
689
+
690
+
691
+	/**
692
+	 *    extra_nocache_headers
693
+	 *
694
+	 * @access    public
695
+	 * @param $headers
696
+	 * @return    array
697
+	 */
698
+	public static function extra_nocache_headers($headers)
699
+	{
700
+		// for NGINX
701
+		$headers['X-Accel-Expires'] = 0;
702
+		// plus extra for Google Chrome since it doesn't seem to respect "no-cache", but WILL respect "no-store"
703
+		$headers['Cache-Control'] = 'no-store, no-cache, must-revalidate, max-age=0';
704
+		return $headers;
705
+	}
706
+
707
+
708
+
709
+	/**
710
+	 *    nocache_headers
711
+	 *
712
+	 * @access    public
713
+	 * @return    void
714
+	 */
715
+	public static function nocache_headers()
716
+	{
717
+		nocache_headers();
718
+	}
719
+
720
+
721
+
722
+
723
+	/**
724
+	 * simply hooks into "wp_list_pages_exclude" filter (for wp_list_pages method) and makes sure EE critical pages are
725
+	 * never returned with the function.
726
+	 *
727
+	 * @param  array $exclude_array any existing pages being excluded are in this array.
728
+	 * @return array
729
+	 */
730
+	public function remove_pages_from_wp_list_pages($exclude_array)
731
+	{
732
+		return array_merge($exclude_array, $this->registry->CFG->core->get_critical_pages_array());
733
+	}
734
+
735
+
736
+
737
+	/******************************** DEPRECATED ***************************************/
738
+
739
+
740
+
741
+	/**
742
+	 * @deprecated 4.9.40
743
+	 * @return void
744
+	 */
745
+	public function detect_if_activation_or_upgrade()
746
+	{
747
+	}
748
+
749
+
750
+
751
+	/**
752
+	 * @deprecated 4.9.40
753
+	 * @return void
754
+	 */
755
+	public function update_list_of_installed_versions($version_history = null, $current_version_to_add = null)
756
+	{
757
+	}
758
+
759
+
760
+
761
+	/**
762
+	 * @deprecated 4.9.40
763
+	 * @param null $espresso_db_update
764
+	 * @return int one of the constants on EE_System::req_type_
765
+	 */
766
+	public function detect_req_type($espresso_db_update = null)
767
+	{
768
+		return $this->getRequestType()->getRequestType();
769
+	}
770
+
771
+
772
+
773
+	/**
774
+	 * @deprecated 4.9.40
775
+	 * @return bool
776
+	 */
777
+	public function is_major_version_change()
778
+	{
779
+		return $this->getRequestType()->isMajorVersionChange();
780
+	}
781 781
 
782 782
 
783 783
 
784
-    /**
785
-     * @deprecated 4.9.40
786
-     * @param array  $activation_history_for_addon
787
-     * @param string $activation_indicator_option_name
788
-     * @param string $version_to_upgrade_to
789
-     * @return int one of the constants on EE_System::req_type_*
790
-     */
791
-    public static function detect_req_type_given_activation_history(
792
-        $activation_history_for_addon,
793
-        $activation_indicator_option_name,
794
-        $version_to_upgrade_to
795
-    ) {
796
-        return EE_System::instance()->getRequestType()->getRequestType();
797
-    }
784
+	/**
785
+	 * @deprecated 4.9.40
786
+	 * @param array  $activation_history_for_addon
787
+	 * @param string $activation_indicator_option_name
788
+	 * @param string $version_to_upgrade_to
789
+	 * @return int one of the constants on EE_System::req_type_*
790
+	 */
791
+	public static function detect_req_type_given_activation_history(
792
+		$activation_history_for_addon,
793
+		$activation_indicator_option_name,
794
+		$version_to_upgrade_to
795
+	) {
796
+		return EE_System::instance()->getRequestType()->getRequestType();
797
+	}
798 798
 
799 799
 
800 800
 
801
-    /**
802
-     * @deprecated 4.9.40
803
-     * @param boolean $initialize_addons_too
804
-     * @param boolean $verify_schema
805
-     * @return void
806
-     * @throws EE_Error
807
-     */
808
-    public function initialize_db_if_no_migrations_required($initialize_addons_too = false, $verify_schema = true)
809
-    {
810
-    }
801
+	/**
802
+	 * @deprecated 4.9.40
803
+	 * @param boolean $initialize_addons_too
804
+	 * @param boolean $verify_schema
805
+	 * @return void
806
+	 * @throws EE_Error
807
+	 */
808
+	public function initialize_db_if_no_migrations_required($initialize_addons_too = false, $verify_schema = true)
809
+	{
810
+	}
811 811
 
812 812
 
813 813
 
814
-    /**
815
-     * @deprecated 4.9.40
816
-     * @throws EE_Error
817
-     */
818
-    public function initialize_addons()
819
-    {
820
-    }
814
+	/**
815
+	 * @deprecated 4.9.40
816
+	 * @throws EE_Error
817
+	 */
818
+	public function initialize_addons()
819
+	{
820
+	}
821 821
 
822 822
 
823 823
 
824
-    /**
825
-     * @deprecated 4.9.40
826
-     * @return void
827
-     */
828
-    public function redirect_to_about_ee()
829
-    {
830
-    }
824
+	/**
825
+	 * @deprecated 4.9.40
826
+	 * @return void
827
+	 */
828
+	public function redirect_to_about_ee()
829
+	{
830
+	}
831 831
 
832 832
 
833 833
 }
Please login to merge, or discard this patch.
core/request_stack/EE_Request.core.php 1 patch
Indentation   +226 added lines, -226 removed lines patch added patch discarded remove patch
@@ -16,232 +16,232 @@
 block discarded – undo
16 16
 class EE_Request implements InterminableInterface
17 17
 {
18 18
 
19
-    /**
20
-     *  $_GET parameters
21
-     *
22
-     * @var array $_get
23
-     */
24
-    private $_get;
25
-
26
-    /**
27
-     * $_POST parameters
28
-     *
29
-     * @var array $_post
30
-     */
31
-    private $_post;
32
-
33
-    /**
34
-     * $_COOKIE parameters
35
-     *
36
-     * @var array $_cookie
37
-     */
38
-    private $_cookie;
39
-
40
-    /**
41
-     * $_REQUEST parameters
42
-     *
43
-     * @var array $_params
44
-     */
45
-    private $_params;
46
-
47
-    /**
48
-     * whether current request is via AJAX
49
-     *
50
-     * @var boolean $ajax
51
-     */
52
-    public $ajax;
53
-
54
-    /**
55
-     * whether current request is via AJAX from the frontend of the site
56
-     *
57
-     * @var boolean $front_ajax
58
-     */
59
-    public $front_ajax;
60
-
61
-    /**
62
-     * IP address for request
63
-     *
64
-     * @var string $_ip_address
65
-     */
66
-    private $_ip_address;
67
-
68
-
69
-    /**
70
-     * class constructor
71
-     *
72
-     * @access    public
73
-     * @param array $get
74
-     * @param array $post
75
-     * @param array $cookie
76
-     */
77
-    public function __construct($get, $post, $cookie)
78
-    {
79
-        // grab request vars
80
-        $this->_get = (array)$get;
81
-        $this->_post = (array)$post;
82
-        $this->_cookie = (array)$cookie;
83
-        $this->_params = array_merge($this->_get, $this->_post);
84
-        // AJAX ???
85
-        $this->ajax = defined('DOING_AJAX') && DOING_AJAX;
86
-        $this->front_ajax = $this->is_set('ee_front_ajax') && (int)$this->get('ee_front_ajax') === 1;
87
-        // grab user IP
88
-        $this->_ip_address = $this->_visitor_ip();
89
-    }
90
-
91
-
92
-
93
-    /**
94
-     * @return array
95
-     */
96
-    public function get_params()
97
-    {
98
-        return $this->_get;
99
-    }
100
-
101
-
102
-
103
-    /**
104
-     * @return array
105
-     */
106
-    public function post_params()
107
-    {
108
-        return $this->_post;
109
-    }
110
-
111
-
112
-
113
-    /**
114
-     * @return array
115
-     */
116
-    public function cookie_params()
117
-    {
118
-        return $this->_cookie;
119
-    }
120
-
121
-
122
-
123
-    /**
124
-     * returns contents of $_REQUEST
125
-     *
126
-     * @return array
127
-     */
128
-    public function params()
129
-    {
130
-        return $this->_params;
131
-    }
132
-
133
-
134
-
135
-    /**
136
-     *    setter
137
-     *
138
-     * @access    public
139
-     * @param      $key
140
-     * @param      $value
141
-     * @param bool $override_ee
142
-     * @return    void
143
-     */
144
-    public function set($key, $value, $override_ee = false)
145
-    {
146
-        // don't allow "ee" to be overwritten unless explicitly instructed to do so
147
-        if (
148
-            $key !== 'ee'
149
-            || ($key === 'ee' && empty($this->_params['ee']))
150
-            || ($key === 'ee' && ! empty($this->_params['ee']) && $override_ee)
151
-        ) {
152
-            $this->_params[$key] = $value;
153
-        }
154
-    }
155
-
156
-
157
-
158
-    /**
159
-     *    getter
160
-     *
161
-     * @access    public
162
-     * @param      $key
163
-     * @param null $default
164
-     * @return    mixed
165
-     */
166
-    public function get($key, $default = null)
167
-    {
168
-        return isset($this->_params[$key]) ? $this->_params[$key] : $default;
169
-    }
170
-
171
-
172
-
173
-    /**
174
-     *    check if param exists
175
-     *
176
-     * @access    public
177
-     * @param $key
178
-     * @return    boolean
179
-     */
180
-    public function is_set($key)
181
-    {
182
-        return isset($this->_params[$key]) ? true : false;
183
-    }
184
-
185
-
186
-
187
-    /**
188
-     *    remove param
189
-     *
190
-     * @access    public
191
-     * @param      $key
192
-     * @param bool $unset_from_global_too
193
-     */
194
-    public function un_set($key, $unset_from_global_too = false)
195
-    {
196
-        unset($this->_params[$key]);
197
-        if ($unset_from_global_too) {
198
-            unset($_REQUEST[$key]);
199
-        }
200
-    }
201
-
202
-
203
-
204
-    /**
205
-     * @return string
206
-     */
207
-    public function ip_address()
208
-    {
209
-        return $this->_ip_address;
210
-    }
211
-
212
-
213
-
214
-    /**
215
-     * _visitor_ip
216
-     *    attempt to get IP address of current visitor from server
217
-     * plz see: http://stackoverflow.com/a/2031935/1475279
218
-     *
219
-     * @access public
220
-     * @return string
221
-     */
222
-    private function _visitor_ip()
223
-    {
224
-        $visitor_ip = '0.0.0.0';
225
-        $server_keys = array(
226
-            'HTTP_CLIENT_IP',
227
-            'HTTP_X_FORWARDED_FOR',
228
-            'HTTP_X_FORWARDED',
229
-            'HTTP_X_CLUSTER_CLIENT_IP',
230
-            'HTTP_FORWARDED_FOR',
231
-            'HTTP_FORWARDED',
232
-            'REMOTE_ADDR',
233
-        );
234
-        foreach ($server_keys as $key) {
235
-            if (isset($_SERVER[$key])) {
236
-                foreach (array_map('trim', explode(',', $_SERVER[$key])) as $ip) {
237
-                    if ($ip === '127.0.0.1' || filter_var($ip, FILTER_VALIDATE_IP) !== false) {
238
-                        $visitor_ip = $ip;
239
-                    }
240
-                }
241
-            }
242
-        }
243
-        return $visitor_ip;
244
-    }
19
+	/**
20
+	 *  $_GET parameters
21
+	 *
22
+	 * @var array $_get
23
+	 */
24
+	private $_get;
25
+
26
+	/**
27
+	 * $_POST parameters
28
+	 *
29
+	 * @var array $_post
30
+	 */
31
+	private $_post;
32
+
33
+	/**
34
+	 * $_COOKIE parameters
35
+	 *
36
+	 * @var array $_cookie
37
+	 */
38
+	private $_cookie;
39
+
40
+	/**
41
+	 * $_REQUEST parameters
42
+	 *
43
+	 * @var array $_params
44
+	 */
45
+	private $_params;
46
+
47
+	/**
48
+	 * whether current request is via AJAX
49
+	 *
50
+	 * @var boolean $ajax
51
+	 */
52
+	public $ajax;
53
+
54
+	/**
55
+	 * whether current request is via AJAX from the frontend of the site
56
+	 *
57
+	 * @var boolean $front_ajax
58
+	 */
59
+	public $front_ajax;
60
+
61
+	/**
62
+	 * IP address for request
63
+	 *
64
+	 * @var string $_ip_address
65
+	 */
66
+	private $_ip_address;
67
+
68
+
69
+	/**
70
+	 * class constructor
71
+	 *
72
+	 * @access    public
73
+	 * @param array $get
74
+	 * @param array $post
75
+	 * @param array $cookie
76
+	 */
77
+	public function __construct($get, $post, $cookie)
78
+	{
79
+		// grab request vars
80
+		$this->_get = (array)$get;
81
+		$this->_post = (array)$post;
82
+		$this->_cookie = (array)$cookie;
83
+		$this->_params = array_merge($this->_get, $this->_post);
84
+		// AJAX ???
85
+		$this->ajax = defined('DOING_AJAX') && DOING_AJAX;
86
+		$this->front_ajax = $this->is_set('ee_front_ajax') && (int)$this->get('ee_front_ajax') === 1;
87
+		// grab user IP
88
+		$this->_ip_address = $this->_visitor_ip();
89
+	}
90
+
91
+
92
+
93
+	/**
94
+	 * @return array
95
+	 */
96
+	public function get_params()
97
+	{
98
+		return $this->_get;
99
+	}
100
+
101
+
102
+
103
+	/**
104
+	 * @return array
105
+	 */
106
+	public function post_params()
107
+	{
108
+		return $this->_post;
109
+	}
110
+
111
+
112
+
113
+	/**
114
+	 * @return array
115
+	 */
116
+	public function cookie_params()
117
+	{
118
+		return $this->_cookie;
119
+	}
120
+
121
+
122
+
123
+	/**
124
+	 * returns contents of $_REQUEST
125
+	 *
126
+	 * @return array
127
+	 */
128
+	public function params()
129
+	{
130
+		return $this->_params;
131
+	}
132
+
133
+
134
+
135
+	/**
136
+	 *    setter
137
+	 *
138
+	 * @access    public
139
+	 * @param      $key
140
+	 * @param      $value
141
+	 * @param bool $override_ee
142
+	 * @return    void
143
+	 */
144
+	public function set($key, $value, $override_ee = false)
145
+	{
146
+		// don't allow "ee" to be overwritten unless explicitly instructed to do so
147
+		if (
148
+			$key !== 'ee'
149
+			|| ($key === 'ee' && empty($this->_params['ee']))
150
+			|| ($key === 'ee' && ! empty($this->_params['ee']) && $override_ee)
151
+		) {
152
+			$this->_params[$key] = $value;
153
+		}
154
+	}
155
+
156
+
157
+
158
+	/**
159
+	 *    getter
160
+	 *
161
+	 * @access    public
162
+	 * @param      $key
163
+	 * @param null $default
164
+	 * @return    mixed
165
+	 */
166
+	public function get($key, $default = null)
167
+	{
168
+		return isset($this->_params[$key]) ? $this->_params[$key] : $default;
169
+	}
170
+
171
+
172
+
173
+	/**
174
+	 *    check if param exists
175
+	 *
176
+	 * @access    public
177
+	 * @param $key
178
+	 * @return    boolean
179
+	 */
180
+	public function is_set($key)
181
+	{
182
+		return isset($this->_params[$key]) ? true : false;
183
+	}
184
+
185
+
186
+
187
+	/**
188
+	 *    remove param
189
+	 *
190
+	 * @access    public
191
+	 * @param      $key
192
+	 * @param bool $unset_from_global_too
193
+	 */
194
+	public function un_set($key, $unset_from_global_too = false)
195
+	{
196
+		unset($this->_params[$key]);
197
+		if ($unset_from_global_too) {
198
+			unset($_REQUEST[$key]);
199
+		}
200
+	}
201
+
202
+
203
+
204
+	/**
205
+	 * @return string
206
+	 */
207
+	public function ip_address()
208
+	{
209
+		return $this->_ip_address;
210
+	}
211
+
212
+
213
+
214
+	/**
215
+	 * _visitor_ip
216
+	 *    attempt to get IP address of current visitor from server
217
+	 * plz see: http://stackoverflow.com/a/2031935/1475279
218
+	 *
219
+	 * @access public
220
+	 * @return string
221
+	 */
222
+	private function _visitor_ip()
223
+	{
224
+		$visitor_ip = '0.0.0.0';
225
+		$server_keys = array(
226
+			'HTTP_CLIENT_IP',
227
+			'HTTP_X_FORWARDED_FOR',
228
+			'HTTP_X_FORWARDED',
229
+			'HTTP_X_CLUSTER_CLIENT_IP',
230
+			'HTTP_FORWARDED_FOR',
231
+			'HTTP_FORWARDED',
232
+			'REMOTE_ADDR',
233
+		);
234
+		foreach ($server_keys as $key) {
235
+			if (isset($_SERVER[$key])) {
236
+				foreach (array_map('trim', explode(',', $_SERVER[$key])) as $ip) {
237
+					if ($ip === '127.0.0.1' || filter_var($ip, FILTER_VALIDATE_IP) !== false) {
238
+						$visitor_ip = $ip;
239
+					}
240
+				}
241
+			}
242
+		}
243
+		return $visitor_ip;
244
+	}
245 245
 
246 246
 
247 247
 
Please login to merge, or discard this patch.
core/helpers/EEH_Activation.helper.php 1 patch
Indentation   +1655 added lines, -1655 removed lines patch added patch discarded remove patch
@@ -2,7 +2,7 @@  discard block
 block discarded – undo
2 2
 use EventEspresso\core\interfaces\ResettableInterface;
3 3
 
4 4
 if ( ! defined('EVENT_ESPRESSO_VERSION')) {
5
-    exit('No direct script access allowed');
5
+	exit('No direct script access allowed');
6 6
 }
7 7
 
8 8
 
@@ -17,244 +17,244 @@  discard block
 block discarded – undo
17 17
 class EEH_Activation implements ResettableInterface
18 18
 {
19 19
 
20
-    /**
21
-     * constant used to indicate a cron task is no longer in use
22
-     */
23
-    const cron_task_no_longer_in_use = 'no_longer_in_use';
24
-
25
-    /**
26
-     * option name that will indicate whether or not we still
27
-     * need to create EE's folders in the uploads directory
28
-     * (because if EE was installed without file system access,
29
-     * we need to request credentials before we can create them)
30
-     */
31
-    const upload_directories_incomplete_option_name = 'ee_upload_directories_incomplete';
32
-
33
-    /**
34
-     * WP_User->ID
35
-     *
36
-     * @var int
37
-     */
38
-    private static $_default_creator_id;
39
-
40
-    /**
41
-     * indicates whether or not we've already verified core's default data during this request,
42
-     * because after migrations are done, any addons activated while in maintenance mode
43
-     * will want to setup their own default data, and they might hook into core's default data
44
-     * and trigger core to setup its default data. In which case they might all ask for core to init its default data.
45
-     * This prevents doing that for EVERY single addon.
46
-     *
47
-     * @var boolean
48
-     */
49
-    protected static $_initialized_db_content_already_in_this_request = false;
50
-
51
-    /**
52
-     * @var \EventEspresso\core\services\database\TableAnalysis $table_analysis
53
-     */
54
-    private static $table_analysis;
55
-
56
-    /**
57
-     * @var \EventEspresso\core\services\database\TableManager $table_manager
58
-     */
59
-    private static $table_manager;
60
-
61
-
62
-    /**
63
-     * @return \EventEspresso\core\services\database\TableAnalysis
64
-     */
65
-    public static function getTableAnalysis()
66
-    {
67
-        if (! self::$table_analysis instanceof \EventEspresso\core\services\database\TableAnalysis) {
68
-            self::$table_analysis = EE_Registry::instance()->create('TableAnalysis', array(), true);
69
-        }
70
-        return self::$table_analysis;
71
-    }
72
-
73
-
74
-    /**
75
-     * @return \EventEspresso\core\services\database\TableManager
76
-     */
77
-    public static function getTableManager()
78
-    {
79
-        if (! self::$table_manager instanceof \EventEspresso\core\services\database\TableManager) {
80
-            self::$table_manager = EE_Registry::instance()->create('TableManager', array(), true);
81
-        }
82
-        return self::$table_manager;
83
-    }
84
-
85
-
86
-    /**
87
-     *    _ensure_table_name_has_prefix
88
-     *
89
-     * @deprecated instead use TableAnalysis::ensureTableNameHasPrefix()
90
-     * @access     public
91
-     * @static
92
-     * @param $table_name
93
-     * @return string
94
-     */
95
-    public static function ensure_table_name_has_prefix($table_name)
96
-    {
97
-        return \EEH_Activation::getTableAnalysis()->ensureTableNameHasPrefix($table_name);
98
-    }
99
-
100
-
101
-    /**
102
-     *    system_initialization
103
-     *    ensures the EE configuration settings are loaded with at least default options set
104
-     *    and that all critical EE pages have been generated with the appropriate shortcodes in place
105
-     *
106
-     * @access public
107
-     * @static
108
-     * @return void
109
-     */
110
-    public static function system_initialization()
111
-    {
112
-        EEH_Activation::reset_and_update_config();
113
-        //which is fired BEFORE activation of plugin anyways
114
-        EEH_Activation::verify_default_pages_exist();
115
-    }
116
-
117
-
118
-    /**
119
-     * Sets the database schema and creates folders. This should
120
-     * be called on plugin activation and reactivation
121
-     *
122
-     * @return boolean success, whether the database and folders are setup properly
123
-     * @throws \EE_Error
124
-     */
125
-    public static function initialize_db_and_folders()
126
-    {
127
-        $good_filesystem = EEH_Activation::create_upload_directories();
128
-        $good_db         = EEH_Activation::create_database_tables();
129
-        return $good_filesystem && $good_db;
130
-    }
131
-
132
-
133
-    /**
134
-     * assuming we have an up-to-date database schema, this will populate it
135
-     * with default and initial data. This should be called
136
-     * upon activation of a new plugin, reactivation, and at the end
137
-     * of running migration scripts
138
-     *
139
-     * @throws \EE_Error
140
-     */
141
-    public static function initialize_db_content()
142
-    {
143
-        //let's avoid doing all this logic repeatedly, especially when addons are requesting it
144
-        if (EEH_Activation::$_initialized_db_content_already_in_this_request) {
145
-            return;
146
-        }
147
-        EEH_Activation::$_initialized_db_content_already_in_this_request = true;
148
-
149
-        EEH_Activation::initialize_system_questions();
150
-        EEH_Activation::insert_default_status_codes();
151
-        EEH_Activation::generate_default_message_templates();
152
-        EEH_Activation::create_no_ticket_prices_array();
153
-        EE_Registry::instance()->CAP->init_caps();
154
-
155
-        EEH_Activation::validate_messages_system();
156
-        EEH_Activation::insert_default_payment_methods();
157
-        //in case we've
158
-        EEH_Activation::remove_cron_tasks();
159
-        EEH_Activation::create_cron_tasks();
160
-        // remove all TXN locks since that is being done via extra meta now
161
-        delete_option('ee_locked_transactions');
162
-        //also, check for CAF default db content
163
-        do_action('AHEE__EEH_Activation__initialize_db_content');
164
-        //also: EEM_Gateways::load_all_gateways() outputs a lot of success messages
165
-        //which users really won't care about on initial activation
166
-        EE_Error::overwrite_success();
167
-    }
168
-
169
-
170
-    /**
171
-     * Returns an array of cron tasks. Array values are the actions fired by the cron tasks (the "hooks"),
172
-     * values are the frequency (the "recurrence"). See http://codex.wordpress.org/Function_Reference/wp_schedule_event
173
-     * If the cron task should NO longer be used, it should have a value of EEH_Activation::cron_task_no_longer_in_use
174
-     * (null)
175
-     *
176
-     * @param string $which_to_include can be 'current' (ones that are currently in use),
177
-     *                                 'old' (only returns ones that should no longer be used),or 'all',
178
-     * @return array
179
-     * @throws \EE_Error
180
-     */
181
-    public static function get_cron_tasks($which_to_include)
182
-    {
183
-        $cron_tasks = apply_filters(
184
-            'FHEE__EEH_Activation__get_cron_tasks',
185
-            array(
186
-                'AHEE__EE_Cron_Tasks__clean_up_junk_transactions'      => 'hourly',
20
+	/**
21
+	 * constant used to indicate a cron task is no longer in use
22
+	 */
23
+	const cron_task_no_longer_in_use = 'no_longer_in_use';
24
+
25
+	/**
26
+	 * option name that will indicate whether or not we still
27
+	 * need to create EE's folders in the uploads directory
28
+	 * (because if EE was installed without file system access,
29
+	 * we need to request credentials before we can create them)
30
+	 */
31
+	const upload_directories_incomplete_option_name = 'ee_upload_directories_incomplete';
32
+
33
+	/**
34
+	 * WP_User->ID
35
+	 *
36
+	 * @var int
37
+	 */
38
+	private static $_default_creator_id;
39
+
40
+	/**
41
+	 * indicates whether or not we've already verified core's default data during this request,
42
+	 * because after migrations are done, any addons activated while in maintenance mode
43
+	 * will want to setup their own default data, and they might hook into core's default data
44
+	 * and trigger core to setup its default data. In which case they might all ask for core to init its default data.
45
+	 * This prevents doing that for EVERY single addon.
46
+	 *
47
+	 * @var boolean
48
+	 */
49
+	protected static $_initialized_db_content_already_in_this_request = false;
50
+
51
+	/**
52
+	 * @var \EventEspresso\core\services\database\TableAnalysis $table_analysis
53
+	 */
54
+	private static $table_analysis;
55
+
56
+	/**
57
+	 * @var \EventEspresso\core\services\database\TableManager $table_manager
58
+	 */
59
+	private static $table_manager;
60
+
61
+
62
+	/**
63
+	 * @return \EventEspresso\core\services\database\TableAnalysis
64
+	 */
65
+	public static function getTableAnalysis()
66
+	{
67
+		if (! self::$table_analysis instanceof \EventEspresso\core\services\database\TableAnalysis) {
68
+			self::$table_analysis = EE_Registry::instance()->create('TableAnalysis', array(), true);
69
+		}
70
+		return self::$table_analysis;
71
+	}
72
+
73
+
74
+	/**
75
+	 * @return \EventEspresso\core\services\database\TableManager
76
+	 */
77
+	public static function getTableManager()
78
+	{
79
+		if (! self::$table_manager instanceof \EventEspresso\core\services\database\TableManager) {
80
+			self::$table_manager = EE_Registry::instance()->create('TableManager', array(), true);
81
+		}
82
+		return self::$table_manager;
83
+	}
84
+
85
+
86
+	/**
87
+	 *    _ensure_table_name_has_prefix
88
+	 *
89
+	 * @deprecated instead use TableAnalysis::ensureTableNameHasPrefix()
90
+	 * @access     public
91
+	 * @static
92
+	 * @param $table_name
93
+	 * @return string
94
+	 */
95
+	public static function ensure_table_name_has_prefix($table_name)
96
+	{
97
+		return \EEH_Activation::getTableAnalysis()->ensureTableNameHasPrefix($table_name);
98
+	}
99
+
100
+
101
+	/**
102
+	 *    system_initialization
103
+	 *    ensures the EE configuration settings are loaded with at least default options set
104
+	 *    and that all critical EE pages have been generated with the appropriate shortcodes in place
105
+	 *
106
+	 * @access public
107
+	 * @static
108
+	 * @return void
109
+	 */
110
+	public static function system_initialization()
111
+	{
112
+		EEH_Activation::reset_and_update_config();
113
+		//which is fired BEFORE activation of plugin anyways
114
+		EEH_Activation::verify_default_pages_exist();
115
+	}
116
+
117
+
118
+	/**
119
+	 * Sets the database schema and creates folders. This should
120
+	 * be called on plugin activation and reactivation
121
+	 *
122
+	 * @return boolean success, whether the database and folders are setup properly
123
+	 * @throws \EE_Error
124
+	 */
125
+	public static function initialize_db_and_folders()
126
+	{
127
+		$good_filesystem = EEH_Activation::create_upload_directories();
128
+		$good_db         = EEH_Activation::create_database_tables();
129
+		return $good_filesystem && $good_db;
130
+	}
131
+
132
+
133
+	/**
134
+	 * assuming we have an up-to-date database schema, this will populate it
135
+	 * with default and initial data. This should be called
136
+	 * upon activation of a new plugin, reactivation, and at the end
137
+	 * of running migration scripts
138
+	 *
139
+	 * @throws \EE_Error
140
+	 */
141
+	public static function initialize_db_content()
142
+	{
143
+		//let's avoid doing all this logic repeatedly, especially when addons are requesting it
144
+		if (EEH_Activation::$_initialized_db_content_already_in_this_request) {
145
+			return;
146
+		}
147
+		EEH_Activation::$_initialized_db_content_already_in_this_request = true;
148
+
149
+		EEH_Activation::initialize_system_questions();
150
+		EEH_Activation::insert_default_status_codes();
151
+		EEH_Activation::generate_default_message_templates();
152
+		EEH_Activation::create_no_ticket_prices_array();
153
+		EE_Registry::instance()->CAP->init_caps();
154
+
155
+		EEH_Activation::validate_messages_system();
156
+		EEH_Activation::insert_default_payment_methods();
157
+		//in case we've
158
+		EEH_Activation::remove_cron_tasks();
159
+		EEH_Activation::create_cron_tasks();
160
+		// remove all TXN locks since that is being done via extra meta now
161
+		delete_option('ee_locked_transactions');
162
+		//also, check for CAF default db content
163
+		do_action('AHEE__EEH_Activation__initialize_db_content');
164
+		//also: EEM_Gateways::load_all_gateways() outputs a lot of success messages
165
+		//which users really won't care about on initial activation
166
+		EE_Error::overwrite_success();
167
+	}
168
+
169
+
170
+	/**
171
+	 * Returns an array of cron tasks. Array values are the actions fired by the cron tasks (the "hooks"),
172
+	 * values are the frequency (the "recurrence"). See http://codex.wordpress.org/Function_Reference/wp_schedule_event
173
+	 * If the cron task should NO longer be used, it should have a value of EEH_Activation::cron_task_no_longer_in_use
174
+	 * (null)
175
+	 *
176
+	 * @param string $which_to_include can be 'current' (ones that are currently in use),
177
+	 *                                 'old' (only returns ones that should no longer be used),or 'all',
178
+	 * @return array
179
+	 * @throws \EE_Error
180
+	 */
181
+	public static function get_cron_tasks($which_to_include)
182
+	{
183
+		$cron_tasks = apply_filters(
184
+			'FHEE__EEH_Activation__get_cron_tasks',
185
+			array(
186
+				'AHEE__EE_Cron_Tasks__clean_up_junk_transactions'      => 'hourly',
187 187
 //				'AHEE__EE_Cron_Tasks__finalize_abandoned_transactions' => EEH_Activation::cron_task_no_longer_in_use, actually this is still in use
188
-                'AHEE__EE_Cron_Tasks__update_transaction_with_payment' => EEH_Activation::cron_task_no_longer_in_use,
189
-                //there may have been a bug which prevented from these cron tasks from getting unscheduled, so we might want to remove these for a few updates
190
-                'AHEE_EE_Cron_Tasks__clean_out_old_gateway_logs'       => 'daily',
191
-            )
192
-        );
193
-        if ($which_to_include === 'old') {
194
-            $cron_tasks = array_filter(
195
-                $cron_tasks,
196
-                function ($value) {
197
-                    return $value === EEH_Activation::cron_task_no_longer_in_use;
198
-                }
199
-            );
200
-        } elseif ($which_to_include === 'current') {
201
-            $cron_tasks = array_filter($cron_tasks);
202
-        } elseif (WP_DEBUG && $which_to_include !== 'all') {
203
-            throw new EE_Error(
204
-                sprintf(
205
-                    __(
206
-                        'Invalid argument of "%1$s" passed to EEH_Activation::get_cron_tasks. Valid values are "all", "old" and "current".',
207
-                        'event_espresso'
208
-                    ),
209
-                    $which_to_include
210
-                )
211
-            );
212
-        }
213
-        return $cron_tasks;
214
-    }
215
-
216
-
217
-    /**
218
-     * Ensure cron tasks are setup (the removal of crons should be done by remove_crons())
219
-     *
220
-     * @throws \EE_Error
221
-     */
222
-    public static function create_cron_tasks()
223
-    {
224
-
225
-        foreach (EEH_Activation::get_cron_tasks('current') as $hook_name => $frequency) {
226
-            if (! wp_next_scheduled($hook_name)) {
227
-                /**
228
-                 * This allows client code to define the initial start timestamp for this schedule.
229
-                 */
230
-                if (is_array($frequency)
231
-                    && count($frequency) === 2
232
-                    && isset($frequency[0], $frequency[1])
233
-                ) {
234
-                    $start_timestamp = $frequency[0];
235
-                    $frequency = $frequency[1];
236
-                } else {
237
-                    $start_timestamp = time();
238
-                }
239
-                wp_schedule_event($start_timestamp, $frequency, $hook_name);
240
-            }
241
-        }
242
-
243
-    }
244
-
245
-
246
-    /**
247
-     * Remove the currently-existing and now-removed cron tasks.
248
-     *
249
-     * @param boolean $remove_all whether to only remove the old ones, or remove absolutely ALL the EE ones
250
-     * @throws \EE_Error
251
-     */
252
-    public static function remove_cron_tasks($remove_all = true)
253
-    {
254
-        $cron_tasks_to_remove = $remove_all ? 'all' : 'old';
255
-        $crons                = _get_cron_array();
256
-        $crons                = is_array($crons) ? $crons : array();
257
-        /* reminder of what $crons look like:
188
+				'AHEE__EE_Cron_Tasks__update_transaction_with_payment' => EEH_Activation::cron_task_no_longer_in_use,
189
+				//there may have been a bug which prevented from these cron tasks from getting unscheduled, so we might want to remove these for a few updates
190
+				'AHEE_EE_Cron_Tasks__clean_out_old_gateway_logs'       => 'daily',
191
+			)
192
+		);
193
+		if ($which_to_include === 'old') {
194
+			$cron_tasks = array_filter(
195
+				$cron_tasks,
196
+				function ($value) {
197
+					return $value === EEH_Activation::cron_task_no_longer_in_use;
198
+				}
199
+			);
200
+		} elseif ($which_to_include === 'current') {
201
+			$cron_tasks = array_filter($cron_tasks);
202
+		} elseif (WP_DEBUG && $which_to_include !== 'all') {
203
+			throw new EE_Error(
204
+				sprintf(
205
+					__(
206
+						'Invalid argument of "%1$s" passed to EEH_Activation::get_cron_tasks. Valid values are "all", "old" and "current".',
207
+						'event_espresso'
208
+					),
209
+					$which_to_include
210
+				)
211
+			);
212
+		}
213
+		return $cron_tasks;
214
+	}
215
+
216
+
217
+	/**
218
+	 * Ensure cron tasks are setup (the removal of crons should be done by remove_crons())
219
+	 *
220
+	 * @throws \EE_Error
221
+	 */
222
+	public static function create_cron_tasks()
223
+	{
224
+
225
+		foreach (EEH_Activation::get_cron_tasks('current') as $hook_name => $frequency) {
226
+			if (! wp_next_scheduled($hook_name)) {
227
+				/**
228
+				 * This allows client code to define the initial start timestamp for this schedule.
229
+				 */
230
+				if (is_array($frequency)
231
+					&& count($frequency) === 2
232
+					&& isset($frequency[0], $frequency[1])
233
+				) {
234
+					$start_timestamp = $frequency[0];
235
+					$frequency = $frequency[1];
236
+				} else {
237
+					$start_timestamp = time();
238
+				}
239
+				wp_schedule_event($start_timestamp, $frequency, $hook_name);
240
+			}
241
+		}
242
+
243
+	}
244
+
245
+
246
+	/**
247
+	 * Remove the currently-existing and now-removed cron tasks.
248
+	 *
249
+	 * @param boolean $remove_all whether to only remove the old ones, or remove absolutely ALL the EE ones
250
+	 * @throws \EE_Error
251
+	 */
252
+	public static function remove_cron_tasks($remove_all = true)
253
+	{
254
+		$cron_tasks_to_remove = $remove_all ? 'all' : 'old';
255
+		$crons                = _get_cron_array();
256
+		$crons                = is_array($crons) ? $crons : array();
257
+		/* reminder of what $crons look like:
258 258
          * Top-level keys are timestamps, and their values are arrays.
259 259
          * The 2nd level arrays have keys with each of the cron task hook names to run at that time
260 260
          * and their values are arrays.
@@ -271,912 +271,912 @@  discard block
 block discarded – undo
271 271
          *					...
272 272
          *      ...
273 273
          */
274
-        $ee_cron_tasks_to_remove = EEH_Activation::get_cron_tasks($cron_tasks_to_remove);
275
-        foreach ($crons as $timestamp => $hooks_to_fire_at_time) {
276
-            if (is_array($hooks_to_fire_at_time)) {
277
-                foreach ($hooks_to_fire_at_time as $hook_name => $hook_actions) {
278
-                    if (isset($ee_cron_tasks_to_remove[$hook_name])
279
-                        && is_array($ee_cron_tasks_to_remove[$hook_name])
280
-                    ) {
281
-                        unset($crons[$timestamp][$hook_name]);
282
-                    }
283
-                }
284
-                //also take care of any empty cron timestamps.
285
-                if (empty($hooks_to_fire_at_time)) {
286
-                    unset($crons[$timestamp]);
287
-                }
288
-            }
289
-        }
290
-        _set_cron_array($crons);
291
-    }
292
-
293
-
294
-    /**
295
-     *    CPT_initialization
296
-     *    registers all EE CPTs ( Custom Post Types ) then flushes rewrite rules so that all endpoints exist
297
-     *
298
-     * @access public
299
-     * @static
300
-     * @return void
301
-     */
302
-    public static function CPT_initialization()
303
-    {
304
-        // register Custom Post Types
305
-        EE_Registry::instance()->load_core('Register_CPTs');
306
-        flush_rewrite_rules();
307
-    }
308
-
309
-
310
-
311
-    /**
312
-     *    reset_and_update_config
313
-     * The following code was moved over from EE_Config so that it will no longer run on every request.
314
-     * If there is old calendar config data saved, then it will get converted on activation.
315
-     * This was basically a DMS before we had DMS's, and will get removed after a few more versions.
316
-     *
317
-     * @access public
318
-     * @static
319
-     * @return void
320
-     */
321
-    public static function reset_and_update_config()
322
-    {
323
-        do_action('AHEE__EE_Config___load_core_config__start', array('EEH_Activation', 'load_calendar_config'));
324
-        add_filter(
325
-            'FHEE__EE_Config___load_core_config__config_settings',
326
-            array('EEH_Activation', 'migrate_old_config_data'),
327
-            10,
328
-            3
329
-        );
330
-        //EE_Config::reset();
331
-        if (! EE_Config::logging_enabled()) {
332
-            delete_option(EE_Config::LOG_NAME);
333
-        }
334
-    }
335
-
336
-
337
-    /**
338
-     *    load_calendar_config
339
-     *
340
-     * @access    public
341
-     * @return    void
342
-     */
343
-    public static function load_calendar_config()
344
-    {
345
-        // grab array of all plugin folders and loop thru it
346
-        $plugins = glob(WP_PLUGIN_DIR . DS . '*', GLOB_ONLYDIR);
347
-        if (empty($plugins)) {
348
-            return;
349
-        }
350
-        foreach ($plugins as $plugin_path) {
351
-            // grab plugin folder name from path
352
-            $plugin = basename($plugin_path);
353
-            // drill down to Espresso plugins
354
-            // then to calendar related plugins
355
-            if (
356
-                strpos($plugin, 'espresso') !== false
357
-                || strpos($plugin, 'Espresso') !== false
358
-                || strpos($plugin, 'ee4') !== false
359
-                || strpos($plugin, 'EE4') !== false
360
-                || strpos($plugin, 'calendar') !== false
361
-            ) {
362
-                // this is what we are looking for
363
-                $calendar_config = $plugin_path . DS . 'EE_Calendar_Config.php';
364
-                // does it exist in this folder ?
365
-                if (is_readable($calendar_config)) {
366
-                    // YEAH! let's load it
367
-                    require_once($calendar_config);
368
-                }
369
-            }
370
-        }
371
-    }
372
-
373
-
374
-
375
-    /**
376
-     *    _migrate_old_config_data
377
-     *
378
-     * @access    public
379
-     * @param array|stdClass $settings
380
-     * @param string         $config
381
-     * @param \EE_Config     $EE_Config
382
-     * @return \stdClass
383
-     */
384
-    public static function migrate_old_config_data($settings = array(), $config = '', EE_Config $EE_Config)
385
-    {
386
-        $convert_from_array = array('addons');
387
-        // in case old settings were saved as an array
388
-        if (is_array($settings) && in_array($config, $convert_from_array)) {
389
-            // convert existing settings to an object
390
-            $config_array = $settings;
391
-            $settings = new stdClass();
392
-            foreach ($config_array as $key => $value) {
393
-                if ($key === 'calendar' && class_exists('EE_Calendar_Config')) {
394
-                    $EE_Config->set_config('addons', 'EE_Calendar', 'EE_Calendar_Config', $value);
395
-                } else {
396
-                    $settings->{$key} = $value;
397
-                }
398
-            }
399
-            add_filter('FHEE__EE_Config___load_core_config__update_espresso_config', '__return_true');
400
-        }
401
-        return $settings;
402
-    }
403
-
404
-
405
-    /**
406
-     * deactivate_event_espresso
407
-     *
408
-     * @access public
409
-     * @static
410
-     * @return void
411
-     */
412
-    public static function deactivate_event_espresso()
413
-    {
414
-        // check permissions
415
-        if (current_user_can('activate_plugins')) {
416
-            deactivate_plugins(EE_PLUGIN_BASENAME, true);
417
-        }
418
-    }
419
-
420
-
421
-
422
-
423
-
424
-    /**
425
-     * verify_default_pages_exist
426
-     *
427
-     * @access public
428
-     * @static
429
-     * @return void
430
-     */
431
-    public static function verify_default_pages_exist()
432
-    {
433
-        $critical_page_problem = false;
434
-        $critical_pages = array(
435
-            array(
436
-                'id'   => 'reg_page_id',
437
-                'name' => __('Registration Checkout', 'event_espresso'),
438
-                'post' => null,
439
-                'code' => 'ESPRESSO_CHECKOUT',
440
-            ),
441
-            array(
442
-                'id'   => 'txn_page_id',
443
-                'name' => __('Transactions', 'event_espresso'),
444
-                'post' => null,
445
-                'code' => 'ESPRESSO_TXN_PAGE',
446
-            ),
447
-            array(
448
-                'id'   => 'thank_you_page_id',
449
-                'name' => __('Thank You', 'event_espresso'),
450
-                'post' => null,
451
-                'code' => 'ESPRESSO_THANK_YOU',
452
-            ),
453
-            array(
454
-                'id'   => 'cancel_page_id',
455
-                'name' => __('Registration Cancelled', 'event_espresso'),
456
-                'post' => null,
457
-                'code' => 'ESPRESSO_CANCELLED',
458
-            ),
459
-        );
460
-        $EE_Core_Config = EE_Registry::instance()->CFG->core;
461
-        foreach ($critical_pages as $critical_page) {
462
-            // is critical page ID set in config ?
463
-            if ($EE_Core_Config->{$critical_page['id']} !== false) {
464
-                // attempt to find post by ID
465
-                $critical_page['post'] = get_post($EE_Core_Config->{$critical_page['id']});
466
-            }
467
-            // no dice?
468
-            if ($critical_page['post'] === null) {
469
-                // attempt to find post by title
470
-                $critical_page['post'] = self::get_page_by_ee_shortcode($critical_page['code']);
471
-                // still nothing?
472
-                if ($critical_page['post'] === null) {
473
-                    $critical_page = EEH_Activation::create_critical_page($critical_page);
474
-                    // REALLY? Still nothing ??!?!?
475
-                    if ($critical_page['post'] === null) {
476
-                        $msg = __(
477
-                            'The Event Espresso critical page configuration settings could not be updated.',
478
-                            'event_espresso'
479
-                        );
480
-                        EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
481
-                        break;
482
-                    }
483
-                }
484
-            }
485
-            // check that Post ID matches critical page ID in config
486
-            if (
487
-                isset($critical_page['post']->ID)
488
-                && $critical_page['post']->ID !== $EE_Core_Config->{$critical_page['id']}
489
-            ) {
490
-                //update Config with post ID
491
-                $EE_Core_Config->{$critical_page['id']} = $critical_page['post']->ID;
492
-                if (! EE_Config::instance()->update_espresso_config(false, false)) {
493
-                    $msg = __(
494
-                        'The Event Espresso critical page configuration settings could not be updated.',
495
-                        'event_espresso'
496
-                    );
497
-                    EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
498
-                }
499
-            }
500
-            $critical_page_problem =
501
-                ! isset($critical_page['post']->post_status)
502
-                || $critical_page['post']->post_status !== 'publish'
503
-                || strpos($critical_page['post']->post_content, $critical_page['code']) === false
504
-                    ? true
505
-                    : $critical_page_problem;
506
-        }
507
-        if ($critical_page_problem) {
508
-            $msg = sprintf(
509
-                __(
510
-                    'A potential issue has been detected with one or more of your Event Espresso pages. Go to %s to view your Event Espresso pages.',
511
-                    'event_espresso'
512
-                ),
513
-                '<a href="'
514
-                . admin_url('admin.php?page=espresso_general_settings&action=critical_pages')
515
-                . '">'
516
-                . __('Event Espresso Critical Pages Settings', 'event_espresso')
517
-                . '</a>'
518
-            );
519
-            EE_Error::add_persistent_admin_notice('critical_page_problem', $msg);
520
-        }
521
-        if (EE_Error::has_notices()) {
522
-            EE_Error::get_notices(false, true, true);
523
-        }
524
-    }
525
-
526
-
527
-
528
-    /**
529
-     * Returns the first post which uses the specified shortcode
530
-     *
531
-     * @param string $ee_shortcode usually one of the critical pages shortcodes, eg
532
-     *                             ESPRESSO_THANK_YOU. So we will search fora post with the content
533
-     *                             "[ESPRESSO_THANK_YOU"
534
-     *                             (we don't search for the closing shortcode bracket because they might have added
535
-     *                             parameter to the shortcode
536
-     * @return WP_Post or NULl
537
-     */
538
-    public static function get_page_by_ee_shortcode($ee_shortcode)
539
-    {
540
-        global $wpdb;
541
-        $shortcode_and_opening_bracket = '[' . $ee_shortcode;
542
-        $post_id = $wpdb->get_var("SELECT ID FROM {$wpdb->posts} WHERE post_content LIKE '%$shortcode_and_opening_bracket%' LIMIT 1");
543
-        if ($post_id) {
544
-            return get_post($post_id);
545
-        } else {
546
-            return null;
547
-        }
548
-    }
549
-
550
-
551
-    /**
552
-     *    This function generates a post for critical espresso pages
553
-     *
554
-     * @access public
555
-     * @static
556
-     * @param array $critical_page
557
-     * @return array
558
-     */
559
-    public static function create_critical_page($critical_page)
560
-    {
561
-
562
-        $post_args = array(
563
-            'post_title'     => $critical_page['name'],
564
-            'post_status'    => 'publish',
565
-            'post_type'      => 'page',
566
-            'comment_status' => 'closed',
567
-            'post_content'   => '[' . $critical_page['code'] . ']',
568
-        );
569
-
570
-        $post_id = wp_insert_post($post_args);
571
-        if (! $post_id) {
572
-            $msg = sprintf(
573
-                __('The Event Espresso  critical page entitled "%s" could not be created.', 'event_espresso'),
574
-                $critical_page['name']
575
-            );
576
-            EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
577
-            return $critical_page;
578
-        }
579
-        // get newly created post's details
580
-        if (! $critical_page['post'] = get_post($post_id)) {
581
-            $msg = sprintf(
582
-                __('The Event Espresso critical page entitled "%s" could not be retrieved.', 'event_espresso'),
583
-                $critical_page['name']
584
-            );
585
-            EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
586
-        }
587
-
588
-        return $critical_page;
589
-
590
-    }
591
-
592
-
593
-
594
-
595
-    /**
596
-     * Tries to find the oldest admin for this site.  If there are no admins for this site then return NULL.
597
-     * The role being used to check is filterable.
598
-     *
599
-     * @since  4.6.0
600
-     * @global WPDB $wpdb
601
-     * @return mixed null|int WP_user ID or NULL
602
-     */
603
-    public static function get_default_creator_id()
604
-    {
605
-        global $wpdb;
606
-        if ( ! empty(self::$_default_creator_id)) {
607
-            return self::$_default_creator_id;
608
-        }/**/
609
-        $role_to_check = apply_filters('FHEE__EEH_Activation__get_default_creator_id__role_to_check', 'administrator');
610
-        //let's allow pre_filtering for early exits by alternative methods for getting id.  We check for truthy result and if so then exit early.
611
-        $pre_filtered_id = apply_filters(
612
-            'FHEE__EEH_Activation__get_default_creator_id__pre_filtered_id',
613
-            false,
614
-            $role_to_check
615
-        );
616
-        if ($pre_filtered_id !== false) {
617
-            return (int)$pre_filtered_id;
618
-        }
619
-        $capabilities_key = \EEH_Activation::getTableAnalysis()->ensureTableNameHasPrefix('capabilities');
620
-        $query = $wpdb->prepare(
621
-            "SELECT user_id FROM $wpdb->usermeta WHERE meta_key = '$capabilities_key' AND meta_value LIKE %s ORDER BY user_id ASC LIMIT 0,1",
622
-            '%' . $role_to_check . '%'
623
-        );
624
-        $user_id = $wpdb->get_var($query);
625
-        $user_id = apply_filters('FHEE__EEH_Activation_Helper__get_default_creator_id__user_id', $user_id);
626
-        if ($user_id && (int)$user_id) {
627
-            self::$_default_creator_id = (int)$user_id;
628
-            return self::$_default_creator_id;
629
-        } else {
630
-            return null;
631
-        }
632
-    }
633
-
634
-
635
-
636
-    /**
637
-     * used by EE and EE addons during plugin activation to create tables.
638
-     * Its a wrapper for EventEspresso\core\services\database\TableManager::createTable,
639
-     * but includes extra logic regarding activations.
640
-     *
641
-     * @access public
642
-     * @static
643
-     * @param string  $table_name              without the $wpdb->prefix
644
-     * @param string  $sql                     SQL for creating the table (contents between brackets in an SQL create
645
-     *                                         table query)
646
-     * @param string  $engine                  like 'ENGINE=MyISAM' or 'ENGINE=InnoDB'
647
-     * @param boolean $drop_pre_existing_table set to TRUE when you want to make SURE the table is completely empty
648
-     *                                         and new once this function is done (ie, you really do want to CREATE a
649
-     *                                         table, and expect it to be empty once you're done) leave as FALSE when
650
-     *                                         you just want to verify the table exists and matches this definition
651
-     *                                         (and if it HAS data in it you want to leave it be)
652
-     * @return void
653
-     * @throws EE_Error if there are database errors
654
-     */
655
-    public static function create_table($table_name, $sql, $engine = 'ENGINE=MyISAM ', $drop_pre_existing_table = false)
656
-    {
657
-        if (apply_filters('FHEE__EEH_Activation__create_table__short_circuit', false, $table_name, $sql)) {
658
-            return;
659
-        }
660
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
661
-        if ( ! function_exists('dbDelta')) {
662
-            require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
663
-        }
664
-        $tableAnalysis = \EEH_Activation::getTableAnalysis();
665
-        $wp_table_name = $tableAnalysis->ensureTableNameHasPrefix($table_name);
666
-        // do we need to first delete an existing version of this table ?
667
-        if ($drop_pre_existing_table && $tableAnalysis->tableExists($wp_table_name)) {
668
-            // ok, delete the table... but ONLY if it's empty
669
-            $deleted_safely = EEH_Activation::delete_db_table_if_empty($wp_table_name);
670
-            // table is NOT empty, are you SURE you want to delete this table ???
671
-            if ( ! $deleted_safely && defined('EE_DROP_BAD_TABLES') && EE_DROP_BAD_TABLES) {
672
-                \EEH_Activation::getTableManager()->dropTable($wp_table_name);
673
-            } else if ( ! $deleted_safely) {
674
-                // so we should be more cautious rather than just dropping tables so easily
675
-                error_log(
676
-                    sprintf(
677
-                        __(
678
-                            'It appears that database table "%1$s" exists when it shouldn\'t, and therefore may contain erroneous data. If you have previously restored your database from a backup that didn\'t remove the old tables, then we recommend: %2$s 1. create a new COMPLETE backup of your database, %2$s 2. delete ALL tables from your database, %2$s 3. restore to your previous backup. %2$s If, however, you have not restored to a backup, then somehow your "%3$s" WordPress option could not be read. You can probably ignore this message, but should investigate why that option is being removed.',
679
-                            'event_espresso'
680
-                        ),
681
-                        $wp_table_name,
682
-                        '<br/>',
683
-                        'espresso_db_update'
684
-                    )
685
-                );
686
-            }
687
-        }
688
-        $engine = str_replace('ENGINE=', '', $engine);
689
-        \EEH_Activation::getTableManager()->createTable($table_name, $sql, $engine);
690
-    }
691
-
692
-
693
-
694
-    /**
695
-     *    add_column_if_it_doesn't_exist
696
-     *    Checks if this column already exists on the specified table. Handy for addons which want to add a column
697
-     *
698
-     * @access     public
699
-     * @static
700
-     * @deprecated instead use TableManager::addColumn()
701
-     * @param string $table_name  (without "wp_", eg "esp_attendee"
702
-     * @param string $column_name
703
-     * @param string $column_info if your SQL were 'ALTER TABLE table_name ADD price VARCHAR(10)', this would be
704
-     *                            'VARCHAR(10)'
705
-     * @return bool|int
706
-     */
707
-    public static function add_column_if_it_doesnt_exist(
708
-        $table_name,
709
-        $column_name,
710
-        $column_info = 'INT UNSIGNED NOT NULL'
711
-    ) {
712
-        return \EEH_Activation::getTableManager()->addColumn($table_name, $column_name, $column_info);
713
-    }
714
-
715
-
716
-    /**
717
-     * get_fields_on_table
718
-     * Gets all the fields on the database table.
719
-     *
720
-     * @access     public
721
-     * @deprecated instead use TableManager::getTableColumns()
722
-     * @static
723
-     * @param string $table_name , without prefixed $wpdb->prefix
724
-     * @return array of database column names
725
-     */
726
-    public static function get_fields_on_table($table_name = null)
727
-    {
728
-        return \EEH_Activation::getTableManager()->getTableColumns($table_name);
729
-    }
730
-
731
-
732
-    /**
733
-     * db_table_is_empty
734
-     *
735
-     * @access     public\
736
-     * @deprecated instead use TableAnalysis::tableIsEmpty()
737
-     * @static
738
-     * @param string $table_name
739
-     * @return bool
740
-     */
741
-    public static function db_table_is_empty($table_name)
742
-    {
743
-        return \EEH_Activation::getTableAnalysis()->tableIsEmpty($table_name);
744
-    }
745
-
746
-
747
-    /**
748
-     * delete_db_table_if_empty
749
-     *
750
-     * @access public
751
-     * @static
752
-     * @param string $table_name
753
-     * @return bool | int
754
-     */
755
-    public static function delete_db_table_if_empty($table_name)
756
-    {
757
-        if (\EEH_Activation::getTableAnalysis()->tableIsEmpty($table_name)) {
758
-            return \EEH_Activation::getTableManager()->dropTable($table_name);
759
-        }
760
-        return false;
761
-    }
762
-
763
-
764
-    /**
765
-     * delete_unused_db_table
766
-     *
767
-     * @access     public
768
-     * @static
769
-     * @deprecated instead use TableManager::dropTable()
770
-     * @param string $table_name
771
-     * @return bool | int
772
-     */
773
-    public static function delete_unused_db_table($table_name)
774
-    {
775
-        return \EEH_Activation::getTableManager()->dropTable($table_name);
776
-    }
777
-
778
-
779
-    /**
780
-     * drop_index
781
-     *
782
-     * @access     public
783
-     * @static
784
-     * @deprecated instead use TableManager::dropIndex()
785
-     * @param string $table_name
786
-     * @param string $index_name
787
-     * @return bool | int
788
-     */
789
-    public static function drop_index($table_name, $index_name)
790
-    {
791
-        return \EEH_Activation::getTableManager()->dropIndex($table_name, $index_name);
792
-    }
793
-
794
-
795
-
796
-    /**
797
-     * create_database_tables
798
-     *
799
-     * @access public
800
-     * @static
801
-     * @throws EE_Error
802
-     * @return boolean success (whether database is setup properly or not)
803
-     */
804
-    public static function create_database_tables()
805
-    {
806
-        EE_Registry::instance()->load_core('Data_Migration_Manager');
807
-        //find the migration script that sets the database to be compatible with the code
808
-        $dms_name = EE_Data_Migration_Manager::instance()->get_most_up_to_date_dms();
809
-        if ($dms_name) {
810
-            $current_data_migration_script = EE_Registry::instance()->load_dms($dms_name);
811
-            $current_data_migration_script->set_migrating(false);
812
-            $current_data_migration_script->schema_changes_before_migration();
813
-            $current_data_migration_script->schema_changes_after_migration();
814
-            if ($current_data_migration_script->get_errors()) {
815
-                if (WP_DEBUG) {
816
-                    foreach ($current_data_migration_script->get_errors() as $error) {
817
-                        EE_Error::add_error($error, __FILE__, __FUNCTION__, __LINE__);
818
-                    }
819
-                } else {
820
-                    EE_Error::add_error(
821
-                        __(
822
-                            'There were errors creating the Event Espresso database tables and Event Espresso has been 
274
+		$ee_cron_tasks_to_remove = EEH_Activation::get_cron_tasks($cron_tasks_to_remove);
275
+		foreach ($crons as $timestamp => $hooks_to_fire_at_time) {
276
+			if (is_array($hooks_to_fire_at_time)) {
277
+				foreach ($hooks_to_fire_at_time as $hook_name => $hook_actions) {
278
+					if (isset($ee_cron_tasks_to_remove[$hook_name])
279
+						&& is_array($ee_cron_tasks_to_remove[$hook_name])
280
+					) {
281
+						unset($crons[$timestamp][$hook_name]);
282
+					}
283
+				}
284
+				//also take care of any empty cron timestamps.
285
+				if (empty($hooks_to_fire_at_time)) {
286
+					unset($crons[$timestamp]);
287
+				}
288
+			}
289
+		}
290
+		_set_cron_array($crons);
291
+	}
292
+
293
+
294
+	/**
295
+	 *    CPT_initialization
296
+	 *    registers all EE CPTs ( Custom Post Types ) then flushes rewrite rules so that all endpoints exist
297
+	 *
298
+	 * @access public
299
+	 * @static
300
+	 * @return void
301
+	 */
302
+	public static function CPT_initialization()
303
+	{
304
+		// register Custom Post Types
305
+		EE_Registry::instance()->load_core('Register_CPTs');
306
+		flush_rewrite_rules();
307
+	}
308
+
309
+
310
+
311
+	/**
312
+	 *    reset_and_update_config
313
+	 * The following code was moved over from EE_Config so that it will no longer run on every request.
314
+	 * If there is old calendar config data saved, then it will get converted on activation.
315
+	 * This was basically a DMS before we had DMS's, and will get removed after a few more versions.
316
+	 *
317
+	 * @access public
318
+	 * @static
319
+	 * @return void
320
+	 */
321
+	public static function reset_and_update_config()
322
+	{
323
+		do_action('AHEE__EE_Config___load_core_config__start', array('EEH_Activation', 'load_calendar_config'));
324
+		add_filter(
325
+			'FHEE__EE_Config___load_core_config__config_settings',
326
+			array('EEH_Activation', 'migrate_old_config_data'),
327
+			10,
328
+			3
329
+		);
330
+		//EE_Config::reset();
331
+		if (! EE_Config::logging_enabled()) {
332
+			delete_option(EE_Config::LOG_NAME);
333
+		}
334
+	}
335
+
336
+
337
+	/**
338
+	 *    load_calendar_config
339
+	 *
340
+	 * @access    public
341
+	 * @return    void
342
+	 */
343
+	public static function load_calendar_config()
344
+	{
345
+		// grab array of all plugin folders and loop thru it
346
+		$plugins = glob(WP_PLUGIN_DIR . DS . '*', GLOB_ONLYDIR);
347
+		if (empty($plugins)) {
348
+			return;
349
+		}
350
+		foreach ($plugins as $plugin_path) {
351
+			// grab plugin folder name from path
352
+			$plugin = basename($plugin_path);
353
+			// drill down to Espresso plugins
354
+			// then to calendar related plugins
355
+			if (
356
+				strpos($plugin, 'espresso') !== false
357
+				|| strpos($plugin, 'Espresso') !== false
358
+				|| strpos($plugin, 'ee4') !== false
359
+				|| strpos($plugin, 'EE4') !== false
360
+				|| strpos($plugin, 'calendar') !== false
361
+			) {
362
+				// this is what we are looking for
363
+				$calendar_config = $plugin_path . DS . 'EE_Calendar_Config.php';
364
+				// does it exist in this folder ?
365
+				if (is_readable($calendar_config)) {
366
+					// YEAH! let's load it
367
+					require_once($calendar_config);
368
+				}
369
+			}
370
+		}
371
+	}
372
+
373
+
374
+
375
+	/**
376
+	 *    _migrate_old_config_data
377
+	 *
378
+	 * @access    public
379
+	 * @param array|stdClass $settings
380
+	 * @param string         $config
381
+	 * @param \EE_Config     $EE_Config
382
+	 * @return \stdClass
383
+	 */
384
+	public static function migrate_old_config_data($settings = array(), $config = '', EE_Config $EE_Config)
385
+	{
386
+		$convert_from_array = array('addons');
387
+		// in case old settings were saved as an array
388
+		if (is_array($settings) && in_array($config, $convert_from_array)) {
389
+			// convert existing settings to an object
390
+			$config_array = $settings;
391
+			$settings = new stdClass();
392
+			foreach ($config_array as $key => $value) {
393
+				if ($key === 'calendar' && class_exists('EE_Calendar_Config')) {
394
+					$EE_Config->set_config('addons', 'EE_Calendar', 'EE_Calendar_Config', $value);
395
+				} else {
396
+					$settings->{$key} = $value;
397
+				}
398
+			}
399
+			add_filter('FHEE__EE_Config___load_core_config__update_espresso_config', '__return_true');
400
+		}
401
+		return $settings;
402
+	}
403
+
404
+
405
+	/**
406
+	 * deactivate_event_espresso
407
+	 *
408
+	 * @access public
409
+	 * @static
410
+	 * @return void
411
+	 */
412
+	public static function deactivate_event_espresso()
413
+	{
414
+		// check permissions
415
+		if (current_user_can('activate_plugins')) {
416
+			deactivate_plugins(EE_PLUGIN_BASENAME, true);
417
+		}
418
+	}
419
+
420
+
421
+
422
+
423
+
424
+	/**
425
+	 * verify_default_pages_exist
426
+	 *
427
+	 * @access public
428
+	 * @static
429
+	 * @return void
430
+	 */
431
+	public static function verify_default_pages_exist()
432
+	{
433
+		$critical_page_problem = false;
434
+		$critical_pages = array(
435
+			array(
436
+				'id'   => 'reg_page_id',
437
+				'name' => __('Registration Checkout', 'event_espresso'),
438
+				'post' => null,
439
+				'code' => 'ESPRESSO_CHECKOUT',
440
+			),
441
+			array(
442
+				'id'   => 'txn_page_id',
443
+				'name' => __('Transactions', 'event_espresso'),
444
+				'post' => null,
445
+				'code' => 'ESPRESSO_TXN_PAGE',
446
+			),
447
+			array(
448
+				'id'   => 'thank_you_page_id',
449
+				'name' => __('Thank You', 'event_espresso'),
450
+				'post' => null,
451
+				'code' => 'ESPRESSO_THANK_YOU',
452
+			),
453
+			array(
454
+				'id'   => 'cancel_page_id',
455
+				'name' => __('Registration Cancelled', 'event_espresso'),
456
+				'post' => null,
457
+				'code' => 'ESPRESSO_CANCELLED',
458
+			),
459
+		);
460
+		$EE_Core_Config = EE_Registry::instance()->CFG->core;
461
+		foreach ($critical_pages as $critical_page) {
462
+			// is critical page ID set in config ?
463
+			if ($EE_Core_Config->{$critical_page['id']} !== false) {
464
+				// attempt to find post by ID
465
+				$critical_page['post'] = get_post($EE_Core_Config->{$critical_page['id']});
466
+			}
467
+			// no dice?
468
+			if ($critical_page['post'] === null) {
469
+				// attempt to find post by title
470
+				$critical_page['post'] = self::get_page_by_ee_shortcode($critical_page['code']);
471
+				// still nothing?
472
+				if ($critical_page['post'] === null) {
473
+					$critical_page = EEH_Activation::create_critical_page($critical_page);
474
+					// REALLY? Still nothing ??!?!?
475
+					if ($critical_page['post'] === null) {
476
+						$msg = __(
477
+							'The Event Espresso critical page configuration settings could not be updated.',
478
+							'event_espresso'
479
+						);
480
+						EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
481
+						break;
482
+					}
483
+				}
484
+			}
485
+			// check that Post ID matches critical page ID in config
486
+			if (
487
+				isset($critical_page['post']->ID)
488
+				&& $critical_page['post']->ID !== $EE_Core_Config->{$critical_page['id']}
489
+			) {
490
+				//update Config with post ID
491
+				$EE_Core_Config->{$critical_page['id']} = $critical_page['post']->ID;
492
+				if (! EE_Config::instance()->update_espresso_config(false, false)) {
493
+					$msg = __(
494
+						'The Event Espresso critical page configuration settings could not be updated.',
495
+						'event_espresso'
496
+					);
497
+					EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
498
+				}
499
+			}
500
+			$critical_page_problem =
501
+				! isset($critical_page['post']->post_status)
502
+				|| $critical_page['post']->post_status !== 'publish'
503
+				|| strpos($critical_page['post']->post_content, $critical_page['code']) === false
504
+					? true
505
+					: $critical_page_problem;
506
+		}
507
+		if ($critical_page_problem) {
508
+			$msg = sprintf(
509
+				__(
510
+					'A potential issue has been detected with one or more of your Event Espresso pages. Go to %s to view your Event Espresso pages.',
511
+					'event_espresso'
512
+				),
513
+				'<a href="'
514
+				. admin_url('admin.php?page=espresso_general_settings&action=critical_pages')
515
+				. '">'
516
+				. __('Event Espresso Critical Pages Settings', 'event_espresso')
517
+				. '</a>'
518
+			);
519
+			EE_Error::add_persistent_admin_notice('critical_page_problem', $msg);
520
+		}
521
+		if (EE_Error::has_notices()) {
522
+			EE_Error::get_notices(false, true, true);
523
+		}
524
+	}
525
+
526
+
527
+
528
+	/**
529
+	 * Returns the first post which uses the specified shortcode
530
+	 *
531
+	 * @param string $ee_shortcode usually one of the critical pages shortcodes, eg
532
+	 *                             ESPRESSO_THANK_YOU. So we will search fora post with the content
533
+	 *                             "[ESPRESSO_THANK_YOU"
534
+	 *                             (we don't search for the closing shortcode bracket because they might have added
535
+	 *                             parameter to the shortcode
536
+	 * @return WP_Post or NULl
537
+	 */
538
+	public static function get_page_by_ee_shortcode($ee_shortcode)
539
+	{
540
+		global $wpdb;
541
+		$shortcode_and_opening_bracket = '[' . $ee_shortcode;
542
+		$post_id = $wpdb->get_var("SELECT ID FROM {$wpdb->posts} WHERE post_content LIKE '%$shortcode_and_opening_bracket%' LIMIT 1");
543
+		if ($post_id) {
544
+			return get_post($post_id);
545
+		} else {
546
+			return null;
547
+		}
548
+	}
549
+
550
+
551
+	/**
552
+	 *    This function generates a post for critical espresso pages
553
+	 *
554
+	 * @access public
555
+	 * @static
556
+	 * @param array $critical_page
557
+	 * @return array
558
+	 */
559
+	public static function create_critical_page($critical_page)
560
+	{
561
+
562
+		$post_args = array(
563
+			'post_title'     => $critical_page['name'],
564
+			'post_status'    => 'publish',
565
+			'post_type'      => 'page',
566
+			'comment_status' => 'closed',
567
+			'post_content'   => '[' . $critical_page['code'] . ']',
568
+		);
569
+
570
+		$post_id = wp_insert_post($post_args);
571
+		if (! $post_id) {
572
+			$msg = sprintf(
573
+				__('The Event Espresso  critical page entitled "%s" could not be created.', 'event_espresso'),
574
+				$critical_page['name']
575
+			);
576
+			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
577
+			return $critical_page;
578
+		}
579
+		// get newly created post's details
580
+		if (! $critical_page['post'] = get_post($post_id)) {
581
+			$msg = sprintf(
582
+				__('The Event Espresso critical page entitled "%s" could not be retrieved.', 'event_espresso'),
583
+				$critical_page['name']
584
+			);
585
+			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
586
+		}
587
+
588
+		return $critical_page;
589
+
590
+	}
591
+
592
+
593
+
594
+
595
+	/**
596
+	 * Tries to find the oldest admin for this site.  If there are no admins for this site then return NULL.
597
+	 * The role being used to check is filterable.
598
+	 *
599
+	 * @since  4.6.0
600
+	 * @global WPDB $wpdb
601
+	 * @return mixed null|int WP_user ID or NULL
602
+	 */
603
+	public static function get_default_creator_id()
604
+	{
605
+		global $wpdb;
606
+		if ( ! empty(self::$_default_creator_id)) {
607
+			return self::$_default_creator_id;
608
+		}/**/
609
+		$role_to_check = apply_filters('FHEE__EEH_Activation__get_default_creator_id__role_to_check', 'administrator');
610
+		//let's allow pre_filtering for early exits by alternative methods for getting id.  We check for truthy result and if so then exit early.
611
+		$pre_filtered_id = apply_filters(
612
+			'FHEE__EEH_Activation__get_default_creator_id__pre_filtered_id',
613
+			false,
614
+			$role_to_check
615
+		);
616
+		if ($pre_filtered_id !== false) {
617
+			return (int)$pre_filtered_id;
618
+		}
619
+		$capabilities_key = \EEH_Activation::getTableAnalysis()->ensureTableNameHasPrefix('capabilities');
620
+		$query = $wpdb->prepare(
621
+			"SELECT user_id FROM $wpdb->usermeta WHERE meta_key = '$capabilities_key' AND meta_value LIKE %s ORDER BY user_id ASC LIMIT 0,1",
622
+			'%' . $role_to_check . '%'
623
+		);
624
+		$user_id = $wpdb->get_var($query);
625
+		$user_id = apply_filters('FHEE__EEH_Activation_Helper__get_default_creator_id__user_id', $user_id);
626
+		if ($user_id && (int)$user_id) {
627
+			self::$_default_creator_id = (int)$user_id;
628
+			return self::$_default_creator_id;
629
+		} else {
630
+			return null;
631
+		}
632
+	}
633
+
634
+
635
+
636
+	/**
637
+	 * used by EE and EE addons during plugin activation to create tables.
638
+	 * Its a wrapper for EventEspresso\core\services\database\TableManager::createTable,
639
+	 * but includes extra logic regarding activations.
640
+	 *
641
+	 * @access public
642
+	 * @static
643
+	 * @param string  $table_name              without the $wpdb->prefix
644
+	 * @param string  $sql                     SQL for creating the table (contents between brackets in an SQL create
645
+	 *                                         table query)
646
+	 * @param string  $engine                  like 'ENGINE=MyISAM' or 'ENGINE=InnoDB'
647
+	 * @param boolean $drop_pre_existing_table set to TRUE when you want to make SURE the table is completely empty
648
+	 *                                         and new once this function is done (ie, you really do want to CREATE a
649
+	 *                                         table, and expect it to be empty once you're done) leave as FALSE when
650
+	 *                                         you just want to verify the table exists and matches this definition
651
+	 *                                         (and if it HAS data in it you want to leave it be)
652
+	 * @return void
653
+	 * @throws EE_Error if there are database errors
654
+	 */
655
+	public static function create_table($table_name, $sql, $engine = 'ENGINE=MyISAM ', $drop_pre_existing_table = false)
656
+	{
657
+		if (apply_filters('FHEE__EEH_Activation__create_table__short_circuit', false, $table_name, $sql)) {
658
+			return;
659
+		}
660
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
661
+		if ( ! function_exists('dbDelta')) {
662
+			require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
663
+		}
664
+		$tableAnalysis = \EEH_Activation::getTableAnalysis();
665
+		$wp_table_name = $tableAnalysis->ensureTableNameHasPrefix($table_name);
666
+		// do we need to first delete an existing version of this table ?
667
+		if ($drop_pre_existing_table && $tableAnalysis->tableExists($wp_table_name)) {
668
+			// ok, delete the table... but ONLY if it's empty
669
+			$deleted_safely = EEH_Activation::delete_db_table_if_empty($wp_table_name);
670
+			// table is NOT empty, are you SURE you want to delete this table ???
671
+			if ( ! $deleted_safely && defined('EE_DROP_BAD_TABLES') && EE_DROP_BAD_TABLES) {
672
+				\EEH_Activation::getTableManager()->dropTable($wp_table_name);
673
+			} else if ( ! $deleted_safely) {
674
+				// so we should be more cautious rather than just dropping tables so easily
675
+				error_log(
676
+					sprintf(
677
+						__(
678
+							'It appears that database table "%1$s" exists when it shouldn\'t, and therefore may contain erroneous data. If you have previously restored your database from a backup that didn\'t remove the old tables, then we recommend: %2$s 1. create a new COMPLETE backup of your database, %2$s 2. delete ALL tables from your database, %2$s 3. restore to your previous backup. %2$s If, however, you have not restored to a backup, then somehow your "%3$s" WordPress option could not be read. You can probably ignore this message, but should investigate why that option is being removed.',
679
+							'event_espresso'
680
+						),
681
+						$wp_table_name,
682
+						'<br/>',
683
+						'espresso_db_update'
684
+					)
685
+				);
686
+			}
687
+		}
688
+		$engine = str_replace('ENGINE=', '', $engine);
689
+		\EEH_Activation::getTableManager()->createTable($table_name, $sql, $engine);
690
+	}
691
+
692
+
693
+
694
+	/**
695
+	 *    add_column_if_it_doesn't_exist
696
+	 *    Checks if this column already exists on the specified table. Handy for addons which want to add a column
697
+	 *
698
+	 * @access     public
699
+	 * @static
700
+	 * @deprecated instead use TableManager::addColumn()
701
+	 * @param string $table_name  (without "wp_", eg "esp_attendee"
702
+	 * @param string $column_name
703
+	 * @param string $column_info if your SQL were 'ALTER TABLE table_name ADD price VARCHAR(10)', this would be
704
+	 *                            'VARCHAR(10)'
705
+	 * @return bool|int
706
+	 */
707
+	public static function add_column_if_it_doesnt_exist(
708
+		$table_name,
709
+		$column_name,
710
+		$column_info = 'INT UNSIGNED NOT NULL'
711
+	) {
712
+		return \EEH_Activation::getTableManager()->addColumn($table_name, $column_name, $column_info);
713
+	}
714
+
715
+
716
+	/**
717
+	 * get_fields_on_table
718
+	 * Gets all the fields on the database table.
719
+	 *
720
+	 * @access     public
721
+	 * @deprecated instead use TableManager::getTableColumns()
722
+	 * @static
723
+	 * @param string $table_name , without prefixed $wpdb->prefix
724
+	 * @return array of database column names
725
+	 */
726
+	public static function get_fields_on_table($table_name = null)
727
+	{
728
+		return \EEH_Activation::getTableManager()->getTableColumns($table_name);
729
+	}
730
+
731
+
732
+	/**
733
+	 * db_table_is_empty
734
+	 *
735
+	 * @access     public\
736
+	 * @deprecated instead use TableAnalysis::tableIsEmpty()
737
+	 * @static
738
+	 * @param string $table_name
739
+	 * @return bool
740
+	 */
741
+	public static function db_table_is_empty($table_name)
742
+	{
743
+		return \EEH_Activation::getTableAnalysis()->tableIsEmpty($table_name);
744
+	}
745
+
746
+
747
+	/**
748
+	 * delete_db_table_if_empty
749
+	 *
750
+	 * @access public
751
+	 * @static
752
+	 * @param string $table_name
753
+	 * @return bool | int
754
+	 */
755
+	public static function delete_db_table_if_empty($table_name)
756
+	{
757
+		if (\EEH_Activation::getTableAnalysis()->tableIsEmpty($table_name)) {
758
+			return \EEH_Activation::getTableManager()->dropTable($table_name);
759
+		}
760
+		return false;
761
+	}
762
+
763
+
764
+	/**
765
+	 * delete_unused_db_table
766
+	 *
767
+	 * @access     public
768
+	 * @static
769
+	 * @deprecated instead use TableManager::dropTable()
770
+	 * @param string $table_name
771
+	 * @return bool | int
772
+	 */
773
+	public static function delete_unused_db_table($table_name)
774
+	{
775
+		return \EEH_Activation::getTableManager()->dropTable($table_name);
776
+	}
777
+
778
+
779
+	/**
780
+	 * drop_index
781
+	 *
782
+	 * @access     public
783
+	 * @static
784
+	 * @deprecated instead use TableManager::dropIndex()
785
+	 * @param string $table_name
786
+	 * @param string $index_name
787
+	 * @return bool | int
788
+	 */
789
+	public static function drop_index($table_name, $index_name)
790
+	{
791
+		return \EEH_Activation::getTableManager()->dropIndex($table_name, $index_name);
792
+	}
793
+
794
+
795
+
796
+	/**
797
+	 * create_database_tables
798
+	 *
799
+	 * @access public
800
+	 * @static
801
+	 * @throws EE_Error
802
+	 * @return boolean success (whether database is setup properly or not)
803
+	 */
804
+	public static function create_database_tables()
805
+	{
806
+		EE_Registry::instance()->load_core('Data_Migration_Manager');
807
+		//find the migration script that sets the database to be compatible with the code
808
+		$dms_name = EE_Data_Migration_Manager::instance()->get_most_up_to_date_dms();
809
+		if ($dms_name) {
810
+			$current_data_migration_script = EE_Registry::instance()->load_dms($dms_name);
811
+			$current_data_migration_script->set_migrating(false);
812
+			$current_data_migration_script->schema_changes_before_migration();
813
+			$current_data_migration_script->schema_changes_after_migration();
814
+			if ($current_data_migration_script->get_errors()) {
815
+				if (WP_DEBUG) {
816
+					foreach ($current_data_migration_script->get_errors() as $error) {
817
+						EE_Error::add_error($error, __FILE__, __FUNCTION__, __LINE__);
818
+					}
819
+				} else {
820
+					EE_Error::add_error(
821
+						__(
822
+							'There were errors creating the Event Espresso database tables and Event Espresso has been 
823 823
                             deactivated. To view the errors, please enable WP_DEBUG in your wp-config.php file.',
824
-                            'event_espresso'
825
-                        )
826
-                    );
827
-                }
828
-                return false;
829
-            }
830
-            EE_Data_Migration_Manager::instance()->update_current_database_state_to();
831
-        } else {
832
-            EE_Error::add_error(
833
-                __(
834
-                    'Could not determine most up-to-date data migration script from which to pull database schema
824
+							'event_espresso'
825
+						)
826
+					);
827
+				}
828
+				return false;
829
+			}
830
+			EE_Data_Migration_Manager::instance()->update_current_database_state_to();
831
+		} else {
832
+			EE_Error::add_error(
833
+				__(
834
+					'Could not determine most up-to-date data migration script from which to pull database schema
835 835
                      structure. So database is probably not setup properly',
836
-                    'event_espresso'
837
-                ),
838
-                __FILE__,
839
-                __FUNCTION__,
840
-                __LINE__
841
-            );
842
-            return false;
843
-        }
844
-        return true;
845
-    }
846
-
847
-
848
-
849
-    /**
850
-     * initialize_system_questions
851
-     *
852
-     * @access public
853
-     * @static
854
-     * @return void
855
-     */
856
-    public static function initialize_system_questions()
857
-    {
858
-        // QUESTION GROUPS
859
-        global $wpdb;
860
-        $table_name = \EEH_Activation::getTableAnalysis()->ensureTableNameHasPrefix('esp_question_group');
861
-        $SQL = "SELECT QSG_system FROM $table_name WHERE QSG_system != 0";
862
-        // what we have
863
-        $question_groups = $wpdb->get_col($SQL);
864
-        // check the response
865
-        $question_groups = is_array($question_groups) ? $question_groups : array();
866
-        // what we should have
867
-        $QSG_systems = array(1, 2);
868
-        // loop thru what we should have and compare to what we have
869
-        foreach ($QSG_systems as $QSG_system) {
870
-            // reset values array
871
-            $QSG_values = array();
872
-            // if we don't have what we should have (but use $QST_system as as string because that's what we got from the db)
873
-            if (! in_array("$QSG_system", $question_groups)) {
874
-                // add it
875
-                switch ($QSG_system) {
876
-                    case 1:
877
-                        $QSG_values = array(
878
-                            'QSG_name'            => __('Personal Information', 'event_espresso'),
879
-                            'QSG_identifier'      => 'personal-information-' . time(),
880
-                            'QSG_desc'            => '',
881
-                            'QSG_order'           => 1,
882
-                            'QSG_show_group_name' => 1,
883
-                            'QSG_show_group_desc' => 1,
884
-                            'QSG_system'          => EEM_Question_Group::system_personal,
885
-                            'QSG_deleted'         => 0,
886
-                        );
887
-                        break;
888
-                    case 2:
889
-                        $QSG_values = array(
890
-                            'QSG_name'            => __('Address Information', 'event_espresso'),
891
-                            'QSG_identifier'      => 'address-information-' . time(),
892
-                            'QSG_desc'            => '',
893
-                            'QSG_order'           => 2,
894
-                            'QSG_show_group_name' => 1,
895
-                            'QSG_show_group_desc' => 1,
896
-                            'QSG_system'          => EEM_Question_Group::system_address,
897
-                            'QSG_deleted'         => 0,
898
-                        );
899
-                        break;
900
-                }
901
-                // make sure we have some values before inserting them
902
-                if (! empty($QSG_values)) {
903
-                    // insert system question
904
-                    $wpdb->insert(
905
-                        $table_name,
906
-                        $QSG_values,
907
-                        array('%s', '%s', '%s', '%d', '%d', '%d', '%d', '%d')
908
-                    );
909
-                    $QSG_IDs[$QSG_system] = $wpdb->insert_id;
910
-                }
911
-            }
912
-        }
913
-        // QUESTIONS
914
-        global $wpdb;
915
-        $table_name = \EEH_Activation::getTableAnalysis()->ensureTableNameHasPrefix('esp_question');
916
-        $SQL = "SELECT QST_system FROM $table_name WHERE QST_system != ''";
917
-        // what we have
918
-        $questions = $wpdb->get_col($SQL);
919
-        // what we should have
920
-        $QST_systems = array(
921
-            'fname',
922
-            'lname',
923
-            'email',
924
-            'address',
925
-            'address2',
926
-            'city',
927
-            'country',
928
-            'state',
929
-            'zip',
930
-            'phone',
931
-        );
932
-        $order_for_group_1 = 1;
933
-        $order_for_group_2 = 1;
934
-        // loop thru what we should have and compare to what we have
935
-        foreach ($QST_systems as $QST_system) {
936
-            // reset values array
937
-            $QST_values = array();
938
-            // if we don't have what we should have
939
-            if (! in_array($QST_system, $questions)) {
940
-                // add it
941
-                switch ($QST_system) {
942
-                    case 'fname':
943
-                        $QST_values = array(
944
-                            'QST_display_text'  => __('First Name', 'event_espresso'),
945
-                            'QST_admin_label'   => __('First Name - System Question', 'event_espresso'),
946
-                            'QST_system'        => 'fname',
947
-                            'QST_type'          => 'TEXT',
948
-                            'QST_required'      => 1,
949
-                            'QST_required_text' => __('This field is required', 'event_espresso'),
950
-                            'QST_order'         => 1,
951
-                            'QST_admin_only'    => 0,
952
-                            'QST_max'           => EEM_Question::instance()->absolute_max_for_system_question($QST_system),
953
-                            'QST_wp_user'       => self::get_default_creator_id(),
954
-                            'QST_deleted'       => 0,
955
-                        );
956
-                        break;
957
-                    case 'lname':
958
-                        $QST_values = array(
959
-                            'QST_display_text'  => __('Last Name', 'event_espresso'),
960
-                            'QST_admin_label'   => __('Last Name - System Question', 'event_espresso'),
961
-                            'QST_system'        => 'lname',
962
-                            'QST_type'          => 'TEXT',
963
-                            'QST_required'      => 1,
964
-                            'QST_required_text' => __('This field is required', 'event_espresso'),
965
-                            'QST_order'         => 2,
966
-                            'QST_admin_only'    => 0,
967
-                            'QST_max'           => EEM_Question::instance()->absolute_max_for_system_question($QST_system),
968
-                            'QST_wp_user'       => self::get_default_creator_id(),
969
-                            'QST_deleted'       => 0,
970
-                        );
971
-                        break;
972
-                    case 'email':
973
-                        $QST_values = array(
974
-                            'QST_display_text'  => __('Email Address', 'event_espresso'),
975
-                            'QST_admin_label'   => __('Email Address - System Question', 'event_espresso'),
976
-                            'QST_system'        => 'email',
977
-                            'QST_type'          => 'EMAIL',
978
-                            'QST_required'      => 1,
979
-                            'QST_required_text' => __('This field is required', 'event_espresso'),
980
-                            'QST_order'         => 3,
981
-                            'QST_admin_only'    => 0,
982
-                            'QST_max'           => EEM_Question::instance()->absolute_max_for_system_question($QST_system),
983
-                            'QST_wp_user'       => self::get_default_creator_id(),
984
-                            'QST_deleted'       => 0,
985
-                        );
986
-                        break;
987
-                    case 'address':
988
-                        $QST_values = array(
989
-                            'QST_display_text'  => __('Address', 'event_espresso'),
990
-                            'QST_admin_label'   => __('Address - System Question', 'event_espresso'),
991
-                            'QST_system'        => 'address',
992
-                            'QST_type'          => 'TEXT',
993
-                            'QST_required'      => 0,
994
-                            'QST_required_text' => __('This field is required', 'event_espresso'),
995
-                            'QST_order'         => 4,
996
-                            'QST_admin_only'    => 0,
997
-                            'QST_max'           => EEM_Question::instance()->absolute_max_for_system_question($QST_system),
998
-                            'QST_wp_user'       => self::get_default_creator_id(),
999
-                            'QST_deleted'       => 0,
1000
-                        );
1001
-                        break;
1002
-                    case 'address2':
1003
-                        $QST_values = array(
1004
-                            'QST_display_text'  => __('Address2', 'event_espresso'),
1005
-                            'QST_admin_label'   => __('Address2 - System Question', 'event_espresso'),
1006
-                            'QST_system'        => 'address2',
1007
-                            'QST_type'          => 'TEXT',
1008
-                            'QST_required'      => 0,
1009
-                            'QST_required_text' => __('This field is required', 'event_espresso'),
1010
-                            'QST_order'         => 5,
1011
-                            'QST_admin_only'    => 0,
1012
-                            'QST_max'           => EEM_Question::instance()->absolute_max_for_system_question($QST_system),
1013
-                            'QST_wp_user'       => self::get_default_creator_id(),
1014
-                            'QST_deleted'       => 0,
1015
-                        );
1016
-                        break;
1017
-                    case 'city':
1018
-                        $QST_values = array(
1019
-                            'QST_display_text'  => __('City', 'event_espresso'),
1020
-                            'QST_admin_label'   => __('City - System Question', 'event_espresso'),
1021
-                            'QST_system'        => 'city',
1022
-                            'QST_type'          => 'TEXT',
1023
-                            'QST_required'      => 0,
1024
-                            'QST_required_text' => __('This field is required', 'event_espresso'),
1025
-                            'QST_order'         => 6,
1026
-                            'QST_admin_only'    => 0,
1027
-                            'QST_max'           => EEM_Question::instance()->absolute_max_for_system_question($QST_system),
1028
-                            'QST_wp_user'       => self::get_default_creator_id(),
1029
-                            'QST_deleted'       => 0,
1030
-                        );
1031
-                        break;
1032
-                    case 'country':
1033
-                        $QST_values = array(
1034
-                            'QST_display_text'  => __('Country', 'event_espresso'),
1035
-                            'QST_admin_label'   => __('Country - System Question', 'event_espresso'),
1036
-                            'QST_system'        => 'country',
1037
-                            'QST_type'          => 'COUNTRY',
1038
-                            'QST_required'      => 0,
1039
-                            'QST_required_text' => __('This field is required', 'event_espresso'),
1040
-                            'QST_order'         => 7,
1041
-                            'QST_admin_only'    => 0,
1042
-                            'QST_wp_user'       => self::get_default_creator_id(),
1043
-                            'QST_deleted'       => 0,
1044
-                        );
1045
-                        break;
1046
-                    case 'state':
1047
-                        $QST_values = array(
1048
-                            'QST_display_text'  => __('State/Province', 'event_espresso'),
1049
-                            'QST_admin_label'   => __('State/Province - System Question', 'event_espresso'),
1050
-                            'QST_system'        => 'state',
1051
-                            'QST_type'          => 'STATE',
1052
-                            'QST_required'      => 0,
1053
-                            'QST_required_text' => __('This field is required', 'event_espresso'),
1054
-                            'QST_order'         => 8,
1055
-                            'QST_admin_only'    => 0,
1056
-                            'QST_wp_user'       => self::get_default_creator_id(),
1057
-                            'QST_deleted'       => 0,
1058
-                        );
1059
-                        break;
1060
-                    case 'zip':
1061
-                        $QST_values = array(
1062
-                            'QST_display_text'  => __('Zip/Postal Code', 'event_espresso'),
1063
-                            'QST_admin_label'   => __('Zip/Postal Code - System Question', 'event_espresso'),
1064
-                            'QST_system'        => 'zip',
1065
-                            'QST_type'          => 'TEXT',
1066
-                            'QST_required'      => 0,
1067
-                            'QST_required_text' => __('This field is required', 'event_espresso'),
1068
-                            'QST_order'         => 9,
1069
-                            'QST_admin_only'    => 0,
1070
-                            'QST_max'           => EEM_Question::instance()->absolute_max_for_system_question($QST_system),
1071
-                            'QST_wp_user'       => self::get_default_creator_id(),
1072
-                            'QST_deleted'       => 0,
1073
-                        );
1074
-                        break;
1075
-                    case 'phone':
1076
-                        $QST_values = array(
1077
-                            'QST_display_text'  => __('Phone Number', 'event_espresso'),
1078
-                            'QST_admin_label'   => __('Phone Number - System Question', 'event_espresso'),
1079
-                            'QST_system'        => 'phone',
1080
-                            'QST_type'          => 'TEXT',
1081
-                            'QST_required'      => 0,
1082
-                            'QST_required_text' => __('This field is required', 'event_espresso'),
1083
-                            'QST_order'         => 10,
1084
-                            'QST_admin_only'    => 0,
1085
-                            'QST_max'           => EEM_Question::instance()->absolute_max_for_system_question($QST_system),
1086
-                            'QST_wp_user'       => self::get_default_creator_id(),
1087
-                            'QST_deleted'       => 0,
1088
-                        );
1089
-                        break;
1090
-                }
1091
-                if (! empty($QST_values)) {
1092
-                    // insert system question
1093
-                    $wpdb->insert(
1094
-                        $table_name,
1095
-                        $QST_values,
1096
-                        array('%s', '%s', '%s', '%s', '%d', '%s', '%d', '%d', '%d', '%d')
1097
-                    );
1098
-                    $QST_ID = $wpdb->insert_id;
1099
-                    // QUESTION GROUP QUESTIONS
1100
-                    if (in_array($QST_system, array('fname', 'lname', 'email'))) {
1101
-                        $system_question_we_want = EEM_Question_Group::system_personal;
1102
-                    } else {
1103
-                        $system_question_we_want = EEM_Question_Group::system_address;
1104
-                    }
1105
-                    if (isset($QSG_IDs[$system_question_we_want])) {
1106
-                        $QSG_ID = $QSG_IDs[$system_question_we_want];
1107
-                    } else {
1108
-                        $id_col = EEM_Question_Group::instance()
1109
-                                                    ->get_col(array(array('QSG_system' => $system_question_we_want)));
1110
-                        if (is_array($id_col)) {
1111
-                            $QSG_ID = reset($id_col);
1112
-                        } else {
1113
-                            //ok so we didn't find it in the db either?? that's weird because we should have inserted it at the start of this method
1114
-                            EE_Log::instance()->log(
1115
-                                __FILE__,
1116
-                                __FUNCTION__,
1117
-                                sprintf(
1118
-                                    __(
1119
-                                        'Could not associate question %1$s to a question group because no system question
836
+					'event_espresso'
837
+				),
838
+				__FILE__,
839
+				__FUNCTION__,
840
+				__LINE__
841
+			);
842
+			return false;
843
+		}
844
+		return true;
845
+	}
846
+
847
+
848
+
849
+	/**
850
+	 * initialize_system_questions
851
+	 *
852
+	 * @access public
853
+	 * @static
854
+	 * @return void
855
+	 */
856
+	public static function initialize_system_questions()
857
+	{
858
+		// QUESTION GROUPS
859
+		global $wpdb;
860
+		$table_name = \EEH_Activation::getTableAnalysis()->ensureTableNameHasPrefix('esp_question_group');
861
+		$SQL = "SELECT QSG_system FROM $table_name WHERE QSG_system != 0";
862
+		// what we have
863
+		$question_groups = $wpdb->get_col($SQL);
864
+		// check the response
865
+		$question_groups = is_array($question_groups) ? $question_groups : array();
866
+		// what we should have
867
+		$QSG_systems = array(1, 2);
868
+		// loop thru what we should have and compare to what we have
869
+		foreach ($QSG_systems as $QSG_system) {
870
+			// reset values array
871
+			$QSG_values = array();
872
+			// if we don't have what we should have (but use $QST_system as as string because that's what we got from the db)
873
+			if (! in_array("$QSG_system", $question_groups)) {
874
+				// add it
875
+				switch ($QSG_system) {
876
+					case 1:
877
+						$QSG_values = array(
878
+							'QSG_name'            => __('Personal Information', 'event_espresso'),
879
+							'QSG_identifier'      => 'personal-information-' . time(),
880
+							'QSG_desc'            => '',
881
+							'QSG_order'           => 1,
882
+							'QSG_show_group_name' => 1,
883
+							'QSG_show_group_desc' => 1,
884
+							'QSG_system'          => EEM_Question_Group::system_personal,
885
+							'QSG_deleted'         => 0,
886
+						);
887
+						break;
888
+					case 2:
889
+						$QSG_values = array(
890
+							'QSG_name'            => __('Address Information', 'event_espresso'),
891
+							'QSG_identifier'      => 'address-information-' . time(),
892
+							'QSG_desc'            => '',
893
+							'QSG_order'           => 2,
894
+							'QSG_show_group_name' => 1,
895
+							'QSG_show_group_desc' => 1,
896
+							'QSG_system'          => EEM_Question_Group::system_address,
897
+							'QSG_deleted'         => 0,
898
+						);
899
+						break;
900
+				}
901
+				// make sure we have some values before inserting them
902
+				if (! empty($QSG_values)) {
903
+					// insert system question
904
+					$wpdb->insert(
905
+						$table_name,
906
+						$QSG_values,
907
+						array('%s', '%s', '%s', '%d', '%d', '%d', '%d', '%d')
908
+					);
909
+					$QSG_IDs[$QSG_system] = $wpdb->insert_id;
910
+				}
911
+			}
912
+		}
913
+		// QUESTIONS
914
+		global $wpdb;
915
+		$table_name = \EEH_Activation::getTableAnalysis()->ensureTableNameHasPrefix('esp_question');
916
+		$SQL = "SELECT QST_system FROM $table_name WHERE QST_system != ''";
917
+		// what we have
918
+		$questions = $wpdb->get_col($SQL);
919
+		// what we should have
920
+		$QST_systems = array(
921
+			'fname',
922
+			'lname',
923
+			'email',
924
+			'address',
925
+			'address2',
926
+			'city',
927
+			'country',
928
+			'state',
929
+			'zip',
930
+			'phone',
931
+		);
932
+		$order_for_group_1 = 1;
933
+		$order_for_group_2 = 1;
934
+		// loop thru what we should have and compare to what we have
935
+		foreach ($QST_systems as $QST_system) {
936
+			// reset values array
937
+			$QST_values = array();
938
+			// if we don't have what we should have
939
+			if (! in_array($QST_system, $questions)) {
940
+				// add it
941
+				switch ($QST_system) {
942
+					case 'fname':
943
+						$QST_values = array(
944
+							'QST_display_text'  => __('First Name', 'event_espresso'),
945
+							'QST_admin_label'   => __('First Name - System Question', 'event_espresso'),
946
+							'QST_system'        => 'fname',
947
+							'QST_type'          => 'TEXT',
948
+							'QST_required'      => 1,
949
+							'QST_required_text' => __('This field is required', 'event_espresso'),
950
+							'QST_order'         => 1,
951
+							'QST_admin_only'    => 0,
952
+							'QST_max'           => EEM_Question::instance()->absolute_max_for_system_question($QST_system),
953
+							'QST_wp_user'       => self::get_default_creator_id(),
954
+							'QST_deleted'       => 0,
955
+						);
956
+						break;
957
+					case 'lname':
958
+						$QST_values = array(
959
+							'QST_display_text'  => __('Last Name', 'event_espresso'),
960
+							'QST_admin_label'   => __('Last Name - System Question', 'event_espresso'),
961
+							'QST_system'        => 'lname',
962
+							'QST_type'          => 'TEXT',
963
+							'QST_required'      => 1,
964
+							'QST_required_text' => __('This field is required', 'event_espresso'),
965
+							'QST_order'         => 2,
966
+							'QST_admin_only'    => 0,
967
+							'QST_max'           => EEM_Question::instance()->absolute_max_for_system_question($QST_system),
968
+							'QST_wp_user'       => self::get_default_creator_id(),
969
+							'QST_deleted'       => 0,
970
+						);
971
+						break;
972
+					case 'email':
973
+						$QST_values = array(
974
+							'QST_display_text'  => __('Email Address', 'event_espresso'),
975
+							'QST_admin_label'   => __('Email Address - System Question', 'event_espresso'),
976
+							'QST_system'        => 'email',
977
+							'QST_type'          => 'EMAIL',
978
+							'QST_required'      => 1,
979
+							'QST_required_text' => __('This field is required', 'event_espresso'),
980
+							'QST_order'         => 3,
981
+							'QST_admin_only'    => 0,
982
+							'QST_max'           => EEM_Question::instance()->absolute_max_for_system_question($QST_system),
983
+							'QST_wp_user'       => self::get_default_creator_id(),
984
+							'QST_deleted'       => 0,
985
+						);
986
+						break;
987
+					case 'address':
988
+						$QST_values = array(
989
+							'QST_display_text'  => __('Address', 'event_espresso'),
990
+							'QST_admin_label'   => __('Address - System Question', 'event_espresso'),
991
+							'QST_system'        => 'address',
992
+							'QST_type'          => 'TEXT',
993
+							'QST_required'      => 0,
994
+							'QST_required_text' => __('This field is required', 'event_espresso'),
995
+							'QST_order'         => 4,
996
+							'QST_admin_only'    => 0,
997
+							'QST_max'           => EEM_Question::instance()->absolute_max_for_system_question($QST_system),
998
+							'QST_wp_user'       => self::get_default_creator_id(),
999
+							'QST_deleted'       => 0,
1000
+						);
1001
+						break;
1002
+					case 'address2':
1003
+						$QST_values = array(
1004
+							'QST_display_text'  => __('Address2', 'event_espresso'),
1005
+							'QST_admin_label'   => __('Address2 - System Question', 'event_espresso'),
1006
+							'QST_system'        => 'address2',
1007
+							'QST_type'          => 'TEXT',
1008
+							'QST_required'      => 0,
1009
+							'QST_required_text' => __('This field is required', 'event_espresso'),
1010
+							'QST_order'         => 5,
1011
+							'QST_admin_only'    => 0,
1012
+							'QST_max'           => EEM_Question::instance()->absolute_max_for_system_question($QST_system),
1013
+							'QST_wp_user'       => self::get_default_creator_id(),
1014
+							'QST_deleted'       => 0,
1015
+						);
1016
+						break;
1017
+					case 'city':
1018
+						$QST_values = array(
1019
+							'QST_display_text'  => __('City', 'event_espresso'),
1020
+							'QST_admin_label'   => __('City - System Question', 'event_espresso'),
1021
+							'QST_system'        => 'city',
1022
+							'QST_type'          => 'TEXT',
1023
+							'QST_required'      => 0,
1024
+							'QST_required_text' => __('This field is required', 'event_espresso'),
1025
+							'QST_order'         => 6,
1026
+							'QST_admin_only'    => 0,
1027
+							'QST_max'           => EEM_Question::instance()->absolute_max_for_system_question($QST_system),
1028
+							'QST_wp_user'       => self::get_default_creator_id(),
1029
+							'QST_deleted'       => 0,
1030
+						);
1031
+						break;
1032
+					case 'country':
1033
+						$QST_values = array(
1034
+							'QST_display_text'  => __('Country', 'event_espresso'),
1035
+							'QST_admin_label'   => __('Country - System Question', 'event_espresso'),
1036
+							'QST_system'        => 'country',
1037
+							'QST_type'          => 'COUNTRY',
1038
+							'QST_required'      => 0,
1039
+							'QST_required_text' => __('This field is required', 'event_espresso'),
1040
+							'QST_order'         => 7,
1041
+							'QST_admin_only'    => 0,
1042
+							'QST_wp_user'       => self::get_default_creator_id(),
1043
+							'QST_deleted'       => 0,
1044
+						);
1045
+						break;
1046
+					case 'state':
1047
+						$QST_values = array(
1048
+							'QST_display_text'  => __('State/Province', 'event_espresso'),
1049
+							'QST_admin_label'   => __('State/Province - System Question', 'event_espresso'),
1050
+							'QST_system'        => 'state',
1051
+							'QST_type'          => 'STATE',
1052
+							'QST_required'      => 0,
1053
+							'QST_required_text' => __('This field is required', 'event_espresso'),
1054
+							'QST_order'         => 8,
1055
+							'QST_admin_only'    => 0,
1056
+							'QST_wp_user'       => self::get_default_creator_id(),
1057
+							'QST_deleted'       => 0,
1058
+						);
1059
+						break;
1060
+					case 'zip':
1061
+						$QST_values = array(
1062
+							'QST_display_text'  => __('Zip/Postal Code', 'event_espresso'),
1063
+							'QST_admin_label'   => __('Zip/Postal Code - System Question', 'event_espresso'),
1064
+							'QST_system'        => 'zip',
1065
+							'QST_type'          => 'TEXT',
1066
+							'QST_required'      => 0,
1067
+							'QST_required_text' => __('This field is required', 'event_espresso'),
1068
+							'QST_order'         => 9,
1069
+							'QST_admin_only'    => 0,
1070
+							'QST_max'           => EEM_Question::instance()->absolute_max_for_system_question($QST_system),
1071
+							'QST_wp_user'       => self::get_default_creator_id(),
1072
+							'QST_deleted'       => 0,
1073
+						);
1074
+						break;
1075
+					case 'phone':
1076
+						$QST_values = array(
1077
+							'QST_display_text'  => __('Phone Number', 'event_espresso'),
1078
+							'QST_admin_label'   => __('Phone Number - System Question', 'event_espresso'),
1079
+							'QST_system'        => 'phone',
1080
+							'QST_type'          => 'TEXT',
1081
+							'QST_required'      => 0,
1082
+							'QST_required_text' => __('This field is required', 'event_espresso'),
1083
+							'QST_order'         => 10,
1084
+							'QST_admin_only'    => 0,
1085
+							'QST_max'           => EEM_Question::instance()->absolute_max_for_system_question($QST_system),
1086
+							'QST_wp_user'       => self::get_default_creator_id(),
1087
+							'QST_deleted'       => 0,
1088
+						);
1089
+						break;
1090
+				}
1091
+				if (! empty($QST_values)) {
1092
+					// insert system question
1093
+					$wpdb->insert(
1094
+						$table_name,
1095
+						$QST_values,
1096
+						array('%s', '%s', '%s', '%s', '%d', '%s', '%d', '%d', '%d', '%d')
1097
+					);
1098
+					$QST_ID = $wpdb->insert_id;
1099
+					// QUESTION GROUP QUESTIONS
1100
+					if (in_array($QST_system, array('fname', 'lname', 'email'))) {
1101
+						$system_question_we_want = EEM_Question_Group::system_personal;
1102
+					} else {
1103
+						$system_question_we_want = EEM_Question_Group::system_address;
1104
+					}
1105
+					if (isset($QSG_IDs[$system_question_we_want])) {
1106
+						$QSG_ID = $QSG_IDs[$system_question_we_want];
1107
+					} else {
1108
+						$id_col = EEM_Question_Group::instance()
1109
+													->get_col(array(array('QSG_system' => $system_question_we_want)));
1110
+						if (is_array($id_col)) {
1111
+							$QSG_ID = reset($id_col);
1112
+						} else {
1113
+							//ok so we didn't find it in the db either?? that's weird because we should have inserted it at the start of this method
1114
+							EE_Log::instance()->log(
1115
+								__FILE__,
1116
+								__FUNCTION__,
1117
+								sprintf(
1118
+									__(
1119
+										'Could not associate question %1$s to a question group because no system question
1120 1120
                                          group existed',
1121
-                                        'event_espresso'
1122
-                                    ),
1123
-                                    $QST_ID),
1124
-                                'error');
1125
-                            continue;
1126
-                        }
1127
-                    }
1128
-                    // add system questions to groups
1129
-                    $wpdb->insert(
1130
-                        \EEH_Activation::getTableAnalysis()->ensureTableNameHasPrefix('esp_question_group_question'),
1131
-                        array(
1132
-                            'QSG_ID'    => $QSG_ID,
1133
-                            'QST_ID'    => $QST_ID,
1134
-                            'QGQ_order' => ($QSG_ID === 1) ? $order_for_group_1++ : $order_for_group_2++,
1135
-                        ),
1136
-                        array('%d', '%d', '%d')
1137
-                    );
1138
-                }
1139
-            }
1140
-        }
1141
-    }
1142
-
1143
-
1144
-    /**
1145
-     * Makes sure the default payment method (Invoice) is active.
1146
-     * This used to be done automatically as part of constructing the old gateways config
1147
-     *
1148
-     * @throws \EE_Error
1149
-     */
1150
-    public static function insert_default_payment_methods()
1151
-    {
1152
-        if (! EEM_Payment_Method::instance()->count_active(EEM_Payment_Method::scope_cart)) {
1153
-            EE_Registry::instance()->load_lib('Payment_Method_Manager');
1154
-            EE_Payment_Method_Manager::instance()->activate_a_payment_method_of_type('Invoice');
1155
-        } else {
1156
-            EEM_Payment_Method::instance()->verify_button_urls();
1157
-        }
1158
-    }
1159
-
1160
-    /**
1161
-     * insert_default_status_codes
1162
-     *
1163
-     * @access public
1164
-     * @static
1165
-     * @return void
1166
-     */
1167
-    public static function insert_default_status_codes()
1168
-    {
1169
-
1170
-        global $wpdb;
1171
-
1172
-        if (\EEH_Activation::getTableAnalysis()->tableExists(EEM_Status::instance()->table())) {
1173
-
1174
-            $table_name = EEM_Status::instance()->table();
1175
-
1176
-            $SQL = "DELETE FROM $table_name WHERE STS_ID IN ( 'ACT', 'NAC', 'NOP', 'OPN', 'CLS', 'PND', 'ONG', 'SEC', 'DRF', 'DEL', 'DEN', 'EXP', 'RPP', 'RCN', 'RDC', 'RAP', 'RNA', 'RWL', 'TAB', 'TIN', 'TFL', 'TCM', 'TOP', 'PAP', 'PCN', 'PFL', 'PDC', 'EDR', 'ESN', 'PPN', 'RIC', 'MSN', 'MFL', 'MID', 'MRS', 'MIC', 'MDO', 'MEX' );";
1177
-            $wpdb->query($SQL);
1178
-
1179
-            $SQL = "INSERT INTO $table_name
1121
+										'event_espresso'
1122
+									),
1123
+									$QST_ID),
1124
+								'error');
1125
+							continue;
1126
+						}
1127
+					}
1128
+					// add system questions to groups
1129
+					$wpdb->insert(
1130
+						\EEH_Activation::getTableAnalysis()->ensureTableNameHasPrefix('esp_question_group_question'),
1131
+						array(
1132
+							'QSG_ID'    => $QSG_ID,
1133
+							'QST_ID'    => $QST_ID,
1134
+							'QGQ_order' => ($QSG_ID === 1) ? $order_for_group_1++ : $order_for_group_2++,
1135
+						),
1136
+						array('%d', '%d', '%d')
1137
+					);
1138
+				}
1139
+			}
1140
+		}
1141
+	}
1142
+
1143
+
1144
+	/**
1145
+	 * Makes sure the default payment method (Invoice) is active.
1146
+	 * This used to be done automatically as part of constructing the old gateways config
1147
+	 *
1148
+	 * @throws \EE_Error
1149
+	 */
1150
+	public static function insert_default_payment_methods()
1151
+	{
1152
+		if (! EEM_Payment_Method::instance()->count_active(EEM_Payment_Method::scope_cart)) {
1153
+			EE_Registry::instance()->load_lib('Payment_Method_Manager');
1154
+			EE_Payment_Method_Manager::instance()->activate_a_payment_method_of_type('Invoice');
1155
+		} else {
1156
+			EEM_Payment_Method::instance()->verify_button_urls();
1157
+		}
1158
+	}
1159
+
1160
+	/**
1161
+	 * insert_default_status_codes
1162
+	 *
1163
+	 * @access public
1164
+	 * @static
1165
+	 * @return void
1166
+	 */
1167
+	public static function insert_default_status_codes()
1168
+	{
1169
+
1170
+		global $wpdb;
1171
+
1172
+		if (\EEH_Activation::getTableAnalysis()->tableExists(EEM_Status::instance()->table())) {
1173
+
1174
+			$table_name = EEM_Status::instance()->table();
1175
+
1176
+			$SQL = "DELETE FROM $table_name WHERE STS_ID IN ( 'ACT', 'NAC', 'NOP', 'OPN', 'CLS', 'PND', 'ONG', 'SEC', 'DRF', 'DEL', 'DEN', 'EXP', 'RPP', 'RCN', 'RDC', 'RAP', 'RNA', 'RWL', 'TAB', 'TIN', 'TFL', 'TCM', 'TOP', 'PAP', 'PCN', 'PFL', 'PDC', 'EDR', 'ESN', 'PPN', 'RIC', 'MSN', 'MFL', 'MID', 'MRS', 'MIC', 'MDO', 'MEX' );";
1177
+			$wpdb->query($SQL);
1178
+
1179
+			$SQL = "INSERT INTO $table_name
1180 1180
 					(STS_ID, STS_code, STS_type, STS_can_edit, STS_desc, STS_open) VALUES
1181 1181
 					('ACT', 'ACTIVE', 'event', 0, NULL, 1),
1182 1182
 					('NAC', 'NOT_ACTIVE', 'event', 0, NULL, 0),
@@ -1216,523 +1216,523 @@  discard block
 block discarded – undo
1216 1216
 					('MID', 'IDLE', 'message', 0, NULL, 1),
1217 1217
 					('MRS', 'RESEND', 'message', 0, NULL, 1),
1218 1218
 					('MIC', 'INCOMPLETE', 'message', 0, NULL, 0);";
1219
-            $wpdb->query($SQL);
1220
-
1221
-        }
1222
-
1223
-    }
1224
-
1225
-
1226
-    /**
1227
-     * create_upload_directories
1228
-     * Creates folders in the uploads directory to facilitate addons and templates
1229
-     *
1230
-     * @access public
1231
-     * @static
1232
-     * @return boolean success of verifying upload directories exist
1233
-     */
1234
-    public static function create_upload_directories()
1235
-    {
1236
-        // Create the required folders
1237
-        $folders = array(
1238
-            EVENT_ESPRESSO_TEMPLATE_DIR,
1239
-            EVENT_ESPRESSO_GATEWAY_DIR,
1240
-            EVENT_ESPRESSO_UPLOAD_DIR . 'logs/',
1241
-            EVENT_ESPRESSO_UPLOAD_DIR . 'css/',
1242
-            EVENT_ESPRESSO_UPLOAD_DIR . 'tickets/',
1243
-        );
1244
-        foreach ($folders as $folder) {
1245
-            try {
1246
-                EEH_File::ensure_folder_exists_and_is_writable($folder);
1247
-                @ chmod($folder, 0755);
1248
-            } catch (EE_Error $e) {
1249
-                EE_Error::add_error(
1250
-                    sprintf(
1251
-                        __('Could not create the folder at "%1$s" because: %2$s', 'event_espresso'),
1252
-                        $folder,
1253
-                        '<br />' . $e->getMessage()
1254
-                    ),
1255
-                    __FILE__, __FUNCTION__, __LINE__
1256
-                );
1257
-                //indicate we'll need to fix this later
1258
-                update_option(EEH_Activation::upload_directories_incomplete_option_name, true);
1259
-                return false;
1260
-            }
1261
-        }
1262
-        //just add the .htaccess file to the logs directory to begin with. Even if logging
1263
-        //is disabled, there might be activation errors recorded in there
1264
-        EEH_File::add_htaccess_deny_from_all(EVENT_ESPRESSO_UPLOAD_DIR . 'logs/');
1265
-        //remember EE's folders are all good
1266
-        delete_option(EEH_Activation::upload_directories_incomplete_option_name);
1267
-        return true;
1268
-    }
1269
-
1270
-    /**
1271
-     * Whether the upload directories need to be fixed or not.
1272
-     * If EE is installed but filesystem access isn't initially available,
1273
-     * we need to get the user's filesystem credentials and THEN create them,
1274
-     * so there might be period of time when EE is installed but its
1275
-     * upload directories aren't available. This indicates such a state
1276
-     *
1277
-     * @return boolean
1278
-     */
1279
-    public static function upload_directories_incomplete()
1280
-    {
1281
-        return get_option(EEH_Activation::upload_directories_incomplete_option_name, false);
1282
-    }
1283
-
1284
-
1285
-    /**
1286
-     * generate_default_message_templates
1287
-     *
1288
-     * @static
1289
-     * @throws EE_Error
1290
-     * @return bool     true means new templates were created.
1291
-     *                  false means no templates were created.
1292
-     *                  This is NOT an error flag. To check for errors you will want
1293
-     *                  to use either EE_Error or a try catch for an EE_Error exception.
1294
-     */
1295
-    public static function generate_default_message_templates()
1296
-    {
1297
-        /** @type EE_Message_Resource_Manager $message_resource_manager */
1298
-        $message_resource_manager = EE_Registry::instance()->load_lib('Message_Resource_Manager');
1299
-        /*
1219
+			$wpdb->query($SQL);
1220
+
1221
+		}
1222
+
1223
+	}
1224
+
1225
+
1226
+	/**
1227
+	 * create_upload_directories
1228
+	 * Creates folders in the uploads directory to facilitate addons and templates
1229
+	 *
1230
+	 * @access public
1231
+	 * @static
1232
+	 * @return boolean success of verifying upload directories exist
1233
+	 */
1234
+	public static function create_upload_directories()
1235
+	{
1236
+		// Create the required folders
1237
+		$folders = array(
1238
+			EVENT_ESPRESSO_TEMPLATE_DIR,
1239
+			EVENT_ESPRESSO_GATEWAY_DIR,
1240
+			EVENT_ESPRESSO_UPLOAD_DIR . 'logs/',
1241
+			EVENT_ESPRESSO_UPLOAD_DIR . 'css/',
1242
+			EVENT_ESPRESSO_UPLOAD_DIR . 'tickets/',
1243
+		);
1244
+		foreach ($folders as $folder) {
1245
+			try {
1246
+				EEH_File::ensure_folder_exists_and_is_writable($folder);
1247
+				@ chmod($folder, 0755);
1248
+			} catch (EE_Error $e) {
1249
+				EE_Error::add_error(
1250
+					sprintf(
1251
+						__('Could not create the folder at "%1$s" because: %2$s', 'event_espresso'),
1252
+						$folder,
1253
+						'<br />' . $e->getMessage()
1254
+					),
1255
+					__FILE__, __FUNCTION__, __LINE__
1256
+				);
1257
+				//indicate we'll need to fix this later
1258
+				update_option(EEH_Activation::upload_directories_incomplete_option_name, true);
1259
+				return false;
1260
+			}
1261
+		}
1262
+		//just add the .htaccess file to the logs directory to begin with. Even if logging
1263
+		//is disabled, there might be activation errors recorded in there
1264
+		EEH_File::add_htaccess_deny_from_all(EVENT_ESPRESSO_UPLOAD_DIR . 'logs/');
1265
+		//remember EE's folders are all good
1266
+		delete_option(EEH_Activation::upload_directories_incomplete_option_name);
1267
+		return true;
1268
+	}
1269
+
1270
+	/**
1271
+	 * Whether the upload directories need to be fixed or not.
1272
+	 * If EE is installed but filesystem access isn't initially available,
1273
+	 * we need to get the user's filesystem credentials and THEN create them,
1274
+	 * so there might be period of time when EE is installed but its
1275
+	 * upload directories aren't available. This indicates such a state
1276
+	 *
1277
+	 * @return boolean
1278
+	 */
1279
+	public static function upload_directories_incomplete()
1280
+	{
1281
+		return get_option(EEH_Activation::upload_directories_incomplete_option_name, false);
1282
+	}
1283
+
1284
+
1285
+	/**
1286
+	 * generate_default_message_templates
1287
+	 *
1288
+	 * @static
1289
+	 * @throws EE_Error
1290
+	 * @return bool     true means new templates were created.
1291
+	 *                  false means no templates were created.
1292
+	 *                  This is NOT an error flag. To check for errors you will want
1293
+	 *                  to use either EE_Error or a try catch for an EE_Error exception.
1294
+	 */
1295
+	public static function generate_default_message_templates()
1296
+	{
1297
+		/** @type EE_Message_Resource_Manager $message_resource_manager */
1298
+		$message_resource_manager = EE_Registry::instance()->load_lib('Message_Resource_Manager');
1299
+		/*
1300 1300
          * This first method is taking care of ensuring any default messengers
1301 1301
          * that should be made active and have templates generated are done.
1302 1302
          */
1303
-        $new_templates_created_for_messenger = self::_activate_and_generate_default_messengers_and_message_templates(
1304
-            $message_resource_manager
1305
-        );
1306
-        /**
1307
-         * This method is verifying there are no NEW default message types
1308
-         * for ACTIVE messengers that need activated (and corresponding templates setup).
1309
-         */
1310
-        $new_templates_created_for_message_type = self::_activate_new_message_types_for_active_messengers_and_generate_default_templates(
1311
-            $message_resource_manager
1312
-        );
1313
-        //after all is done, let's persist these changes to the db.
1314
-        $message_resource_manager->update_has_activated_messengers_option();
1315
-        $message_resource_manager->update_active_messengers_option();
1316
-        // will return true if either of these are true.  Otherwise will return false.
1317
-        return $new_templates_created_for_message_type || $new_templates_created_for_messenger;
1318
-    }
1319
-
1320
-
1321
-
1322
-    /**
1323
-     * @param \EE_Message_Resource_Manager $message_resource_manager
1324
-     * @return array|bool
1325
-     * @throws \EE_Error
1326
-     */
1327
-    protected static function _activate_new_message_types_for_active_messengers_and_generate_default_templates(
1328
-        EE_Message_Resource_Manager $message_resource_manager
1329
-    ) {
1330
-        /** @type EE_messenger[] $active_messengers */
1331
-        $active_messengers = $message_resource_manager->active_messengers();
1332
-        $installed_message_types = $message_resource_manager->installed_message_types();
1333
-        $templates_created = false;
1334
-        foreach ($active_messengers as $active_messenger) {
1335
-            $default_message_type_names_for_messenger = $active_messenger->get_default_message_types();
1336
-            $default_message_type_names_to_activate = array();
1337
-            // looping through each default message type reported by the messenger
1338
-            // and setup the actual message types to activate.
1339
-            foreach ($default_message_type_names_for_messenger as $default_message_type_name_for_messenger) {
1340
-                // if already active or has already been activated before we skip
1341
-                // (otherwise we might reactivate something user's intentionally deactivated.)
1342
-                // we also skip if the message type is not installed.
1343
-                if (
1344
-                    $message_resource_manager->has_message_type_been_activated_for_messenger(
1345
-                        $default_message_type_name_for_messenger,
1346
-                        $active_messenger->name
1347
-                    )
1348
-                    || $message_resource_manager->is_message_type_active_for_messenger(
1349
-                        $active_messenger->name,
1350
-                        $default_message_type_name_for_messenger
1351
-                    )
1352
-                    || ! isset($installed_message_types[$default_message_type_name_for_messenger])
1353
-                ) {
1354
-                    continue;
1355
-                }
1356
-                $default_message_type_names_to_activate[] = $default_message_type_name_for_messenger;
1357
-            }
1358
-            //let's activate!
1359
-            $message_resource_manager->ensure_message_types_are_active(
1360
-                $default_message_type_names_to_activate,
1361
-                $active_messenger->name,
1362
-                false
1363
-            );
1364
-            //activate the templates for these message types
1365
-            if ( ! empty($default_message_type_names_to_activate)) {
1366
-                $templates_created = EEH_MSG_Template::generate_new_templates(
1367
-                    $active_messenger->name,
1368
-                    $default_message_type_names_for_messenger,
1369
-                    '',
1370
-                    true
1371
-                );
1372
-            }
1373
-        }
1374
-        return $templates_created;
1375
-    }
1376
-
1377
-
1378
-
1379
-    /**
1380
-     * This will activate and generate default messengers and default message types for those messengers.
1381
-     *
1382
-     * @param EE_message_Resource_Manager $message_resource_manager
1383
-     * @return array|bool  True means there were default messengers and message type templates generated.
1384
-     *                     False means that there were no templates generated
1385
-     *                     (which could simply mean there are no default message types for a messenger).
1386
-     * @throws EE_Error
1387
-     */
1388
-    protected static function _activate_and_generate_default_messengers_and_message_templates(
1389
-        EE_Message_Resource_Manager $message_resource_manager
1390
-    ) {
1391
-        /** @type EE_messenger[] $messengers_to_generate */
1392
-        $messengers_to_generate = self::_get_default_messengers_to_generate_on_activation($message_resource_manager);
1393
-        $installed_message_types = $message_resource_manager->installed_message_types();
1394
-        $templates_generated = false;
1395
-        foreach ($messengers_to_generate as $messenger_to_generate) {
1396
-            $default_message_type_names_for_messenger = $messenger_to_generate->get_default_message_types();
1397
-            //verify the default message types match an installed message type.
1398
-            foreach ($default_message_type_names_for_messenger as $key => $name) {
1399
-                if (
1400
-                    ! isset($installed_message_types[$name])
1401
-                    || $message_resource_manager->has_message_type_been_activated_for_messenger(
1402
-                        $name,
1403
-                        $messenger_to_generate->name
1404
-                    )
1405
-                ) {
1406
-                    unset($default_message_type_names_for_messenger[$key]);
1407
-                }
1408
-            }
1409
-            // in previous iterations, the active_messengers option in the db
1410
-            // needed updated before calling create templates. however with the changes this may not be necessary.
1411
-            // This comment is left here just in case we discover that we _do_ need to update before
1412
-            // passing off to create templates (after the refactor is done).
1413
-            // @todo remove this comment when determined not necessary.
1414
-            $message_resource_manager->activate_messenger(
1415
-                $messenger_to_generate->name,
1416
-                $default_message_type_names_for_messenger,
1417
-                false
1418
-            );
1419
-            //create any templates needing created (or will reactivate templates already generated as necessary).
1420
-            if ( ! empty($default_message_type_names_for_messenger)) {
1421
-                $templates_generated = EEH_MSG_Template::generate_new_templates(
1422
-                    $messenger_to_generate->name,
1423
-                    $default_message_type_names_for_messenger,
1424
-                    '',
1425
-                    true
1426
-                );
1427
-            }
1428
-        }
1429
-        return $templates_generated;
1430
-    }
1431
-
1432
-
1433
-    /**
1434
-     * This returns the default messengers to generate templates for on activation of EE.
1435
-     * It considers:
1436
-     * - whether a messenger is already active in the db.
1437
-     * - whether a messenger has been made active at any time in the past.
1438
-     *
1439
-     * @static
1440
-     * @param  EE_Message_Resource_Manager $message_resource_manager
1441
-     * @return EE_messenger[]
1442
-     */
1443
-    protected static function _get_default_messengers_to_generate_on_activation(
1444
-        EE_Message_Resource_Manager $message_resource_manager
1445
-    ) {
1446
-        // make sure EED_Messages is loaded because it sets the autoloaders
1447
-        require_once EE_MODULES . 'messages' . DS . 'EED_Messages.module.php';
1448
-        $active_messengers    = $message_resource_manager->active_messengers();
1449
-        $installed_messengers = $message_resource_manager->installed_messengers();
1450
-        $has_activated        = $message_resource_manager->get_has_activated_messengers_option();
1451
-
1452
-        $messengers_to_generate = array();
1453
-        foreach ($installed_messengers as $installed_messenger) {
1454
-            //if installed messenger is a messenger that should be activated on install
1455
-            //and is not already active
1456
-            //and has never been activated
1457
-            if (
1458
-                ! $installed_messenger->activate_on_install
1459
-                || isset($active_messengers[$installed_messenger->name])
1460
-                || isset($has_activated[$installed_messenger->name])
1461
-            ) {
1462
-                continue;
1463
-            }
1464
-            $messengers_to_generate[$installed_messenger->name] = $installed_messenger;
1465
-        }
1466
-        return $messengers_to_generate;
1467
-    }
1468
-
1469
-
1470
-    /**
1471
-     * This simply validates active message types to ensure they actually match installed
1472
-     * message types.  If there's a mismatch then we deactivate the message type and ensure all related db
1473
-     * rows are set inactive.
1474
-     * Note: Messengers are no longer validated here as of 4.9.0 because they get validated automatically whenever
1475
-     * EE_Messenger_Resource_Manager is constructed.  Message Types are a bit more resource heavy for validation so they
1476
-     * are still handled in here.
1477
-     *
1478
-     * @since 4.3.1
1479
-     * @return void
1480
-     */
1481
-    public static function validate_messages_system()
1482
-    {
1483
-        /** @type EE_Message_Resource_Manager $message_resource_manager */
1484
-        $message_resource_manager = EE_Registry::instance()->load_lib('Message_Resource_Manager');
1485
-        $message_resource_manager->validate_active_message_types_are_installed();
1486
-        do_action('AHEE__EEH_Activation__validate_messages_system');
1487
-    }
1488
-
1489
-
1490
-    /**
1491
-     * create_no_ticket_prices_array
1492
-     *
1493
-     * @access public
1494
-     * @static
1495
-     * @return void
1496
-     */
1497
-    public static function create_no_ticket_prices_array()
1498
-    {
1499
-        // this creates an array for tracking events that have no active ticket prices created
1500
-        // this allows us to warn admins of the situation so that it can be corrected
1501
-        $espresso_no_ticket_prices = get_option('ee_no_ticket_prices', false);
1502
-        if (! $espresso_no_ticket_prices) {
1503
-            add_option('ee_no_ticket_prices', array(), '', false);
1504
-        }
1505
-    }
1506
-
1507
-
1508
-    /**
1509
-     * plugin_deactivation
1510
-     *
1511
-     * @access public
1512
-     * @static
1513
-     * @return void
1514
-     */
1515
-    public static function plugin_deactivation()
1516
-    {
1517
-    }
1518
-
1519
-
1520
-    /**
1521
-     * Finds all our EE4 custom post types, and deletes them and their associated data
1522
-     * (like post meta or term relations)
1523
-     *
1524
-     * @global wpdb $wpdb
1525
-     * @throws \EE_Error
1526
-     */
1527
-    public static function delete_all_espresso_cpt_data()
1528
-    {
1529
-        global $wpdb;
1530
-        //get all the CPT post_types
1531
-        $ee_post_types = array();
1532
-        foreach (EE_Registry::instance()->non_abstract_db_models as $model_name) {
1533
-            if (method_exists($model_name, 'instance')) {
1534
-                $model_obj = call_user_func(array($model_name, 'instance'));
1535
-                if ($model_obj instanceof EEM_CPT_Base) {
1536
-                    $ee_post_types[] = $wpdb->prepare("%s", $model_obj->post_type());
1537
-                }
1538
-            }
1539
-        }
1540
-        //get all our CPTs
1541
-        $query   = "SELECT ID FROM {$wpdb->posts} WHERE post_type IN (" . implode(",", $ee_post_types) . ")";
1542
-        $cpt_ids = $wpdb->get_col($query);
1543
-        //delete each post meta and term relations too
1544
-        foreach ($cpt_ids as $post_id) {
1545
-            wp_delete_post($post_id, true);
1546
-        }
1547
-    }
1548
-
1549
-    /**
1550
-     * Deletes all EE custom tables
1551
-     *
1552
-     * @return array
1553
-     */
1554
-    public static function drop_espresso_tables()
1555
-    {
1556
-        $tables = array();
1557
-        // load registry
1558
-        foreach (EE_Registry::instance()->non_abstract_db_models as $model_name) {
1559
-            if (method_exists($model_name, 'instance')) {
1560
-                $model_obj = call_user_func(array($model_name, 'instance'));
1561
-                if ($model_obj instanceof EEM_Base) {
1562
-                    foreach ($model_obj->get_tables() as $table) {
1563
-                        if (strpos($table->get_table_name(), 'esp_')
1564
-                            &&
1565
-                            (
1566
-                                is_main_site()//main site? nuke them all
1567
-                                || ! $table->is_global()//not main site,but not global either. nuke it
1568
-                            )
1569
-                        ) {
1570
-                            $tables[$table->get_table_name()] = $table->get_table_name();
1571
-                        }
1572
-                    }
1573
-                }
1574
-            }
1575
-        }
1576
-
1577
-        //there are some tables whose models were removed.
1578
-        //they should be removed when removing all EE core's data
1579
-        $tables_without_models = array(
1580
-            'esp_promotion',
1581
-            'esp_promotion_applied',
1582
-            'esp_promotion_object',
1583
-            'esp_promotion_rule',
1584
-            'esp_rule',
1585
-        );
1586
-        foreach ($tables_without_models as $table) {
1587
-            $tables[$table] = $table;
1588
-        }
1589
-        return \EEH_Activation::getTableManager()->dropTables($tables);
1590
-    }
1591
-
1592
-
1593
-
1594
-    /**
1595
-     * Drops all the tables mentioned in a single MYSQL query. Double-checks
1596
-     * each table name provided has a wpdb prefix attached, and that it exists.
1597
-     * Returns the list actually deleted
1598
-     *
1599
-     * @deprecated in 4.9.13. Instead use TableManager::dropTables()
1600
-     * @global WPDB $wpdb
1601
-     * @param array $table_names
1602
-     * @return array of table names which we deleted
1603
-     */
1604
-    public static function drop_tables($table_names)
1605
-    {
1606
-        return \EEH_Activation::getTableManager()->dropTables($table_names);
1607
-    }
1608
-
1609
-
1610
-
1611
-    /**
1612
-     * plugin_uninstall
1613
-     *
1614
-     * @access public
1615
-     * @static
1616
-     * @param bool $remove_all
1617
-     * @return void
1618
-     */
1619
-    public static function delete_all_espresso_tables_and_data($remove_all = true)
1620
-    {
1621
-        global $wpdb;
1622
-        self::drop_espresso_tables();
1623
-        $wp_options_to_delete = array(
1624
-            'ee_no_ticket_prices'                => true,
1625
-            'ee_active_messengers'               => true,
1626
-            'ee_has_activated_messenger'         => true,
1627
-            'ee_flush_rewrite_rules'             => true,
1628
-            'ee_config'                          => false,
1629
-            'ee_data_migration_current_db_state' => true,
1630
-            'ee_data_migration_mapping_'         => false,
1631
-            'ee_data_migration_script_'          => false,
1632
-            'ee_data_migrations'                 => true,
1633
-            'ee_dms_map'                         => false,
1634
-            'ee_notices'                         => true,
1635
-            'lang_file_check_'                   => false,
1636
-            'ee_maintenance_mode'                => true,
1637
-            'ee_ueip_optin'                      => true,
1638
-            'ee_ueip_has_notified'               => true,
1639
-            'ee_plugin_activation_errors'        => true,
1640
-            'ee_id_mapping_from'                 => false,
1641
-            'espresso_persistent_admin_notices'  => true,
1642
-            'ee_encryption_key'                  => true,
1643
-            'pue_force_upgrade_'                 => false,
1644
-            'pue_json_error_'                    => false,
1645
-            'pue_install_key_'                   => false,
1646
-            'pue_verification_error_'            => false,
1647
-            'pu_dismissed_upgrade_'              => false,
1648
-            'external_updates-'                  => false,
1649
-            'ee_extra_data'                      => true,
1650
-            'ee_ssn_'                            => false,
1651
-            'ee_rss_'                            => false,
1652
-            'ee_rte_n_tx_'                       => false,
1653
-            'ee_pers_admin_notices'              => true,
1654
-            'ee_job_parameters_'                 => false,
1655
-            'ee_upload_directories_incomplete'   => true,
1656
-            'ee_verified_db_collations'          => true,
1657
-        );
1658
-        if (is_main_site()) {
1659
-            $wp_options_to_delete['ee_network_config'] = true;
1660
-        }
1661
-        $undeleted_options = array();
1662
-        foreach ($wp_options_to_delete as $option_name => $no_wildcard) {
1663
-            if ($no_wildcard) {
1664
-                if ( ! delete_option($option_name)) {
1665
-                    $undeleted_options[] = $option_name;
1666
-                }
1667
-            } else {
1668
-                $option_names_to_delete_from_wildcard = $wpdb->get_col("SELECT option_name FROM $wpdb->options WHERE option_name LIKE '%$option_name%'");
1669
-                foreach ($option_names_to_delete_from_wildcard as $option_name_from_wildcard) {
1670
-                    if ( ! delete_option($option_name_from_wildcard)) {
1671
-                        $undeleted_options[] = $option_name_from_wildcard;
1672
-                    }
1673
-                }
1674
-            }
1675
-        }
1676
-        //also, let's make sure the "ee_config_option_names" wp option stays out by removing the action that adds it
1677
-        remove_action('shutdown', array(EE_Config::instance(), 'shutdown'), 10);
1678
-        if ($remove_all && $espresso_db_update = get_option('espresso_db_update')) {
1679
-            $db_update_sans_ee4 = array();
1680
-            foreach ($espresso_db_update as $version => $times_activated) {
1681
-                if ((string)$version[0] === '3') {//if its NON EE4
1682
-                    $db_update_sans_ee4[$version] = $times_activated;
1683
-                }
1684
-            }
1685
-            update_option('espresso_db_update', $db_update_sans_ee4);
1686
-        }
1687
-        $errors = '';
1688
-        if ( ! empty($undeleted_options)) {
1689
-            $errors .= sprintf(
1690
-                __('The following wp-options could not be deleted: %s%s', 'event_espresso'),
1691
-                '<br/>',
1692
-                implode(',<br/>', $undeleted_options)
1693
-            );
1694
-        }
1695
-        if ( ! empty($errors)) {
1696
-            EE_Error::add_attention($errors, __FILE__, __FUNCTION__, __LINE__);
1697
-        }
1698
-    }
1699
-
1700
-    /**
1701
-     * Gets the mysql error code from the last used query by wpdb
1702
-     *
1703
-     * @return int mysql error code, see https://dev.mysql.com/doc/refman/5.5/en/error-messages-server.html
1704
-     */
1705
-    public static function last_wpdb_error_code()
1706
-    {
1707
-        global $wpdb;
1708
-        if ($wpdb->use_mysqli) {
1709
-            return mysqli_errno($wpdb->dbh);
1710
-        } else {
1711
-            return mysql_errno($wpdb->dbh);
1712
-        }
1713
-    }
1714
-
1715
-    /**
1716
-     * Checks that the database table exists. Also works on temporary tables (for unit tests mostly).
1717
-     *
1718
-     * @global wpdb  $wpdb
1719
-     * @deprecated instead use TableAnalysis::tableExists()
1720
-     * @param string $table_name with or without $wpdb->prefix
1721
-     * @return boolean
1722
-     */
1723
-    public static function table_exists($table_name)
1724
-    {
1725
-        return \EEH_Activation::getTableAnalysis()->tableExists($table_name);
1726
-    }
1727
-
1728
-    /**
1729
-     * Resets the cache on EEH_Activation
1730
-     */
1731
-    public static function reset()
1732
-    {
1733
-        self::$_default_creator_id                             = null;
1734
-        self::$_initialized_db_content_already_in_this_request = false;
1735
-    }
1303
+		$new_templates_created_for_messenger = self::_activate_and_generate_default_messengers_and_message_templates(
1304
+			$message_resource_manager
1305
+		);
1306
+		/**
1307
+		 * This method is verifying there are no NEW default message types
1308
+		 * for ACTIVE messengers that need activated (and corresponding templates setup).
1309
+		 */
1310
+		$new_templates_created_for_message_type = self::_activate_new_message_types_for_active_messengers_and_generate_default_templates(
1311
+			$message_resource_manager
1312
+		);
1313
+		//after all is done, let's persist these changes to the db.
1314
+		$message_resource_manager->update_has_activated_messengers_option();
1315
+		$message_resource_manager->update_active_messengers_option();
1316
+		// will return true if either of these are true.  Otherwise will return false.
1317
+		return $new_templates_created_for_message_type || $new_templates_created_for_messenger;
1318
+	}
1319
+
1320
+
1321
+
1322
+	/**
1323
+	 * @param \EE_Message_Resource_Manager $message_resource_manager
1324
+	 * @return array|bool
1325
+	 * @throws \EE_Error
1326
+	 */
1327
+	protected static function _activate_new_message_types_for_active_messengers_and_generate_default_templates(
1328
+		EE_Message_Resource_Manager $message_resource_manager
1329
+	) {
1330
+		/** @type EE_messenger[] $active_messengers */
1331
+		$active_messengers = $message_resource_manager->active_messengers();
1332
+		$installed_message_types = $message_resource_manager->installed_message_types();
1333
+		$templates_created = false;
1334
+		foreach ($active_messengers as $active_messenger) {
1335
+			$default_message_type_names_for_messenger = $active_messenger->get_default_message_types();
1336
+			$default_message_type_names_to_activate = array();
1337
+			// looping through each default message type reported by the messenger
1338
+			// and setup the actual message types to activate.
1339
+			foreach ($default_message_type_names_for_messenger as $default_message_type_name_for_messenger) {
1340
+				// if already active or has already been activated before we skip
1341
+				// (otherwise we might reactivate something user's intentionally deactivated.)
1342
+				// we also skip if the message type is not installed.
1343
+				if (
1344
+					$message_resource_manager->has_message_type_been_activated_for_messenger(
1345
+						$default_message_type_name_for_messenger,
1346
+						$active_messenger->name
1347
+					)
1348
+					|| $message_resource_manager->is_message_type_active_for_messenger(
1349
+						$active_messenger->name,
1350
+						$default_message_type_name_for_messenger
1351
+					)
1352
+					|| ! isset($installed_message_types[$default_message_type_name_for_messenger])
1353
+				) {
1354
+					continue;
1355
+				}
1356
+				$default_message_type_names_to_activate[] = $default_message_type_name_for_messenger;
1357
+			}
1358
+			//let's activate!
1359
+			$message_resource_manager->ensure_message_types_are_active(
1360
+				$default_message_type_names_to_activate,
1361
+				$active_messenger->name,
1362
+				false
1363
+			);
1364
+			//activate the templates for these message types
1365
+			if ( ! empty($default_message_type_names_to_activate)) {
1366
+				$templates_created = EEH_MSG_Template::generate_new_templates(
1367
+					$active_messenger->name,
1368
+					$default_message_type_names_for_messenger,
1369
+					'',
1370
+					true
1371
+				);
1372
+			}
1373
+		}
1374
+		return $templates_created;
1375
+	}
1376
+
1377
+
1378
+
1379
+	/**
1380
+	 * This will activate and generate default messengers and default message types for those messengers.
1381
+	 *
1382
+	 * @param EE_message_Resource_Manager $message_resource_manager
1383
+	 * @return array|bool  True means there were default messengers and message type templates generated.
1384
+	 *                     False means that there were no templates generated
1385
+	 *                     (which could simply mean there are no default message types for a messenger).
1386
+	 * @throws EE_Error
1387
+	 */
1388
+	protected static function _activate_and_generate_default_messengers_and_message_templates(
1389
+		EE_Message_Resource_Manager $message_resource_manager
1390
+	) {
1391
+		/** @type EE_messenger[] $messengers_to_generate */
1392
+		$messengers_to_generate = self::_get_default_messengers_to_generate_on_activation($message_resource_manager);
1393
+		$installed_message_types = $message_resource_manager->installed_message_types();
1394
+		$templates_generated = false;
1395
+		foreach ($messengers_to_generate as $messenger_to_generate) {
1396
+			$default_message_type_names_for_messenger = $messenger_to_generate->get_default_message_types();
1397
+			//verify the default message types match an installed message type.
1398
+			foreach ($default_message_type_names_for_messenger as $key => $name) {
1399
+				if (
1400
+					! isset($installed_message_types[$name])
1401
+					|| $message_resource_manager->has_message_type_been_activated_for_messenger(
1402
+						$name,
1403
+						$messenger_to_generate->name
1404
+					)
1405
+				) {
1406
+					unset($default_message_type_names_for_messenger[$key]);
1407
+				}
1408
+			}
1409
+			// in previous iterations, the active_messengers option in the db
1410
+			// needed updated before calling create templates. however with the changes this may not be necessary.
1411
+			// This comment is left here just in case we discover that we _do_ need to update before
1412
+			// passing off to create templates (after the refactor is done).
1413
+			// @todo remove this comment when determined not necessary.
1414
+			$message_resource_manager->activate_messenger(
1415
+				$messenger_to_generate->name,
1416
+				$default_message_type_names_for_messenger,
1417
+				false
1418
+			);
1419
+			//create any templates needing created (or will reactivate templates already generated as necessary).
1420
+			if ( ! empty($default_message_type_names_for_messenger)) {
1421
+				$templates_generated = EEH_MSG_Template::generate_new_templates(
1422
+					$messenger_to_generate->name,
1423
+					$default_message_type_names_for_messenger,
1424
+					'',
1425
+					true
1426
+				);
1427
+			}
1428
+		}
1429
+		return $templates_generated;
1430
+	}
1431
+
1432
+
1433
+	/**
1434
+	 * This returns the default messengers to generate templates for on activation of EE.
1435
+	 * It considers:
1436
+	 * - whether a messenger is already active in the db.
1437
+	 * - whether a messenger has been made active at any time in the past.
1438
+	 *
1439
+	 * @static
1440
+	 * @param  EE_Message_Resource_Manager $message_resource_manager
1441
+	 * @return EE_messenger[]
1442
+	 */
1443
+	protected static function _get_default_messengers_to_generate_on_activation(
1444
+		EE_Message_Resource_Manager $message_resource_manager
1445
+	) {
1446
+		// make sure EED_Messages is loaded because it sets the autoloaders
1447
+		require_once EE_MODULES . 'messages' . DS . 'EED_Messages.module.php';
1448
+		$active_messengers    = $message_resource_manager->active_messengers();
1449
+		$installed_messengers = $message_resource_manager->installed_messengers();
1450
+		$has_activated        = $message_resource_manager->get_has_activated_messengers_option();
1451
+
1452
+		$messengers_to_generate = array();
1453
+		foreach ($installed_messengers as $installed_messenger) {
1454
+			//if installed messenger is a messenger that should be activated on install
1455
+			//and is not already active
1456
+			//and has never been activated
1457
+			if (
1458
+				! $installed_messenger->activate_on_install
1459
+				|| isset($active_messengers[$installed_messenger->name])
1460
+				|| isset($has_activated[$installed_messenger->name])
1461
+			) {
1462
+				continue;
1463
+			}
1464
+			$messengers_to_generate[$installed_messenger->name] = $installed_messenger;
1465
+		}
1466
+		return $messengers_to_generate;
1467
+	}
1468
+
1469
+
1470
+	/**
1471
+	 * This simply validates active message types to ensure they actually match installed
1472
+	 * message types.  If there's a mismatch then we deactivate the message type and ensure all related db
1473
+	 * rows are set inactive.
1474
+	 * Note: Messengers are no longer validated here as of 4.9.0 because they get validated automatically whenever
1475
+	 * EE_Messenger_Resource_Manager is constructed.  Message Types are a bit more resource heavy for validation so they
1476
+	 * are still handled in here.
1477
+	 *
1478
+	 * @since 4.3.1
1479
+	 * @return void
1480
+	 */
1481
+	public static function validate_messages_system()
1482
+	{
1483
+		/** @type EE_Message_Resource_Manager $message_resource_manager */
1484
+		$message_resource_manager = EE_Registry::instance()->load_lib('Message_Resource_Manager');
1485
+		$message_resource_manager->validate_active_message_types_are_installed();
1486
+		do_action('AHEE__EEH_Activation__validate_messages_system');
1487
+	}
1488
+
1489
+
1490
+	/**
1491
+	 * create_no_ticket_prices_array
1492
+	 *
1493
+	 * @access public
1494
+	 * @static
1495
+	 * @return void
1496
+	 */
1497
+	public static function create_no_ticket_prices_array()
1498
+	{
1499
+		// this creates an array for tracking events that have no active ticket prices created
1500
+		// this allows us to warn admins of the situation so that it can be corrected
1501
+		$espresso_no_ticket_prices = get_option('ee_no_ticket_prices', false);
1502
+		if (! $espresso_no_ticket_prices) {
1503
+			add_option('ee_no_ticket_prices', array(), '', false);
1504
+		}
1505
+	}
1506
+
1507
+
1508
+	/**
1509
+	 * plugin_deactivation
1510
+	 *
1511
+	 * @access public
1512
+	 * @static
1513
+	 * @return void
1514
+	 */
1515
+	public static function plugin_deactivation()
1516
+	{
1517
+	}
1518
+
1519
+
1520
+	/**
1521
+	 * Finds all our EE4 custom post types, and deletes them and their associated data
1522
+	 * (like post meta or term relations)
1523
+	 *
1524
+	 * @global wpdb $wpdb
1525
+	 * @throws \EE_Error
1526
+	 */
1527
+	public static function delete_all_espresso_cpt_data()
1528
+	{
1529
+		global $wpdb;
1530
+		//get all the CPT post_types
1531
+		$ee_post_types = array();
1532
+		foreach (EE_Registry::instance()->non_abstract_db_models as $model_name) {
1533
+			if (method_exists($model_name, 'instance')) {
1534
+				$model_obj = call_user_func(array($model_name, 'instance'));
1535
+				if ($model_obj instanceof EEM_CPT_Base) {
1536
+					$ee_post_types[] = $wpdb->prepare("%s", $model_obj->post_type());
1537
+				}
1538
+			}
1539
+		}
1540
+		//get all our CPTs
1541
+		$query   = "SELECT ID FROM {$wpdb->posts} WHERE post_type IN (" . implode(",", $ee_post_types) . ")";
1542
+		$cpt_ids = $wpdb->get_col($query);
1543
+		//delete each post meta and term relations too
1544
+		foreach ($cpt_ids as $post_id) {
1545
+			wp_delete_post($post_id, true);
1546
+		}
1547
+	}
1548
+
1549
+	/**
1550
+	 * Deletes all EE custom tables
1551
+	 *
1552
+	 * @return array
1553
+	 */
1554
+	public static function drop_espresso_tables()
1555
+	{
1556
+		$tables = array();
1557
+		// load registry
1558
+		foreach (EE_Registry::instance()->non_abstract_db_models as $model_name) {
1559
+			if (method_exists($model_name, 'instance')) {
1560
+				$model_obj = call_user_func(array($model_name, 'instance'));
1561
+				if ($model_obj instanceof EEM_Base) {
1562
+					foreach ($model_obj->get_tables() as $table) {
1563
+						if (strpos($table->get_table_name(), 'esp_')
1564
+							&&
1565
+							(
1566
+								is_main_site()//main site? nuke them all
1567
+								|| ! $table->is_global()//not main site,but not global either. nuke it
1568
+							)
1569
+						) {
1570
+							$tables[$table->get_table_name()] = $table->get_table_name();
1571
+						}
1572
+					}
1573
+				}
1574
+			}
1575
+		}
1576
+
1577
+		//there are some tables whose models were removed.
1578
+		//they should be removed when removing all EE core's data
1579
+		$tables_without_models = array(
1580
+			'esp_promotion',
1581
+			'esp_promotion_applied',
1582
+			'esp_promotion_object',
1583
+			'esp_promotion_rule',
1584
+			'esp_rule',
1585
+		);
1586
+		foreach ($tables_without_models as $table) {
1587
+			$tables[$table] = $table;
1588
+		}
1589
+		return \EEH_Activation::getTableManager()->dropTables($tables);
1590
+	}
1591
+
1592
+
1593
+
1594
+	/**
1595
+	 * Drops all the tables mentioned in a single MYSQL query. Double-checks
1596
+	 * each table name provided has a wpdb prefix attached, and that it exists.
1597
+	 * Returns the list actually deleted
1598
+	 *
1599
+	 * @deprecated in 4.9.13. Instead use TableManager::dropTables()
1600
+	 * @global WPDB $wpdb
1601
+	 * @param array $table_names
1602
+	 * @return array of table names which we deleted
1603
+	 */
1604
+	public static function drop_tables($table_names)
1605
+	{
1606
+		return \EEH_Activation::getTableManager()->dropTables($table_names);
1607
+	}
1608
+
1609
+
1610
+
1611
+	/**
1612
+	 * plugin_uninstall
1613
+	 *
1614
+	 * @access public
1615
+	 * @static
1616
+	 * @param bool $remove_all
1617
+	 * @return void
1618
+	 */
1619
+	public static function delete_all_espresso_tables_and_data($remove_all = true)
1620
+	{
1621
+		global $wpdb;
1622
+		self::drop_espresso_tables();
1623
+		$wp_options_to_delete = array(
1624
+			'ee_no_ticket_prices'                => true,
1625
+			'ee_active_messengers'               => true,
1626
+			'ee_has_activated_messenger'         => true,
1627
+			'ee_flush_rewrite_rules'             => true,
1628
+			'ee_config'                          => false,
1629
+			'ee_data_migration_current_db_state' => true,
1630
+			'ee_data_migration_mapping_'         => false,
1631
+			'ee_data_migration_script_'          => false,
1632
+			'ee_data_migrations'                 => true,
1633
+			'ee_dms_map'                         => false,
1634
+			'ee_notices'                         => true,
1635
+			'lang_file_check_'                   => false,
1636
+			'ee_maintenance_mode'                => true,
1637
+			'ee_ueip_optin'                      => true,
1638
+			'ee_ueip_has_notified'               => true,
1639
+			'ee_plugin_activation_errors'        => true,
1640
+			'ee_id_mapping_from'                 => false,
1641
+			'espresso_persistent_admin_notices'  => true,
1642
+			'ee_encryption_key'                  => true,
1643
+			'pue_force_upgrade_'                 => false,
1644
+			'pue_json_error_'                    => false,
1645
+			'pue_install_key_'                   => false,
1646
+			'pue_verification_error_'            => false,
1647
+			'pu_dismissed_upgrade_'              => false,
1648
+			'external_updates-'                  => false,
1649
+			'ee_extra_data'                      => true,
1650
+			'ee_ssn_'                            => false,
1651
+			'ee_rss_'                            => false,
1652
+			'ee_rte_n_tx_'                       => false,
1653
+			'ee_pers_admin_notices'              => true,
1654
+			'ee_job_parameters_'                 => false,
1655
+			'ee_upload_directories_incomplete'   => true,
1656
+			'ee_verified_db_collations'          => true,
1657
+		);
1658
+		if (is_main_site()) {
1659
+			$wp_options_to_delete['ee_network_config'] = true;
1660
+		}
1661
+		$undeleted_options = array();
1662
+		foreach ($wp_options_to_delete as $option_name => $no_wildcard) {
1663
+			if ($no_wildcard) {
1664
+				if ( ! delete_option($option_name)) {
1665
+					$undeleted_options[] = $option_name;
1666
+				}
1667
+			} else {
1668
+				$option_names_to_delete_from_wildcard = $wpdb->get_col("SELECT option_name FROM $wpdb->options WHERE option_name LIKE '%$option_name%'");
1669
+				foreach ($option_names_to_delete_from_wildcard as $option_name_from_wildcard) {
1670
+					if ( ! delete_option($option_name_from_wildcard)) {
1671
+						$undeleted_options[] = $option_name_from_wildcard;
1672
+					}
1673
+				}
1674
+			}
1675
+		}
1676
+		//also, let's make sure the "ee_config_option_names" wp option stays out by removing the action that adds it
1677
+		remove_action('shutdown', array(EE_Config::instance(), 'shutdown'), 10);
1678
+		if ($remove_all && $espresso_db_update = get_option('espresso_db_update')) {
1679
+			$db_update_sans_ee4 = array();
1680
+			foreach ($espresso_db_update as $version => $times_activated) {
1681
+				if ((string)$version[0] === '3') {//if its NON EE4
1682
+					$db_update_sans_ee4[$version] = $times_activated;
1683
+				}
1684
+			}
1685
+			update_option('espresso_db_update', $db_update_sans_ee4);
1686
+		}
1687
+		$errors = '';
1688
+		if ( ! empty($undeleted_options)) {
1689
+			$errors .= sprintf(
1690
+				__('The following wp-options could not be deleted: %s%s', 'event_espresso'),
1691
+				'<br/>',
1692
+				implode(',<br/>', $undeleted_options)
1693
+			);
1694
+		}
1695
+		if ( ! empty($errors)) {
1696
+			EE_Error::add_attention($errors, __FILE__, __FUNCTION__, __LINE__);
1697
+		}
1698
+	}
1699
+
1700
+	/**
1701
+	 * Gets the mysql error code from the last used query by wpdb
1702
+	 *
1703
+	 * @return int mysql error code, see https://dev.mysql.com/doc/refman/5.5/en/error-messages-server.html
1704
+	 */
1705
+	public static function last_wpdb_error_code()
1706
+	{
1707
+		global $wpdb;
1708
+		if ($wpdb->use_mysqli) {
1709
+			return mysqli_errno($wpdb->dbh);
1710
+		} else {
1711
+			return mysql_errno($wpdb->dbh);
1712
+		}
1713
+	}
1714
+
1715
+	/**
1716
+	 * Checks that the database table exists. Also works on temporary tables (for unit tests mostly).
1717
+	 *
1718
+	 * @global wpdb  $wpdb
1719
+	 * @deprecated instead use TableAnalysis::tableExists()
1720
+	 * @param string $table_name with or without $wpdb->prefix
1721
+	 * @return boolean
1722
+	 */
1723
+	public static function table_exists($table_name)
1724
+	{
1725
+		return \EEH_Activation::getTableAnalysis()->tableExists($table_name);
1726
+	}
1727
+
1728
+	/**
1729
+	 * Resets the cache on EEH_Activation
1730
+	 */
1731
+	public static function reset()
1732
+	{
1733
+		self::$_default_creator_id                             = null;
1734
+		self::$_initialized_db_content_already_in_this_request = false;
1735
+	}
1736 1736
 }
1737 1737
 // End of file EEH_Activation.helper.php
1738 1738
 // Location: /helpers/EEH_Activation.core.php
Please login to merge, or discard this patch.