Completed
Pull Request — master (#961)
by Darren
11:39 queued 02:46
created
core/helpers/EEH_Debug_Tools.helper.php 1 patch
Indentation   +685 added lines, -685 removed lines patch added patch discarded remove patch
@@ -11,676 +11,676 @@  discard block
 block discarded – undo
11 11
 class EEH_Debug_Tools
12 12
 {
13 13
 
14
-    /**
15
-     *    instance of the EEH_Autoloader object
16
-     *
17
-     * @var    $_instance
18
-     * @access    private
19
-     */
20
-    private static $_instance;
21
-
22
-    /**
23
-     * @var array
24
-     */
25
-    protected $_memory_usage_points = array();
26
-
27
-
28
-
29
-    /**
30
-     * @singleton method used to instantiate class object
31
-     * @access    public
32
-     * @return EEH_Debug_Tools
33
-     */
34
-    public static function instance()
35
-    {
36
-        // check if class object is instantiated, and instantiated properly
37
-        if (! self::$_instance instanceof EEH_Debug_Tools) {
38
-            self::$_instance = new self();
39
-        }
40
-        return self::$_instance;
41
-    }
42
-
43
-
44
-
45
-    /**
46
-     * private class constructor
47
-     */
48
-    private function __construct()
49
-    {
50
-        // load Kint PHP debugging library
51
-        if (! class_exists('Kint') && file_exists(EE_PLUGIN_DIR_PATH . 'tests' . DS . 'kint' . DS . 'Kint.class.php')) {
52
-            // despite EE4 having a check for an existing copy of the Kint debugging class,
53
-            // if another plugin was loaded AFTER EE4 and they did NOT perform a similar check,
54
-            // then hilarity would ensue as PHP throws a "Cannot redeclare class Kint" error
55
-            // so we've moved it to our test folder so that it is not included with production releases
56
-            // plz use https://wordpress.org/plugins/kint-debugger/  if testing production versions of EE
57
-            require_once(EE_PLUGIN_DIR_PATH . 'tests' . DS . 'kint' . DS . 'Kint.class.php');
58
-        }
59
-        // if ( ! defined('DOING_AJAX') || $_REQUEST['noheader'] !== 'true' || ! isset( $_REQUEST['noheader'], $_REQUEST['TB_iframe'] ) ) {
60
-        // add_action( 'shutdown', array($this,'espresso_session_footer_dump') );
61
-        // }
62
-        $plugin = basename(EE_PLUGIN_DIR_PATH);
63
-        add_action("activate_{$plugin}", array('EEH_Debug_Tools', 'ee_plugin_activation_errors'));
64
-        add_action('activated_plugin', array('EEH_Debug_Tools', 'ee_plugin_activation_errors'));
65
-        add_action('shutdown', array('EEH_Debug_Tools', 'show_db_name'));
66
-    }
67
-
68
-
69
-
70
-    /**
71
-     *    show_db_name
72
-     *
73
-     * @return void
74
-     */
75
-    public static function show_db_name()
76
-    {
77
-        if (! defined('DOING_AJAX') && (defined('EE_ERROR_EMAILS') && EE_ERROR_EMAILS)) {
78
-            echo '<p style="font-size:10px;font-weight:normal;color:#E76700;margin: 1em 2em; text-align: right;">DB_NAME: '
79
-                 . DB_NAME
80
-                 . '</p>';
81
-        }
82
-        if (EE_DEBUG) {
83
-            Benchmark::displayResults();
84
-        }
85
-    }
86
-
87
-
88
-
89
-    /**
90
-     *    dump EE_Session object at bottom of page after everything else has happened
91
-     *
92
-     * @return void
93
-     */
94
-    public function espresso_session_footer_dump()
95
-    {
96
-        if ((defined('WP_DEBUG') && WP_DEBUG)
97
-            && ! defined('DOING_AJAX')
98
-            && class_exists('Kint')
99
-            && function_exists('wp_get_current_user')
100
-            && current_user_can('update_core')
101
-            && class_exists('EE_Registry')
102
-        ) {
103
-            Kint::dump(EE_Registry::instance()->SSN->id());
104
-            Kint::dump(EE_Registry::instance()->SSN);
105
-            //          Kint::dump( EE_Registry::instance()->SSN->get_session_data('cart')->get_tickets() );
106
-            $this->espresso_list_hooked_functions();
107
-            Benchmark::displayResults();
108
-        }
109
-    }
110
-
111
-
112
-
113
-    /**
114
-     *    List All Hooked Functions
115
-     *    to list all functions for a specific hook, add ee_list_hooks={hook-name} to URL
116
-     *    http://wp.smashingmagazine.com/2009/08/18/10-useful-wordpress-hook-hacks/
117
-     *
118
-     * @param string $tag
119
-     * @return void
120
-     */
121
-    public function espresso_list_hooked_functions($tag = '')
122
-    {
123
-        global $wp_filter;
124
-        echo '<br/><br/><br/><h3>Hooked Functions</h3>';
125
-        if ($tag) {
126
-            $hook[ $tag ] = $wp_filter[ $tag ];
127
-            if (! is_array($hook[ $tag ])) {
128
-                trigger_error("Nothing found for '$tag' hook", E_USER_WARNING);
129
-                return;
130
-            }
131
-            echo '<h5>For Tag: ' . $tag . '</h5>';
132
-        } else {
133
-            $hook = is_array($wp_filter) ? $wp_filter : array($wp_filter);
134
-            ksort($hook);
135
-        }
136
-        foreach ($hook as $tag_name => $priorities) {
137
-            echo "<br />&gt;&gt;&gt;&gt;&gt;\t<strong>$tag_name</strong><br />";
138
-            ksort($priorities);
139
-            foreach ($priorities as $priority => $function) {
140
-                echo $priority;
141
-                foreach ($function as $name => $properties) {
142
-                    echo "\t$name<br />";
143
-                }
144
-            }
145
-        }
146
-    }
147
-
148
-
149
-
150
-    /**
151
-     *    registered_filter_callbacks
152
-     *
153
-     * @param string $hook_name
154
-     * @return array
155
-     */
156
-    public static function registered_filter_callbacks($hook_name = '')
157
-    {
158
-        $filters = array();
159
-        global $wp_filter;
160
-        if (isset($wp_filter[ $hook_name ])) {
161
-            $filters[ $hook_name ] = array();
162
-            foreach ($wp_filter[ $hook_name ] as $priority => $callbacks) {
163
-                $filters[ $hook_name ][ $priority ] = array();
164
-                foreach ($callbacks as $callback) {
165
-                    $filters[ $hook_name ][ $priority ][] = $callback['function'];
166
-                }
167
-            }
168
-        }
169
-        return $filters;
170
-    }
171
-
172
-
173
-
174
-    /**
175
-     *    captures plugin activation errors for debugging
176
-     *
177
-     * @return void
178
-     * @throws EE_Error
179
-     */
180
-    public static function ee_plugin_activation_errors()
181
-    {
182
-        if (WP_DEBUG) {
183
-            $activation_errors = ob_get_contents();
184
-            if (! empty($activation_errors)) {
185
-                $activation_errors = date('Y-m-d H:i:s') . "\n" . $activation_errors;
186
-            }
187
-            espresso_load_required('EEH_File', EE_HELPERS . 'EEH_File.helper.php');
188
-            if (class_exists('EEH_File')) {
189
-                try {
190
-                    EEH_File::ensure_file_exists_and_is_writable(
191
-                        EVENT_ESPRESSO_UPLOAD_DIR . 'logs' . DS . 'espresso_plugin_activation_errors.html'
192
-                    );
193
-                    EEH_File::write_to_file(
194
-                        EVENT_ESPRESSO_UPLOAD_DIR . 'logs' . DS . 'espresso_plugin_activation_errors.html',
195
-                        $activation_errors
196
-                    );
197
-                } catch (EE_Error $e) {
198
-                    EE_Error::add_error(
199
-                        sprintf(
200
-                            __(
201
-                                'The Event Espresso activation errors file could not be setup because: %s',
202
-                                'event_espresso'
203
-                            ),
204
-                            $e->getMessage()
205
-                        ),
206
-                        __FILE__,
207
-                        __FUNCTION__,
208
-                        __LINE__
209
-                    );
210
-                }
211
-            } else {
212
-                // old school attempt
213
-                file_put_contents(
214
-                    EVENT_ESPRESSO_UPLOAD_DIR . 'logs' . DS . 'espresso_plugin_activation_errors.html',
215
-                    $activation_errors
216
-                );
217
-            }
218
-            $activation_errors = get_option('ee_plugin_activation_errors', '') . $activation_errors;
219
-            update_option('ee_plugin_activation_errors', $activation_errors);
220
-        }
221
-    }
222
-
223
-
224
-
225
-    /**
226
-     * This basically mimics the WordPress _doing_it_wrong() function except adds our own messaging etc.
227
-     * Very useful for providing helpful messages to developers when the method of doing something has been deprecated,
228
-     * or we want to make sure they use something the right way.
229
-     *
230
-     * @access public
231
-     * @param string $function      The function that was called
232
-     * @param string $message       A message explaining what has been done incorrectly
233
-     * @param string $version       The version of Event Espresso where the error was added
234
-     * @param string $applies_when  a version string for when you want the doing_it_wrong notice to begin appearing
235
-     *                              for a deprecated function. This allows deprecation to occur during one version,
236
-     *                              but not have any notices appear until a later version. This allows developers
237
-     *                              extra time to update their code before notices appear.
238
-     * @param int    $error_type
239
-     * @uses   trigger_error()
240
-     */
241
-    public function doing_it_wrong(
242
-        $function,
243
-        $message,
244
-        $version,
245
-        $applies_when = '',
246
-        $error_type = null
247
-    ) {
248
-        $applies_when = ! empty($applies_when) ? $applies_when : espresso_version();
249
-        $error_type = $error_type !== null ? $error_type : E_USER_NOTICE;
250
-        // because we swapped the parameter order around for the last two params,
251
-        // let's verify that some third party isn't still passing an error type value for the third param
252
-        if (is_int($applies_when)) {
253
-            $error_type = $applies_when;
254
-            $applies_when = espresso_version();
255
-        }
256
-        // if not displaying notices yet, then just leave
257
-        if (version_compare(espresso_version(), $applies_when, '<')) {
258
-            return;
259
-        }
260
-        do_action('AHEE__EEH_Debug_Tools__doing_it_wrong_run', $function, $message, $version);
261
-        $version = $version === null
262
-            ? ''
263
-            : sprintf(
264
-                __('(This message was added in version %s of Event Espresso)', 'event_espresso'),
265
-                $version
266
-            );
267
-        $error_message = sprintf(
268
-            esc_html__('%1$s was called %2$sincorrectly%3$s. %4$s %5$s', 'event_espresso'),
269
-            $function,
270
-            '<strong>',
271
-            '</strong>',
272
-            $message,
273
-            $version
274
-        );
275
-        // don't trigger error if doing ajax,
276
-        // instead we'll add a transient EE_Error notice that in theory should show on the next request.
277
-        if (defined('DOING_AJAX') && DOING_AJAX) {
278
-            $error_message .= ' ' . esc_html__(
279
-                'This is a doing_it_wrong message that was triggered during an ajax request.  The request params on this request were: ',
280
-                'event_espresso'
281
-            );
282
-            $error_message .= '<ul><li>';
283
-            $error_message .= implode('</li><li>', EE_Registry::instance()->REQ->params());
284
-            $error_message .= '</ul>';
285
-            EE_Error::add_error($error_message, 'debug::doing_it_wrong', $function, '42');
286
-            // now we set this on the transient so it shows up on the next request.
287
-            EE_Error::get_notices(false, true);
288
-        } else {
289
-            trigger_error($error_message, $error_type);
290
-        }
291
-    }
292
-
293
-
294
-
295
-
296
-    /**
297
-     * Logger helpers
298
-     */
299
-    /**
300
-     * debug
301
-     *
302
-     * @param string $class
303
-     * @param string $func
304
-     * @param string $line
305
-     * @param array  $info
306
-     * @param bool   $display_request
307
-     * @param string $debug_index
308
-     * @param string $debug_key
309
-     * @throws EE_Error
310
-     * @throws \EventEspresso\core\exceptions\InvalidSessionDataException
311
-     */
312
-    public static function log(
313
-        $class = '',
314
-        $func = '',
315
-        $line = '',
316
-        $info = array(),
317
-        $display_request = false,
318
-        $debug_index = '',
319
-        $debug_key = 'EE_DEBUG_SPCO'
320
-    ) {
321
-        if (WP_DEBUG) {
322
-            $debug_key = $debug_key . '_' . EE_Session::instance()->id();
323
-            $debug_data = get_option($debug_key, array());
324
-            $default_data = array(
325
-                $class => $func . '() : ' . $line,
326
-                'REQ'  => $display_request ? $_REQUEST : '',
327
-            );
328
-            // don't serialize objects
329
-            $info = self::strip_objects($info);
330
-            $index = ! empty($debug_index) ? $debug_index : 0;
331
-            if (! isset($debug_data[ $index ])) {
332
-                $debug_data[ $index ] = array();
333
-            }
334
-            $debug_data[ $index ][ microtime() ] = array_merge($default_data, $info);
335
-            update_option($debug_key, $debug_data);
336
-        }
337
-    }
338
-
339
-
340
-
341
-    /**
342
-     * strip_objects
343
-     *
344
-     * @param array $info
345
-     * @return array
346
-     */
347
-    public static function strip_objects($info = array())
348
-    {
349
-        foreach ($info as $key => $value) {
350
-            if (is_array($value)) {
351
-                $info[ $key ] = self::strip_objects($value);
352
-            } elseif (is_object($value)) {
353
-                $object_class = get_class($value);
354
-                $info[ $object_class ] = array();
355
-                $info[ $object_class ]['ID'] = method_exists($value, 'ID') ? $value->ID() : spl_object_hash($value);
356
-                if (method_exists($value, 'ID')) {
357
-                    $info[ $object_class ]['ID'] = $value->ID();
358
-                }
359
-                if (method_exists($value, 'status')) {
360
-                    $info[ $object_class ]['status'] = $value->status();
361
-                } elseif (method_exists($value, 'status_ID')) {
362
-                    $info[ $object_class ]['status'] = $value->status_ID();
363
-                }
364
-                unset($info[ $key ]);
365
-            }
366
-        }
367
-        return (array) $info;
368
-    }
369
-
370
-
371
-
372
-    /**
373
-     * @param mixed      $var
374
-     * @param string     $var_name
375
-     * @param string     $file
376
-     * @param int|string $line
377
-     * @param int|string $heading_tag
378
-     * @param bool       $die
379
-     * @param string     $margin
380
-     */
381
-    public static function printv(
382
-        $var,
383
-        $var_name = '',
384
-        $file = '',
385
-        $line = '',
386
-        $heading_tag = 5,
387
-        $die = false,
388
-        $margin = ''
389
-    ) {
390
-        $var_name = ! $var_name ? 'string' : $var_name;
391
-        $var_name = ucwords(str_replace('$', '', $var_name));
392
-        $is_method = method_exists($var_name, $var);
393
-        $var_name = ucwords(str_replace('_', ' ', $var_name));
394
-        $heading_tag = EEH_Debug_Tools::headingTag($heading_tag);
395
-        $result = EEH_Debug_Tools::headingSpacer($heading_tag);
396
-        $result .= EEH_Debug_Tools::heading($var_name, $heading_tag, $margin, $line);
397
-        $result .= $is_method
398
-            ? EEH_Debug_Tools::grey_span('::') . EEH_Debug_Tools::orange_span($var . '()')
399
-            : EEH_Debug_Tools::grey_span(' : ') . EEH_Debug_Tools::orange_span($var);
400
-        $result .= EEH_Debug_Tools::file_and_line($file, $line, $heading_tag);
401
-        $result .= EEH_Debug_Tools::headingX($heading_tag);
402
-        if ($die) {
403
-            die($result);
404
-        }
405
-        echo $result;
406
-    }
407
-
408
-
409
-    protected static function headingTag($heading_tag)
410
-    {
411
-        $heading_tag = absint($heading_tag);
412
-        return $heading_tag > 0 && $heading_tag < 7 ? "h{$heading_tag}" : 'h5';
413
-    }
414
-
415
-
416
-    protected static function headingSpacer($heading_tag)
417
-    {
418
-        return EEH_Debug_Tools::plainOutput() && ($heading_tag === 'h1' || $heading_tag === 'h2')
419
-            ? "\n"
420
-            : '';
421
-    }
422
-
423
-
424
-    protected static function plainOutput()
425
-    {
426
-        return defined('EE_TESTS_DIR')
427
-               || (defined('DOING_AJAX') && DOING_AJAX)
428
-               || (
429
-                   isset($_SERVER['REQUEST_URI'])
430
-                   && strpos(parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH), 'wp-json') !== false
431
-               );
432
-    }
433
-
434
-
435
-    /**
436
-     * @param string $var_name
437
-     * @param string $heading_tag
438
-     * @param string $margin
439
-     * @param int    $line
440
-     * @return string
441
-     */
442
-    protected static function heading($var_name = '', $heading_tag = 'h5', $margin = '', $line = 0)
443
-    {
444
-        if (EEH_Debug_Tools::plainOutput()) {
445
-            $heading = '';
446
-            if ($heading_tag === 'h1' || $heading_tag === 'h2') {
447
-                $heading .= "\n";
448
-            }
449
-            $heading .= "\n{$line}) {$var_name}";
450
-            return $heading;
451
-        }
452
-        $margin = "25px 0 0 {$margin}";
453
-        return '<' . $heading_tag . ' style="color:#2EA2CC; margin:' . $margin . ';"><b>' . $var_name . '</b>';
454
-    }
455
-
456
-
457
-
458
-    /**
459
-     * @param string $heading_tag
460
-     * @return string
461
-     */
462
-    protected static function headingX($heading_tag = 'h5')
463
-    {
464
-        if (EEH_Debug_Tools::plainOutput()) {
465
-            return '';
466
-        }
467
-        return '</' . $heading_tag . '>';
468
-    }
469
-
470
-
471
-
472
-    /**
473
-     * @param string $content
474
-     * @return string
475
-     */
476
-    protected static function grey_span($content = '')
477
-    {
478
-        if (EEH_Debug_Tools::plainOutput()) {
479
-            return $content;
480
-        }
481
-        return '<span style="color:#999">' . $content . '</span>';
482
-    }
483
-
484
-
485
-
486
-    /**
487
-     * @param string $file
488
-     * @param int    $line
489
-     * @return string
490
-     */
491
-    protected static function file_and_line($file, $line, $heading_tag)
492
-    {
493
-        if ($file === '' || $line === '') {
494
-            return '';
495
-        }
496
-        $file = str_replace(EE_PLUGIN_DIR_PATH, '/', $file);
497
-        if (EEH_Debug_Tools::plainOutput()) {
498
-            if ($heading_tag === 'h1' || $heading_tag === 'h2') {
499
-                return " ({$file})";
500
-            }
501
-            return '';
502
-        }
503
-        return '<br /><span style="font-size:9px;font-weight:normal;color:#666;line-height: 12px;">'
504
-               . $file
505
-               . '<br />line no: '
506
-               . $line
507
-               . '</span>';
508
-    }
509
-
510
-
511
-
512
-    /**
513
-     * @param string $content
514
-     * @return string
515
-     */
516
-    protected static function orange_span($content = '')
517
-    {
518
-        if (EEH_Debug_Tools::plainOutput()) {
519
-            return $content;
520
-        }
521
-        return '<span style="color:#E76700">' . $content . '</span>';
522
-    }
523
-
524
-
525
-
526
-    /**
527
-     * @param mixed $var
528
-     * @return string
529
-     */
530
-    protected static function pre_span($var)
531
-    {
532
-        ob_start();
533
-        var_dump($var);
534
-        $var = ob_get_clean();
535
-        if (EEH_Debug_Tools::plainOutput()) {
536
-            return $var;
537
-        }
538
-        return '<pre style="color:#999; padding:1em; background: #fff">' . $var . '</pre>';
539
-    }
540
-
541
-
542
-
543
-    /**
544
-     * @param mixed      $var
545
-     * @param string     $var_name
546
-     * @param string     $file
547
-     * @param int|string $line
548
-     * @param int|string $heading_tag
549
-     * @param bool       $die
550
-     */
551
-    public static function printr(
552
-        $var,
553
-        $var_name = '',
554
-        $file = '',
555
-        $line = '',
556
-        $heading_tag = 5,
557
-        $die = false
558
-    ) {
559
-        // return;
560
-        $file = str_replace(rtrim(ABSPATH, '\\/'), '', $file);
561
-        if (empty($var) && empty($var_name)) {
562
-            $var = $file;
563
-            $var_name = "line $line";
564
-            $file = '';
565
-            $line = '';
566
-        }
567
-        $margin = is_admin() ? ' 180px' : '0';
568
-        // $print_r = false;
569
-        if (is_string($var)) {
570
-            EEH_Debug_Tools::printv($var, $var_name, $file, $line, $heading_tag, $die, $margin);
571
-            return;
572
-        }
573
-        if (is_object($var)) {
574
-            $var_name = ! $var_name ? 'object' : $var_name;
575
-            // $print_r = true;
576
-        } elseif (is_array($var)) {
577
-            $var_name = ! $var_name ? 'array' : $var_name;
578
-            // $print_r = true;
579
-        } elseif (is_numeric($var)) {
580
-            $var_name = ! $var_name ? 'numeric' : $var_name;
581
-        } elseif ($var === null) {
582
-            $var_name = ! $var_name ? 'null' : $var_name;
583
-        }
584
-        $var_name = ucwords(str_replace(array('$', '_'), array('', ' '), $var_name));
585
-        $heading_tag = EEH_Debug_Tools::headingTag($heading_tag);
586
-        $result = EEH_Debug_Tools::headingSpacer($heading_tag);
587
-        $result .= EEH_Debug_Tools::heading($var_name, $heading_tag, $margin, $line);
588
-        $result .= EEH_Debug_Tools::grey_span(' : ') . EEH_Debug_Tools::orange_span(
589
-            EEH_Debug_Tools::pre_span($var)
590
-        );
591
-        $result .= EEH_Debug_Tools::file_and_line($file, $line, $heading_tag);
592
-        $result .= EEH_Debug_Tools::headingX($heading_tag);
593
-        if ($die) {
594
-            die($result);
595
-        }
596
-        echo $result;
597
-    }
598
-
599
-
600
-
601
-    /******************** deprecated ********************/
602
-
603
-
604
-
605
-    /**
606
-     * @deprecated 4.9.39.rc.034
607
-     */
608
-    public function reset_times()
609
-    {
610
-        Benchmark::resetTimes();
611
-    }
612
-
613
-
614
-
615
-    /**
616
-     * @deprecated 4.9.39.rc.034
617
-     * @param null $timer_name
618
-     */
619
-    public function start_timer($timer_name = null)
620
-    {
621
-        Benchmark::startTimer($timer_name);
622
-    }
623
-
624
-
625
-
626
-    /**
627
-     * @deprecated 4.9.39.rc.034
628
-     * @param string $timer_name
629
-     */
630
-    public function stop_timer($timer_name = '')
631
-    {
632
-        Benchmark::stopTimer($timer_name);
633
-    }
634
-
635
-
636
-
637
-    /**
638
-     * @deprecated 4.9.39.rc.034
639
-     * @param string  $label      The label to show for this time eg "Start of calling Some_Class::some_function"
640
-     * @param boolean $output_now whether to echo now, or wait until EEH_Debug_Tools::show_times() is called
641
-     * @return void
642
-     */
643
-    public function measure_memory($label, $output_now = false)
644
-    {
645
-        Benchmark::measureMemory($label, $output_now);
646
-    }
647
-
648
-
649
-
650
-    /**
651
-     * @deprecated 4.9.39.rc.034
652
-     * @param int $size
653
-     * @return string
654
-     */
655
-    public function convert($size)
656
-    {
657
-        return Benchmark::convert($size);
658
-    }
659
-
660
-
661
-
662
-    /**
663
-     * @deprecated 4.9.39.rc.034
664
-     * @param bool $output_now
665
-     * @return string
666
-     */
667
-    public function show_times($output_now = true)
668
-    {
669
-        return Benchmark::displayResults($output_now);
670
-    }
671
-
672
-
673
-
674
-    /**
675
-     * @deprecated 4.9.39.rc.034
676
-     * @param string $timer_name
677
-     * @param float  $total_time
678
-     * @return string
679
-     */
680
-    public function format_time($timer_name, $total_time)
681
-    {
682
-        return Benchmark::formatTime($timer_name, $total_time);
683
-    }
14
+	/**
15
+	 *    instance of the EEH_Autoloader object
16
+	 *
17
+	 * @var    $_instance
18
+	 * @access    private
19
+	 */
20
+	private static $_instance;
21
+
22
+	/**
23
+	 * @var array
24
+	 */
25
+	protected $_memory_usage_points = array();
26
+
27
+
28
+
29
+	/**
30
+	 * @singleton method used to instantiate class object
31
+	 * @access    public
32
+	 * @return EEH_Debug_Tools
33
+	 */
34
+	public static function instance()
35
+	{
36
+		// check if class object is instantiated, and instantiated properly
37
+		if (! self::$_instance instanceof EEH_Debug_Tools) {
38
+			self::$_instance = new self();
39
+		}
40
+		return self::$_instance;
41
+	}
42
+
43
+
44
+
45
+	/**
46
+	 * private class constructor
47
+	 */
48
+	private function __construct()
49
+	{
50
+		// load Kint PHP debugging library
51
+		if (! class_exists('Kint') && file_exists(EE_PLUGIN_DIR_PATH . 'tests' . DS . 'kint' . DS . 'Kint.class.php')) {
52
+			// despite EE4 having a check for an existing copy of the Kint debugging class,
53
+			// if another plugin was loaded AFTER EE4 and they did NOT perform a similar check,
54
+			// then hilarity would ensue as PHP throws a "Cannot redeclare class Kint" error
55
+			// so we've moved it to our test folder so that it is not included with production releases
56
+			// plz use https://wordpress.org/plugins/kint-debugger/  if testing production versions of EE
57
+			require_once(EE_PLUGIN_DIR_PATH . 'tests' . DS . 'kint' . DS . 'Kint.class.php');
58
+		}
59
+		// if ( ! defined('DOING_AJAX') || $_REQUEST['noheader'] !== 'true' || ! isset( $_REQUEST['noheader'], $_REQUEST['TB_iframe'] ) ) {
60
+		// add_action( 'shutdown', array($this,'espresso_session_footer_dump') );
61
+		// }
62
+		$plugin = basename(EE_PLUGIN_DIR_PATH);
63
+		add_action("activate_{$plugin}", array('EEH_Debug_Tools', 'ee_plugin_activation_errors'));
64
+		add_action('activated_plugin', array('EEH_Debug_Tools', 'ee_plugin_activation_errors'));
65
+		add_action('shutdown', array('EEH_Debug_Tools', 'show_db_name'));
66
+	}
67
+
68
+
69
+
70
+	/**
71
+	 *    show_db_name
72
+	 *
73
+	 * @return void
74
+	 */
75
+	public static function show_db_name()
76
+	{
77
+		if (! defined('DOING_AJAX') && (defined('EE_ERROR_EMAILS') && EE_ERROR_EMAILS)) {
78
+			echo '<p style="font-size:10px;font-weight:normal;color:#E76700;margin: 1em 2em; text-align: right;">DB_NAME: '
79
+				 . DB_NAME
80
+				 . '</p>';
81
+		}
82
+		if (EE_DEBUG) {
83
+			Benchmark::displayResults();
84
+		}
85
+	}
86
+
87
+
88
+
89
+	/**
90
+	 *    dump EE_Session object at bottom of page after everything else has happened
91
+	 *
92
+	 * @return void
93
+	 */
94
+	public function espresso_session_footer_dump()
95
+	{
96
+		if ((defined('WP_DEBUG') && WP_DEBUG)
97
+			&& ! defined('DOING_AJAX')
98
+			&& class_exists('Kint')
99
+			&& function_exists('wp_get_current_user')
100
+			&& current_user_can('update_core')
101
+			&& class_exists('EE_Registry')
102
+		) {
103
+			Kint::dump(EE_Registry::instance()->SSN->id());
104
+			Kint::dump(EE_Registry::instance()->SSN);
105
+			//          Kint::dump( EE_Registry::instance()->SSN->get_session_data('cart')->get_tickets() );
106
+			$this->espresso_list_hooked_functions();
107
+			Benchmark::displayResults();
108
+		}
109
+	}
110
+
111
+
112
+
113
+	/**
114
+	 *    List All Hooked Functions
115
+	 *    to list all functions for a specific hook, add ee_list_hooks={hook-name} to URL
116
+	 *    http://wp.smashingmagazine.com/2009/08/18/10-useful-wordpress-hook-hacks/
117
+	 *
118
+	 * @param string $tag
119
+	 * @return void
120
+	 */
121
+	public function espresso_list_hooked_functions($tag = '')
122
+	{
123
+		global $wp_filter;
124
+		echo '<br/><br/><br/><h3>Hooked Functions</h3>';
125
+		if ($tag) {
126
+			$hook[ $tag ] = $wp_filter[ $tag ];
127
+			if (! is_array($hook[ $tag ])) {
128
+				trigger_error("Nothing found for '$tag' hook", E_USER_WARNING);
129
+				return;
130
+			}
131
+			echo '<h5>For Tag: ' . $tag . '</h5>';
132
+		} else {
133
+			$hook = is_array($wp_filter) ? $wp_filter : array($wp_filter);
134
+			ksort($hook);
135
+		}
136
+		foreach ($hook as $tag_name => $priorities) {
137
+			echo "<br />&gt;&gt;&gt;&gt;&gt;\t<strong>$tag_name</strong><br />";
138
+			ksort($priorities);
139
+			foreach ($priorities as $priority => $function) {
140
+				echo $priority;
141
+				foreach ($function as $name => $properties) {
142
+					echo "\t$name<br />";
143
+				}
144
+			}
145
+		}
146
+	}
147
+
148
+
149
+
150
+	/**
151
+	 *    registered_filter_callbacks
152
+	 *
153
+	 * @param string $hook_name
154
+	 * @return array
155
+	 */
156
+	public static function registered_filter_callbacks($hook_name = '')
157
+	{
158
+		$filters = array();
159
+		global $wp_filter;
160
+		if (isset($wp_filter[ $hook_name ])) {
161
+			$filters[ $hook_name ] = array();
162
+			foreach ($wp_filter[ $hook_name ] as $priority => $callbacks) {
163
+				$filters[ $hook_name ][ $priority ] = array();
164
+				foreach ($callbacks as $callback) {
165
+					$filters[ $hook_name ][ $priority ][] = $callback['function'];
166
+				}
167
+			}
168
+		}
169
+		return $filters;
170
+	}
171
+
172
+
173
+
174
+	/**
175
+	 *    captures plugin activation errors for debugging
176
+	 *
177
+	 * @return void
178
+	 * @throws EE_Error
179
+	 */
180
+	public static function ee_plugin_activation_errors()
181
+	{
182
+		if (WP_DEBUG) {
183
+			$activation_errors = ob_get_contents();
184
+			if (! empty($activation_errors)) {
185
+				$activation_errors = date('Y-m-d H:i:s') . "\n" . $activation_errors;
186
+			}
187
+			espresso_load_required('EEH_File', EE_HELPERS . 'EEH_File.helper.php');
188
+			if (class_exists('EEH_File')) {
189
+				try {
190
+					EEH_File::ensure_file_exists_and_is_writable(
191
+						EVENT_ESPRESSO_UPLOAD_DIR . 'logs' . DS . 'espresso_plugin_activation_errors.html'
192
+					);
193
+					EEH_File::write_to_file(
194
+						EVENT_ESPRESSO_UPLOAD_DIR . 'logs' . DS . 'espresso_plugin_activation_errors.html',
195
+						$activation_errors
196
+					);
197
+				} catch (EE_Error $e) {
198
+					EE_Error::add_error(
199
+						sprintf(
200
+							__(
201
+								'The Event Espresso activation errors file could not be setup because: %s',
202
+								'event_espresso'
203
+							),
204
+							$e->getMessage()
205
+						),
206
+						__FILE__,
207
+						__FUNCTION__,
208
+						__LINE__
209
+					);
210
+				}
211
+			} else {
212
+				// old school attempt
213
+				file_put_contents(
214
+					EVENT_ESPRESSO_UPLOAD_DIR . 'logs' . DS . 'espresso_plugin_activation_errors.html',
215
+					$activation_errors
216
+				);
217
+			}
218
+			$activation_errors = get_option('ee_plugin_activation_errors', '') . $activation_errors;
219
+			update_option('ee_plugin_activation_errors', $activation_errors);
220
+		}
221
+	}
222
+
223
+
224
+
225
+	/**
226
+	 * This basically mimics the WordPress _doing_it_wrong() function except adds our own messaging etc.
227
+	 * Very useful for providing helpful messages to developers when the method of doing something has been deprecated,
228
+	 * or we want to make sure they use something the right way.
229
+	 *
230
+	 * @access public
231
+	 * @param string $function      The function that was called
232
+	 * @param string $message       A message explaining what has been done incorrectly
233
+	 * @param string $version       The version of Event Espresso where the error was added
234
+	 * @param string $applies_when  a version string for when you want the doing_it_wrong notice to begin appearing
235
+	 *                              for a deprecated function. This allows deprecation to occur during one version,
236
+	 *                              but not have any notices appear until a later version. This allows developers
237
+	 *                              extra time to update their code before notices appear.
238
+	 * @param int    $error_type
239
+	 * @uses   trigger_error()
240
+	 */
241
+	public function doing_it_wrong(
242
+		$function,
243
+		$message,
244
+		$version,
245
+		$applies_when = '',
246
+		$error_type = null
247
+	) {
248
+		$applies_when = ! empty($applies_when) ? $applies_when : espresso_version();
249
+		$error_type = $error_type !== null ? $error_type : E_USER_NOTICE;
250
+		// because we swapped the parameter order around for the last two params,
251
+		// let's verify that some third party isn't still passing an error type value for the third param
252
+		if (is_int($applies_when)) {
253
+			$error_type = $applies_when;
254
+			$applies_when = espresso_version();
255
+		}
256
+		// if not displaying notices yet, then just leave
257
+		if (version_compare(espresso_version(), $applies_when, '<')) {
258
+			return;
259
+		}
260
+		do_action('AHEE__EEH_Debug_Tools__doing_it_wrong_run', $function, $message, $version);
261
+		$version = $version === null
262
+			? ''
263
+			: sprintf(
264
+				__('(This message was added in version %s of Event Espresso)', 'event_espresso'),
265
+				$version
266
+			);
267
+		$error_message = sprintf(
268
+			esc_html__('%1$s was called %2$sincorrectly%3$s. %4$s %5$s', 'event_espresso'),
269
+			$function,
270
+			'<strong>',
271
+			'</strong>',
272
+			$message,
273
+			$version
274
+		);
275
+		// don't trigger error if doing ajax,
276
+		// instead we'll add a transient EE_Error notice that in theory should show on the next request.
277
+		if (defined('DOING_AJAX') && DOING_AJAX) {
278
+			$error_message .= ' ' . esc_html__(
279
+				'This is a doing_it_wrong message that was triggered during an ajax request.  The request params on this request were: ',
280
+				'event_espresso'
281
+			);
282
+			$error_message .= '<ul><li>';
283
+			$error_message .= implode('</li><li>', EE_Registry::instance()->REQ->params());
284
+			$error_message .= '</ul>';
285
+			EE_Error::add_error($error_message, 'debug::doing_it_wrong', $function, '42');
286
+			// now we set this on the transient so it shows up on the next request.
287
+			EE_Error::get_notices(false, true);
288
+		} else {
289
+			trigger_error($error_message, $error_type);
290
+		}
291
+	}
292
+
293
+
294
+
295
+
296
+	/**
297
+	 * Logger helpers
298
+	 */
299
+	/**
300
+	 * debug
301
+	 *
302
+	 * @param string $class
303
+	 * @param string $func
304
+	 * @param string $line
305
+	 * @param array  $info
306
+	 * @param bool   $display_request
307
+	 * @param string $debug_index
308
+	 * @param string $debug_key
309
+	 * @throws EE_Error
310
+	 * @throws \EventEspresso\core\exceptions\InvalidSessionDataException
311
+	 */
312
+	public static function log(
313
+		$class = '',
314
+		$func = '',
315
+		$line = '',
316
+		$info = array(),
317
+		$display_request = false,
318
+		$debug_index = '',
319
+		$debug_key = 'EE_DEBUG_SPCO'
320
+	) {
321
+		if (WP_DEBUG) {
322
+			$debug_key = $debug_key . '_' . EE_Session::instance()->id();
323
+			$debug_data = get_option($debug_key, array());
324
+			$default_data = array(
325
+				$class => $func . '() : ' . $line,
326
+				'REQ'  => $display_request ? $_REQUEST : '',
327
+			);
328
+			// don't serialize objects
329
+			$info = self::strip_objects($info);
330
+			$index = ! empty($debug_index) ? $debug_index : 0;
331
+			if (! isset($debug_data[ $index ])) {
332
+				$debug_data[ $index ] = array();
333
+			}
334
+			$debug_data[ $index ][ microtime() ] = array_merge($default_data, $info);
335
+			update_option($debug_key, $debug_data);
336
+		}
337
+	}
338
+
339
+
340
+
341
+	/**
342
+	 * strip_objects
343
+	 *
344
+	 * @param array $info
345
+	 * @return array
346
+	 */
347
+	public static function strip_objects($info = array())
348
+	{
349
+		foreach ($info as $key => $value) {
350
+			if (is_array($value)) {
351
+				$info[ $key ] = self::strip_objects($value);
352
+			} elseif (is_object($value)) {
353
+				$object_class = get_class($value);
354
+				$info[ $object_class ] = array();
355
+				$info[ $object_class ]['ID'] = method_exists($value, 'ID') ? $value->ID() : spl_object_hash($value);
356
+				if (method_exists($value, 'ID')) {
357
+					$info[ $object_class ]['ID'] = $value->ID();
358
+				}
359
+				if (method_exists($value, 'status')) {
360
+					$info[ $object_class ]['status'] = $value->status();
361
+				} elseif (method_exists($value, 'status_ID')) {
362
+					$info[ $object_class ]['status'] = $value->status_ID();
363
+				}
364
+				unset($info[ $key ]);
365
+			}
366
+		}
367
+		return (array) $info;
368
+	}
369
+
370
+
371
+
372
+	/**
373
+	 * @param mixed      $var
374
+	 * @param string     $var_name
375
+	 * @param string     $file
376
+	 * @param int|string $line
377
+	 * @param int|string $heading_tag
378
+	 * @param bool       $die
379
+	 * @param string     $margin
380
+	 */
381
+	public static function printv(
382
+		$var,
383
+		$var_name = '',
384
+		$file = '',
385
+		$line = '',
386
+		$heading_tag = 5,
387
+		$die = false,
388
+		$margin = ''
389
+	) {
390
+		$var_name = ! $var_name ? 'string' : $var_name;
391
+		$var_name = ucwords(str_replace('$', '', $var_name));
392
+		$is_method = method_exists($var_name, $var);
393
+		$var_name = ucwords(str_replace('_', ' ', $var_name));
394
+		$heading_tag = EEH_Debug_Tools::headingTag($heading_tag);
395
+		$result = EEH_Debug_Tools::headingSpacer($heading_tag);
396
+		$result .= EEH_Debug_Tools::heading($var_name, $heading_tag, $margin, $line);
397
+		$result .= $is_method
398
+			? EEH_Debug_Tools::grey_span('::') . EEH_Debug_Tools::orange_span($var . '()')
399
+			: EEH_Debug_Tools::grey_span(' : ') . EEH_Debug_Tools::orange_span($var);
400
+		$result .= EEH_Debug_Tools::file_and_line($file, $line, $heading_tag);
401
+		$result .= EEH_Debug_Tools::headingX($heading_tag);
402
+		if ($die) {
403
+			die($result);
404
+		}
405
+		echo $result;
406
+	}
407
+
408
+
409
+	protected static function headingTag($heading_tag)
410
+	{
411
+		$heading_tag = absint($heading_tag);
412
+		return $heading_tag > 0 && $heading_tag < 7 ? "h{$heading_tag}" : 'h5';
413
+	}
414
+
415
+
416
+	protected static function headingSpacer($heading_tag)
417
+	{
418
+		return EEH_Debug_Tools::plainOutput() && ($heading_tag === 'h1' || $heading_tag === 'h2')
419
+			? "\n"
420
+			: '';
421
+	}
422
+
423
+
424
+	protected static function plainOutput()
425
+	{
426
+		return defined('EE_TESTS_DIR')
427
+			   || (defined('DOING_AJAX') && DOING_AJAX)
428
+			   || (
429
+				   isset($_SERVER['REQUEST_URI'])
430
+				   && strpos(parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH), 'wp-json') !== false
431
+			   );
432
+	}
433
+
434
+
435
+	/**
436
+	 * @param string $var_name
437
+	 * @param string $heading_tag
438
+	 * @param string $margin
439
+	 * @param int    $line
440
+	 * @return string
441
+	 */
442
+	protected static function heading($var_name = '', $heading_tag = 'h5', $margin = '', $line = 0)
443
+	{
444
+		if (EEH_Debug_Tools::plainOutput()) {
445
+			$heading = '';
446
+			if ($heading_tag === 'h1' || $heading_tag === 'h2') {
447
+				$heading .= "\n";
448
+			}
449
+			$heading .= "\n{$line}) {$var_name}";
450
+			return $heading;
451
+		}
452
+		$margin = "25px 0 0 {$margin}";
453
+		return '<' . $heading_tag . ' style="color:#2EA2CC; margin:' . $margin . ';"><b>' . $var_name . '</b>';
454
+	}
455
+
456
+
457
+
458
+	/**
459
+	 * @param string $heading_tag
460
+	 * @return string
461
+	 */
462
+	protected static function headingX($heading_tag = 'h5')
463
+	{
464
+		if (EEH_Debug_Tools::plainOutput()) {
465
+			return '';
466
+		}
467
+		return '</' . $heading_tag . '>';
468
+	}
469
+
470
+
471
+
472
+	/**
473
+	 * @param string $content
474
+	 * @return string
475
+	 */
476
+	protected static function grey_span($content = '')
477
+	{
478
+		if (EEH_Debug_Tools::plainOutput()) {
479
+			return $content;
480
+		}
481
+		return '<span style="color:#999">' . $content . '</span>';
482
+	}
483
+
484
+
485
+
486
+	/**
487
+	 * @param string $file
488
+	 * @param int    $line
489
+	 * @return string
490
+	 */
491
+	protected static function file_and_line($file, $line, $heading_tag)
492
+	{
493
+		if ($file === '' || $line === '') {
494
+			return '';
495
+		}
496
+		$file = str_replace(EE_PLUGIN_DIR_PATH, '/', $file);
497
+		if (EEH_Debug_Tools::plainOutput()) {
498
+			if ($heading_tag === 'h1' || $heading_tag === 'h2') {
499
+				return " ({$file})";
500
+			}
501
+			return '';
502
+		}
503
+		return '<br /><span style="font-size:9px;font-weight:normal;color:#666;line-height: 12px;">'
504
+			   . $file
505
+			   . '<br />line no: '
506
+			   . $line
507
+			   . '</span>';
508
+	}
509
+
510
+
511
+
512
+	/**
513
+	 * @param string $content
514
+	 * @return string
515
+	 */
516
+	protected static function orange_span($content = '')
517
+	{
518
+		if (EEH_Debug_Tools::plainOutput()) {
519
+			return $content;
520
+		}
521
+		return '<span style="color:#E76700">' . $content . '</span>';
522
+	}
523
+
524
+
525
+
526
+	/**
527
+	 * @param mixed $var
528
+	 * @return string
529
+	 */
530
+	protected static function pre_span($var)
531
+	{
532
+		ob_start();
533
+		var_dump($var);
534
+		$var = ob_get_clean();
535
+		if (EEH_Debug_Tools::plainOutput()) {
536
+			return $var;
537
+		}
538
+		return '<pre style="color:#999; padding:1em; background: #fff">' . $var . '</pre>';
539
+	}
540
+
541
+
542
+
543
+	/**
544
+	 * @param mixed      $var
545
+	 * @param string     $var_name
546
+	 * @param string     $file
547
+	 * @param int|string $line
548
+	 * @param int|string $heading_tag
549
+	 * @param bool       $die
550
+	 */
551
+	public static function printr(
552
+		$var,
553
+		$var_name = '',
554
+		$file = '',
555
+		$line = '',
556
+		$heading_tag = 5,
557
+		$die = false
558
+	) {
559
+		// return;
560
+		$file = str_replace(rtrim(ABSPATH, '\\/'), '', $file);
561
+		if (empty($var) && empty($var_name)) {
562
+			$var = $file;
563
+			$var_name = "line $line";
564
+			$file = '';
565
+			$line = '';
566
+		}
567
+		$margin = is_admin() ? ' 180px' : '0';
568
+		// $print_r = false;
569
+		if (is_string($var)) {
570
+			EEH_Debug_Tools::printv($var, $var_name, $file, $line, $heading_tag, $die, $margin);
571
+			return;
572
+		}
573
+		if (is_object($var)) {
574
+			$var_name = ! $var_name ? 'object' : $var_name;
575
+			// $print_r = true;
576
+		} elseif (is_array($var)) {
577
+			$var_name = ! $var_name ? 'array' : $var_name;
578
+			// $print_r = true;
579
+		} elseif (is_numeric($var)) {
580
+			$var_name = ! $var_name ? 'numeric' : $var_name;
581
+		} elseif ($var === null) {
582
+			$var_name = ! $var_name ? 'null' : $var_name;
583
+		}
584
+		$var_name = ucwords(str_replace(array('$', '_'), array('', ' '), $var_name));
585
+		$heading_tag = EEH_Debug_Tools::headingTag($heading_tag);
586
+		$result = EEH_Debug_Tools::headingSpacer($heading_tag);
587
+		$result .= EEH_Debug_Tools::heading($var_name, $heading_tag, $margin, $line);
588
+		$result .= EEH_Debug_Tools::grey_span(' : ') . EEH_Debug_Tools::orange_span(
589
+			EEH_Debug_Tools::pre_span($var)
590
+		);
591
+		$result .= EEH_Debug_Tools::file_and_line($file, $line, $heading_tag);
592
+		$result .= EEH_Debug_Tools::headingX($heading_tag);
593
+		if ($die) {
594
+			die($result);
595
+		}
596
+		echo $result;
597
+	}
598
+
599
+
600
+
601
+	/******************** deprecated ********************/
602
+
603
+
604
+
605
+	/**
606
+	 * @deprecated 4.9.39.rc.034
607
+	 */
608
+	public function reset_times()
609
+	{
610
+		Benchmark::resetTimes();
611
+	}
612
+
613
+
614
+
615
+	/**
616
+	 * @deprecated 4.9.39.rc.034
617
+	 * @param null $timer_name
618
+	 */
619
+	public function start_timer($timer_name = null)
620
+	{
621
+		Benchmark::startTimer($timer_name);
622
+	}
623
+
624
+
625
+
626
+	/**
627
+	 * @deprecated 4.9.39.rc.034
628
+	 * @param string $timer_name
629
+	 */
630
+	public function stop_timer($timer_name = '')
631
+	{
632
+		Benchmark::stopTimer($timer_name);
633
+	}
634
+
635
+
636
+
637
+	/**
638
+	 * @deprecated 4.9.39.rc.034
639
+	 * @param string  $label      The label to show for this time eg "Start of calling Some_Class::some_function"
640
+	 * @param boolean $output_now whether to echo now, or wait until EEH_Debug_Tools::show_times() is called
641
+	 * @return void
642
+	 */
643
+	public function measure_memory($label, $output_now = false)
644
+	{
645
+		Benchmark::measureMemory($label, $output_now);
646
+	}
647
+
648
+
649
+
650
+	/**
651
+	 * @deprecated 4.9.39.rc.034
652
+	 * @param int $size
653
+	 * @return string
654
+	 */
655
+	public function convert($size)
656
+	{
657
+		return Benchmark::convert($size);
658
+	}
659
+
660
+
661
+
662
+	/**
663
+	 * @deprecated 4.9.39.rc.034
664
+	 * @param bool $output_now
665
+	 * @return string
666
+	 */
667
+	public function show_times($output_now = true)
668
+	{
669
+		return Benchmark::displayResults($output_now);
670
+	}
671
+
672
+
673
+
674
+	/**
675
+	 * @deprecated 4.9.39.rc.034
676
+	 * @param string $timer_name
677
+	 * @param float  $total_time
678
+	 * @return string
679
+	 */
680
+	public function format_time($timer_name, $total_time)
681
+	{
682
+		return Benchmark::formatTime($timer_name, $total_time);
683
+	}
684 684
 }
685 685
 
686 686
 
@@ -690,31 +690,31 @@  discard block
 block discarded – undo
690 690
  * Plugin URI: http://upthemes.com/plugins/kint-debugger/
691 691
  */
692 692
 if (class_exists('Kint') && ! function_exists('dump_wp_query')) {
693
-    function dump_wp_query()
694
-    {
695
-        global $wp_query;
696
-        d($wp_query);
697
-    }
693
+	function dump_wp_query()
694
+	{
695
+		global $wp_query;
696
+		d($wp_query);
697
+	}
698 698
 }
699 699
 /**
700 700
  * borrowed from Kint Debugger
701 701
  * Plugin URI: http://upthemes.com/plugins/kint-debugger/
702 702
  */
703 703
 if (class_exists('Kint') && ! function_exists('dump_wp')) {
704
-    function dump_wp()
705
-    {
706
-        global $wp;
707
-        d($wp);
708
-    }
704
+	function dump_wp()
705
+	{
706
+		global $wp;
707
+		d($wp);
708
+	}
709 709
 }
710 710
 /**
711 711
  * borrowed from Kint Debugger
712 712
  * Plugin URI: http://upthemes.com/plugins/kint-debugger/
713 713
  */
714 714
 if (class_exists('Kint') && ! function_exists('dump_post')) {
715
-    function dump_post()
716
-    {
717
-        global $post;
718
-        d($post);
719
-    }
715
+	function dump_post()
716
+	{
717
+		global $post;
718
+		d($post);
719
+	}
720 720
 }
Please login to merge, or discard this patch.
core/admin/EE_Admin_Page_CPT.core.php 1 patch
Indentation   +1485 added lines, -1485 removed lines patch added patch discarded remove patch
@@ -28,474 +28,474 @@  discard block
 block discarded – undo
28 28
 {
29 29
 
30 30
 
31
-    /**
32
-     * This gets set in _setup_cpt
33
-     * It will contain the object for the custom post type.
34
-     *
35
-     * @var EE_CPT_Base
36
-     */
37
-    protected $_cpt_object;
38
-
39
-
40
-    /**
41
-     * a boolean flag to set whether the current route is a cpt route or not.
42
-     *
43
-     * @var bool
44
-     */
45
-    protected $_cpt_route = false;
46
-
47
-
48
-    /**
49
-     * This property allows cpt classes to define multiple routes as cpt routes.
50
-     * //in this array we define what the custom post type for this route is.
51
-     * array(
52
-     * 'route_name' => 'custom_post_type_slug'
53
-     * )
54
-     *
55
-     * @var array
56
-     */
57
-    protected $_cpt_routes = array();
58
-
59
-
60
-    /**
61
-     * This simply defines what the corresponding routes WP will be redirected to after completing a post save/update.
62
-     * in this format:
63
-     * array(
64
-     * 'post_type_slug' => 'edit_route'
65
-     * )
66
-     *
67
-     * @var array
68
-     */
69
-    protected $_cpt_edit_routes = array();
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
-     * This will hold an array of autosave containers that will be used to obtain input values and hook into the WP
91
-     * autosave so we can save our inputs on the save_post hook!  Children classes should add to this array by using
92
-     * the _register_autosave_containers() method so that we don't override any other containers already registered.
93
-     * Registration of containers should be done before load_page_dependencies() is run.
94
-     *
95
-     * @var array()
96
-     */
97
-    protected $_autosave_containers = array();
98
-    protected $_autosave_fields = array();
99
-
100
-    /**
101
-     * Array mapping from admin actions to their equivalent wp core pages for custom post types. So when a user visits
102
-     * a page for an action, it will appear as if they were visiting the wp core page for that custom post type
103
-     *
104
-     * @var array
105
-     */
106
-    protected $_pagenow_map;
107
-
108
-
109
-    /**
110
-     * This is hooked into the WordPress do_action('save_post') hook and runs after the custom post type has been
111
-     * saved.  Child classes are required to declare this method.  Typically you would use this to save any additional
112
-     * data. Keep in mind also that "save_post" runs on EVERY post update to the database. ALSO very important.  When a
113
-     * post transitions from scheduled to published, the save_post action is fired but you will NOT have any _POST data
114
-     * containing any extra info you may have from other meta saves.  So MAKE sure that you handle this accordingly.
115
-     *
116
-     * @access protected
117
-     * @abstract
118
-     * @param  string      $post_id The ID of the cpt that was saved (so you can link relationally)
119
-     * @param  EE_CPT_Base $post    The post object of the cpt that was saved.
120
-     * @return void
121
-     */
122
-    abstract protected function _insert_update_cpt_item($post_id, $post);
123
-
124
-
125
-    /**
126
-     * This is hooked into the WordPress do_action('trashed_post') hook and runs after a cpt has been trashed.
127
-     *
128
-     * @abstract
129
-     * @access public
130
-     * @param  string $post_id The ID of the cpt that was trashed
131
-     * @return void
132
-     */
133
-    abstract public function trash_cpt_item($post_id);
134
-
135
-
136
-    /**
137
-     * This is hooked into the WordPress do_action('untrashed_post') hook and runs after a cpt has been untrashed
138
-     *
139
-     * @param  string $post_id theID of the cpt that was untrashed
140
-     * @return void
141
-     */
142
-    abstract public function restore_cpt_item($post_id);
143
-
144
-
145
-    /**
146
-     * This is hooked into the WordPress do_action('delete_cpt_item') hook and runs after a cpt has been fully deleted
147
-     * from the db
148
-     *
149
-     * @param  string $post_id the ID of the cpt that was deleted
150
-     * @return void
151
-     */
152
-    abstract public function delete_cpt_item($post_id);
153
-
154
-
155
-    /**
156
-     * Just utilizing the method EE_Admin exposes for doing things before page setup.
157
-     *
158
-     * @access protected
159
-     * @return void
160
-     */
161
-    protected function _before_page_setup()
162
-    {
163
-        $page = isset($this->_req_data['page']) ? $this->_req_data['page'] : $this->page_slug;
164
-        $this->_cpt_routes = array_merge(
165
-            array(
166
-                'create_new' => $this->page_slug,
167
-                'edit'       => $this->page_slug,
168
-                'trash'      => $this->page_slug,
169
-            ),
170
-            $this->_cpt_routes
171
-        );
172
-        // let's see if the current route has a value for cpt_object_slug if it does we use that instead of the page
173
-        $this->_cpt_object = isset($this->_req_data['action']) && isset($this->_cpt_routes[ $this->_req_data['action'] ])
174
-            ? get_post_type_object($this->_cpt_routes[ $this->_req_data['action'] ])
175
-            : get_post_type_object($page);
176
-        // tweak pagenow for page loading.
177
-        if (! $this->_pagenow_map) {
178
-            $this->_pagenow_map = array(
179
-                'create_new' => 'post-new.php',
180
-                'edit'       => 'post.php',
181
-                'trash'      => 'post.php',
182
-            );
183
-        }
184
-        add_action('current_screen', array($this, 'modify_pagenow'));
185
-        // TODO the below will need to be reworked to account for the cpt routes that are NOT based off of page but action param.
186
-        // get current page from autosave
187
-        $current_page = isset($this->_req_data['ee_autosave_data']['ee-cpt-hidden-inputs']['current_page'])
188
-            ? $this->_req_data['ee_autosave_data']['ee-cpt-hidden-inputs']['current_page']
189
-            : null;
190
-        $this->_current_page = isset($this->_req_data['current_page'])
191
-            ? $this->_req_data['current_page']
192
-            : $current_page;
193
-        // autosave... make sure its only for the correct page
194
-        // if ( ! empty($this->_current_page) && $this->_current_page == $this->page_slug) {
195
-        // setup autosave ajax hook
196
-        // add_action('wp_ajax_ee-autosave', array( $this, 'do_extra_autosave_stuff' ), 10 ); //TODO reactivate when 4.2 autosave is implemented
197
-        // }
198
-    }
199
-
200
-
201
-    /**
202
-     * Simply ensure that we simulate the correct post route for cpt screens
203
-     *
204
-     * @param WP_Screen $current_screen
205
-     * @return void
206
-     */
207
-    public function modify_pagenow($current_screen)
208
-    {
209
-        global $pagenow, $hook_suffix;
210
-        // possibly reset pagenow.
211
-        if (! empty($this->_req_data['page'])
212
-            && $this->_req_data['page'] == $this->page_slug
213
-            && ! empty($this->_req_data['action'])
214
-            && isset($this->_pagenow_map[ $this->_req_data['action'] ])
215
-        ) {
216
-            $pagenow = $this->_pagenow_map[ $this->_req_data['action'] ];
217
-            $hook_suffix = $pagenow;
218
-        }
219
-    }
220
-
221
-
222
-    /**
223
-     * This method is used to register additional autosave containers to the _autosave_containers property.
224
-     *
225
-     * @todo We should automate this at some point by creating a wrapper for add_post_metabox and in our wrapper we
226
-     *       automatically register the id for the post metabox as a container.
227
-     * @param  array $ids an array of ids for containers that hold form inputs we want autosave to pickup.  Typically
228
-     *                    you would send along the id of a metabox container.
229
-     * @return void
230
-     */
231
-    protected function _register_autosave_containers($ids)
232
-    {
233
-        $this->_autosave_containers = array_merge($this->_autosave_fields, (array) $ids);
234
-    }
235
-
236
-
237
-    /**
238
-     * Something nifty.  We're going to loop through all the registered metaboxes and if the CALLBACK is an instance of
239
-     * EE_Admin_Page OR EE_Admin_Hooks, then we'll add the id to our _autosave_containers array.
240
-     */
241
-    protected function _set_autosave_containers()
242
-    {
243
-        global $wp_meta_boxes;
244
-        $containers = array();
245
-        if (empty($wp_meta_boxes)) {
246
-            return;
247
-        }
248
-        $current_metaboxes = isset($wp_meta_boxes[ $this->page_slug ]) ? $wp_meta_boxes[ $this->page_slug ] : array();
249
-        foreach ($current_metaboxes as $box_context) {
250
-            foreach ($box_context as $box_details) {
251
-                foreach ($box_details as $box) {
252
-                    if (is_array($box['callback'])
253
-                        && (
254
-                            $box['callback'][0] instanceof EE_Admin_Page
255
-                            || $box['callback'][0] instanceof EE_Admin_Hooks
256
-                        )
257
-                    ) {
258
-                        $containers[] = $box['id'];
259
-                    }
260
-                }
261
-            }
262
-        }
263
-        $this->_autosave_containers = array_merge($this->_autosave_containers, $containers);
264
-        // add hidden inputs container
265
-        $this->_autosave_containers[] = 'ee-cpt-hidden-inputs';
266
-    }
267
-
268
-
269
-    protected function _load_autosave_scripts_styles()
270
-    {
271
-        /*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 );
31
+	/**
32
+	 * This gets set in _setup_cpt
33
+	 * It will contain the object for the custom post type.
34
+	 *
35
+	 * @var EE_CPT_Base
36
+	 */
37
+	protected $_cpt_object;
38
+
39
+
40
+	/**
41
+	 * a boolean flag to set whether the current route is a cpt route or not.
42
+	 *
43
+	 * @var bool
44
+	 */
45
+	protected $_cpt_route = false;
46
+
47
+
48
+	/**
49
+	 * This property allows cpt classes to define multiple routes as cpt routes.
50
+	 * //in this array we define what the custom post type for this route is.
51
+	 * array(
52
+	 * 'route_name' => 'custom_post_type_slug'
53
+	 * )
54
+	 *
55
+	 * @var array
56
+	 */
57
+	protected $_cpt_routes = array();
58
+
59
+
60
+	/**
61
+	 * This simply defines what the corresponding routes WP will be redirected to after completing a post save/update.
62
+	 * in this format:
63
+	 * array(
64
+	 * 'post_type_slug' => 'edit_route'
65
+	 * )
66
+	 *
67
+	 * @var array
68
+	 */
69
+	protected $_cpt_edit_routes = array();
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
+	 * This will hold an array of autosave containers that will be used to obtain input values and hook into the WP
91
+	 * autosave so we can save our inputs on the save_post hook!  Children classes should add to this array by using
92
+	 * the _register_autosave_containers() method so that we don't override any other containers already registered.
93
+	 * Registration of containers should be done before load_page_dependencies() is run.
94
+	 *
95
+	 * @var array()
96
+	 */
97
+	protected $_autosave_containers = array();
98
+	protected $_autosave_fields = array();
99
+
100
+	/**
101
+	 * Array mapping from admin actions to their equivalent wp core pages for custom post types. So when a user visits
102
+	 * a page for an action, it will appear as if they were visiting the wp core page for that custom post type
103
+	 *
104
+	 * @var array
105
+	 */
106
+	protected $_pagenow_map;
107
+
108
+
109
+	/**
110
+	 * This is hooked into the WordPress do_action('save_post') hook and runs after the custom post type has been
111
+	 * saved.  Child classes are required to declare this method.  Typically you would use this to save any additional
112
+	 * data. Keep in mind also that "save_post" runs on EVERY post update to the database. ALSO very important.  When a
113
+	 * post transitions from scheduled to published, the save_post action is fired but you will NOT have any _POST data
114
+	 * containing any extra info you may have from other meta saves.  So MAKE sure that you handle this accordingly.
115
+	 *
116
+	 * @access protected
117
+	 * @abstract
118
+	 * @param  string      $post_id The ID of the cpt that was saved (so you can link relationally)
119
+	 * @param  EE_CPT_Base $post    The post object of the cpt that was saved.
120
+	 * @return void
121
+	 */
122
+	abstract protected function _insert_update_cpt_item($post_id, $post);
123
+
124
+
125
+	/**
126
+	 * This is hooked into the WordPress do_action('trashed_post') hook and runs after a cpt has been trashed.
127
+	 *
128
+	 * @abstract
129
+	 * @access public
130
+	 * @param  string $post_id The ID of the cpt that was trashed
131
+	 * @return void
132
+	 */
133
+	abstract public function trash_cpt_item($post_id);
134
+
135
+
136
+	/**
137
+	 * This is hooked into the WordPress do_action('untrashed_post') hook and runs after a cpt has been untrashed
138
+	 *
139
+	 * @param  string $post_id theID of the cpt that was untrashed
140
+	 * @return void
141
+	 */
142
+	abstract public function restore_cpt_item($post_id);
143
+
144
+
145
+	/**
146
+	 * This is hooked into the WordPress do_action('delete_cpt_item') hook and runs after a cpt has been fully deleted
147
+	 * from the db
148
+	 *
149
+	 * @param  string $post_id the ID of the cpt that was deleted
150
+	 * @return void
151
+	 */
152
+	abstract public function delete_cpt_item($post_id);
153
+
154
+
155
+	/**
156
+	 * Just utilizing the method EE_Admin exposes for doing things before page setup.
157
+	 *
158
+	 * @access protected
159
+	 * @return void
160
+	 */
161
+	protected function _before_page_setup()
162
+	{
163
+		$page = isset($this->_req_data['page']) ? $this->_req_data['page'] : $this->page_slug;
164
+		$this->_cpt_routes = array_merge(
165
+			array(
166
+				'create_new' => $this->page_slug,
167
+				'edit'       => $this->page_slug,
168
+				'trash'      => $this->page_slug,
169
+			),
170
+			$this->_cpt_routes
171
+		);
172
+		// let's see if the current route has a value for cpt_object_slug if it does we use that instead of the page
173
+		$this->_cpt_object = isset($this->_req_data['action']) && isset($this->_cpt_routes[ $this->_req_data['action'] ])
174
+			? get_post_type_object($this->_cpt_routes[ $this->_req_data['action'] ])
175
+			: get_post_type_object($page);
176
+		// tweak pagenow for page loading.
177
+		if (! $this->_pagenow_map) {
178
+			$this->_pagenow_map = array(
179
+				'create_new' => 'post-new.php',
180
+				'edit'       => 'post.php',
181
+				'trash'      => 'post.php',
182
+			);
183
+		}
184
+		add_action('current_screen', array($this, 'modify_pagenow'));
185
+		// TODO the below will need to be reworked to account for the cpt routes that are NOT based off of page but action param.
186
+		// get current page from autosave
187
+		$current_page = isset($this->_req_data['ee_autosave_data']['ee-cpt-hidden-inputs']['current_page'])
188
+			? $this->_req_data['ee_autosave_data']['ee-cpt-hidden-inputs']['current_page']
189
+			: null;
190
+		$this->_current_page = isset($this->_req_data['current_page'])
191
+			? $this->_req_data['current_page']
192
+			: $current_page;
193
+		// autosave... make sure its only for the correct page
194
+		// if ( ! empty($this->_current_page) && $this->_current_page == $this->page_slug) {
195
+		// setup autosave ajax hook
196
+		// add_action('wp_ajax_ee-autosave', array( $this, 'do_extra_autosave_stuff' ), 10 ); //TODO reactivate when 4.2 autosave is implemented
197
+		// }
198
+	}
199
+
200
+
201
+	/**
202
+	 * Simply ensure that we simulate the correct post route for cpt screens
203
+	 *
204
+	 * @param WP_Screen $current_screen
205
+	 * @return void
206
+	 */
207
+	public function modify_pagenow($current_screen)
208
+	{
209
+		global $pagenow, $hook_suffix;
210
+		// possibly reset pagenow.
211
+		if (! empty($this->_req_data['page'])
212
+			&& $this->_req_data['page'] == $this->page_slug
213
+			&& ! empty($this->_req_data['action'])
214
+			&& isset($this->_pagenow_map[ $this->_req_data['action'] ])
215
+		) {
216
+			$pagenow = $this->_pagenow_map[ $this->_req_data['action'] ];
217
+			$hook_suffix = $pagenow;
218
+		}
219
+	}
220
+
221
+
222
+	/**
223
+	 * This method is used to register additional autosave containers to the _autosave_containers property.
224
+	 *
225
+	 * @todo We should automate this at some point by creating a wrapper for add_post_metabox and in our wrapper we
226
+	 *       automatically register the id for the post metabox as a container.
227
+	 * @param  array $ids an array of ids for containers that hold form inputs we want autosave to pickup.  Typically
228
+	 *                    you would send along the id of a metabox container.
229
+	 * @return void
230
+	 */
231
+	protected function _register_autosave_containers($ids)
232
+	{
233
+		$this->_autosave_containers = array_merge($this->_autosave_fields, (array) $ids);
234
+	}
235
+
236
+
237
+	/**
238
+	 * Something nifty.  We're going to loop through all the registered metaboxes and if the CALLBACK is an instance of
239
+	 * EE_Admin_Page OR EE_Admin_Hooks, then we'll add the id to our _autosave_containers array.
240
+	 */
241
+	protected function _set_autosave_containers()
242
+	{
243
+		global $wp_meta_boxes;
244
+		$containers = array();
245
+		if (empty($wp_meta_boxes)) {
246
+			return;
247
+		}
248
+		$current_metaboxes = isset($wp_meta_boxes[ $this->page_slug ]) ? $wp_meta_boxes[ $this->page_slug ] : array();
249
+		foreach ($current_metaboxes as $box_context) {
250
+			foreach ($box_context as $box_details) {
251
+				foreach ($box_details as $box) {
252
+					if (is_array($box['callback'])
253
+						&& (
254
+							$box['callback'][0] instanceof EE_Admin_Page
255
+							|| $box['callback'][0] instanceof EE_Admin_Hooks
256
+						)
257
+					) {
258
+						$containers[] = $box['id'];
259
+					}
260
+				}
261
+			}
262
+		}
263
+		$this->_autosave_containers = array_merge($this->_autosave_containers, $containers);
264
+		// add hidden inputs container
265
+		$this->_autosave_containers[] = 'ee-cpt-hidden-inputs';
266
+	}
267
+
268
+
269
+	protected function _load_autosave_scripts_styles()
270
+	{
271
+		/*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 );
272 272
         wp_enqueue_script('cpt-autosave');/**/ // todo re-enable when we start doing autosave again in 4.2
273 273
 
274
-        // filter _autosave_containers
275
-        $containers = apply_filters(
276
-            'FHEE__EE_Admin_Page_CPT___load_autosave_scripts_styles__containers',
277
-            $this->_autosave_containers,
278
-            $this
279
-        );
280
-        $containers = apply_filters(
281
-            'FHEE__EE_Admin_Page_CPT__' . get_class($this) . '___load_autosave_scripts_styles__containers',
282
-            $containers,
283
-            $this
284
-        );
285
-
286
-        wp_localize_script(
287
-            'event_editor_js',
288
-            'EE_AUTOSAVE_IDS',
289
-            $containers
290
-        ); // todo once we enable autosaves, this needs to be switched to localize with "cpt-autosave"
291
-
292
-        $unsaved_data_msg = array(
293
-            'eventmsg'     => sprintf(
294
-                __(
295
-                    "The changes you made to this %s will be lost if you navigate away from this page.",
296
-                    'event_espresso'
297
-                ),
298
-                $this->_cpt_object->labels->singular_name
299
-            ),
300
-            'inputChanged' => 0,
301
-        );
302
-        wp_localize_script('event_editor_js', 'UNSAVED_DATA_MSG', $unsaved_data_msg);
303
-    }
304
-
305
-
306
-    public function load_page_dependencies()
307
-    {
308
-        try {
309
-            $this->_load_page_dependencies();
310
-        } catch (EE_Error $e) {
311
-            $e->get_error();
312
-        }
313
-    }
314
-
315
-
316
-    /**
317
-     * overloading the EE_Admin_Page parent load_page_dependencies so we can get the cpt stuff added in appropriately
318
-     *
319
-     * @access protected
320
-     * @return void
321
-     */
322
-    protected function _load_page_dependencies()
323
-    {
324
-        // we only add stuff if this is a cpt_route!
325
-        if (! $this->_cpt_route) {
326
-            parent::_load_page_dependencies();
327
-            return;
328
-        }
329
-        // now let's do some automatic filters into the wp_system
330
-        // and we'll check to make sure the CHILD class
331
-        // automatically has the required methods in place.
332
-        // the following filters are for setting all the redirects
333
-        // on DEFAULT WP custom post type actions
334
-        // let's add a hidden input to the post-edit form
335
-        // so we know when we have to trigger our custom redirects!
336
-        // Otherwise the redirects will happen on ALL post saves which wouldn't be good of course!
337
-        add_action('edit_form_after_title', array($this, 'cpt_post_form_hidden_input'));
338
-        // inject our Admin page nav tabs...
339
-        // let's make sure the nav tabs are set if they aren't already
340
-        // if ( empty( $this->_nav_tabs ) ) $this->_set_nav_tabs();
341
-        add_action('post_edit_form_tag', array($this, 'inject_nav_tabs'));
342
-        // modify the post_updated messages array
343
-        add_action('post_updated_messages', array($this, 'post_update_messages'), 10);
344
-        // add shortlink button to cpt edit screens.  We can do this as a universal thing BECAUSE,
345
-        // cpts use the same format for shortlinks as posts!
346
-        add_filter('pre_get_shortlink', array($this, 'add_shortlink_button_to_editor'), 10, 4);
347
-        // This basically allows us to change the title of the "publish" metabox area
348
-        // on CPT pages by setting a 'publishbox' value in the $_labels property array in the child class.
349
-        if (! empty($this->_labels['publishbox'])) {
350
-            $box_label = is_array($this->_labels['publishbox'])
351
-                         && isset($this->_labels['publishbox'][ $this->_req_action ])
352
-                ? $this->_labels['publishbox'][ $this->_req_action ]
353
-                : $this->_labels['publishbox'];
354
-            add_meta_box(
355
-                'submitdiv',
356
-                $box_label,
357
-                'post_submit_meta_box',
358
-                $this->_cpt_routes[ $this->_req_action ],
359
-                'side',
360
-                'core'
361
-            );
362
-        }
363
-        // let's add page_templates metabox if this cpt added support for it.
364
-        if ($this->_supports_page_templates($this->_cpt_object->name)) {
365
-            add_meta_box(
366
-                'page_templates',
367
-                __('Page Template', 'event_espresso'),
368
-                array($this, 'page_template_meta_box'),
369
-                $this->_cpt_routes[ $this->_req_action ],
370
-                'side',
371
-                'default'
372
-            );
373
-        }
374
-        // this is a filter that allows the addition of extra html after the permalink field on the wp post edit-form
375
-        if (method_exists($this, 'extra_permalink_field_buttons')) {
376
-            add_filter('get_sample_permalink_html', array($this, 'extra_permalink_field_buttons'), 10, 4);
377
-        }
378
-        // add preview button
379
-        add_filter('get_sample_permalink_html', array($this, 'preview_button_html'), 5, 4);
380
-        // insert our own post_stati dropdown
381
-        add_action('post_submitbox_misc_actions', array($this, 'custom_post_stati_dropdown'), 10);
382
-        // This allows adding additional information to the publish post submitbox on the wp post edit form
383
-        if (method_exists($this, 'extra_misc_actions_publish_box')) {
384
-            add_action('post_submitbox_misc_actions', array($this, 'extra_misc_actions_publish_box'), 10);
385
-        }
386
-        // This allows for adding additional stuff after the title field on the wp post edit form.
387
-        // This is also before the wp_editor for post description field.
388
-        if (method_exists($this, 'edit_form_after_title')) {
389
-            add_action('edit_form_after_title', array($this, 'edit_form_after_title'), 10);
390
-        }
391
-        /**
392
-         * Filtering WP's esc_url to capture urls pointing to core wp routes so they point to our route.
393
-         */
394
-        add_filter('clean_url', array($this, 'switch_core_wp_urls_with_ours'), 10, 3);
395
-        parent::_load_page_dependencies();
396
-        // notice we are ALSO going to load the pagenow hook set for this route
397
-        // (see _before_page_setup for the reset of the pagenow global ).
398
-        // This is for any plugins that are doing things properly
399
-        // and hooking into the load page hook for core wp cpt routes.
400
-        global $pagenow;
401
-        do_action('load-' . $pagenow);
402
-        $this->modify_current_screen();
403
-        add_action('admin_enqueue_scripts', array($this, 'setup_autosave_hooks'), 30);
404
-        // we route REALLY early.
405
-        try {
406
-            $this->_route_admin_request();
407
-        } catch (EE_Error $e) {
408
-            $e->get_error();
409
-        }
410
-    }
411
-
412
-
413
-    /**
414
-     * Since we don't want users going to default core wp routes, this will check any wp urls run through the
415
-     * esc_url() method and if we see a url matching a pattern for our routes, we'll modify it to point to OUR
416
-     * route instead.
417
-     *
418
-     * @param string $good_protocol_url The escaped url.
419
-     * @param string $original_url      The original url.
420
-     * @param string $_context          The context sent to the esc_url method.
421
-     * @return string possibly a new url for our route.
422
-     */
423
-    public function switch_core_wp_urls_with_ours($good_protocol_url, $original_url, $_context)
424
-    {
425
-        $routes_to_match = array(
426
-            0 => array(
427
-                'edit.php?post_type=espresso_attendees',
428
-                'admin.php?page=espresso_registrations&action=contact_list',
429
-            ),
430
-            1 => array(
431
-                'edit.php?post_type=' . $this->_cpt_object->name,
432
-                'admin.php?page=' . $this->_cpt_object->name,
433
-            ),
434
-        );
435
-        foreach ($routes_to_match as $route_matches) {
436
-            if (strpos($good_protocol_url, $route_matches[0]) !== false) {
437
-                return str_replace($route_matches[0], $route_matches[1], $good_protocol_url);
438
-            }
439
-        }
440
-        return $good_protocol_url;
441
-    }
442
-
443
-
444
-    /**
445
-     * Determine whether the current cpt supports page templates or not.
446
-     *
447
-     * @since %VER%
448
-     * @param string $cpt_name The cpt slug we're checking on.
449
-     * @return bool True supported, false not.
450
-     * @throws InvalidArgumentException
451
-     * @throws InvalidDataTypeException
452
-     * @throws InvalidInterfaceException
453
-     */
454
-    private function _supports_page_templates($cpt_name)
455
-    {
456
-        /** @var EventEspresso\core\domain\entities\custom_post_types\CustomPostTypeDefinitions $custom_post_types */
457
-        $custom_post_types = LoaderFactory::getLoader()->getShared(
458
-            'EventEspresso\core\domain\entities\custom_post_types\CustomPostTypeDefinitions'
459
-        );
460
-        $cpt_args = $custom_post_types->getDefinitions();
461
-        $cpt_args = isset($cpt_args[ $cpt_name ]) ? $cpt_args[ $cpt_name ]['args'] : array();
462
-        $cpt_has_support = ! empty($cpt_args['page_templates']);
463
-
464
-        // if the installed version of WP is > 4.7 we do some additional checks.
465
-        if (RecommendedVersions::compareWordPressVersion('4.7', '>=')) {
466
-            $post_templates = wp_get_theme()->get_post_templates();
467
-            // if there are $post_templates for this cpt, then we return false for this method because
468
-            // that means we aren't going to load our page template manager and leave that up to the native
469
-            // cpt template manager.
470
-            $cpt_has_support = ! isset($post_templates[ $cpt_name ]) ? $cpt_has_support : false;
471
-        }
472
-
473
-        return $cpt_has_support;
474
-    }
475
-
476
-
477
-    /**
478
-     * Callback for the page_templates metabox selector.
479
-     *
480
-     * @since %VER%
481
-     * @return void
482
-     */
483
-    public function page_template_meta_box()
484
-    {
485
-        global $post;
486
-        $template = '';
487
-
488
-        if (RecommendedVersions::compareWordPressVersion('4.7', '>=')) {
489
-            $page_template_count = count(get_page_templates());
490
-        } else {
491
-            $page_template_count = count(get_page_templates($post));
492
-        };
493
-
494
-        if ($page_template_count) {
495
-            $page_template = get_post_meta($post->ID, '_wp_page_template', true);
496
-            $template = ! empty($page_template) ? $page_template : '';
497
-        }
498
-        ?>
274
+		// filter _autosave_containers
275
+		$containers = apply_filters(
276
+			'FHEE__EE_Admin_Page_CPT___load_autosave_scripts_styles__containers',
277
+			$this->_autosave_containers,
278
+			$this
279
+		);
280
+		$containers = apply_filters(
281
+			'FHEE__EE_Admin_Page_CPT__' . get_class($this) . '___load_autosave_scripts_styles__containers',
282
+			$containers,
283
+			$this
284
+		);
285
+
286
+		wp_localize_script(
287
+			'event_editor_js',
288
+			'EE_AUTOSAVE_IDS',
289
+			$containers
290
+		); // todo once we enable autosaves, this needs to be switched to localize with "cpt-autosave"
291
+
292
+		$unsaved_data_msg = array(
293
+			'eventmsg'     => sprintf(
294
+				__(
295
+					"The changes you made to this %s will be lost if you navigate away from this page.",
296
+					'event_espresso'
297
+				),
298
+				$this->_cpt_object->labels->singular_name
299
+			),
300
+			'inputChanged' => 0,
301
+		);
302
+		wp_localize_script('event_editor_js', 'UNSAVED_DATA_MSG', $unsaved_data_msg);
303
+	}
304
+
305
+
306
+	public function load_page_dependencies()
307
+	{
308
+		try {
309
+			$this->_load_page_dependencies();
310
+		} catch (EE_Error $e) {
311
+			$e->get_error();
312
+		}
313
+	}
314
+
315
+
316
+	/**
317
+	 * overloading the EE_Admin_Page parent load_page_dependencies so we can get the cpt stuff added in appropriately
318
+	 *
319
+	 * @access protected
320
+	 * @return void
321
+	 */
322
+	protected function _load_page_dependencies()
323
+	{
324
+		// we only add stuff if this is a cpt_route!
325
+		if (! $this->_cpt_route) {
326
+			parent::_load_page_dependencies();
327
+			return;
328
+		}
329
+		// now let's do some automatic filters into the wp_system
330
+		// and we'll check to make sure the CHILD class
331
+		// automatically has the required methods in place.
332
+		// the following filters are for setting all the redirects
333
+		// on DEFAULT WP custom post type actions
334
+		// let's add a hidden input to the post-edit form
335
+		// so we know when we have to trigger our custom redirects!
336
+		// Otherwise the redirects will happen on ALL post saves which wouldn't be good of course!
337
+		add_action('edit_form_after_title', array($this, 'cpt_post_form_hidden_input'));
338
+		// inject our Admin page nav tabs...
339
+		// let's make sure the nav tabs are set if they aren't already
340
+		// if ( empty( $this->_nav_tabs ) ) $this->_set_nav_tabs();
341
+		add_action('post_edit_form_tag', array($this, 'inject_nav_tabs'));
342
+		// modify the post_updated messages array
343
+		add_action('post_updated_messages', array($this, 'post_update_messages'), 10);
344
+		// add shortlink button to cpt edit screens.  We can do this as a universal thing BECAUSE,
345
+		// cpts use the same format for shortlinks as posts!
346
+		add_filter('pre_get_shortlink', array($this, 'add_shortlink_button_to_editor'), 10, 4);
347
+		// This basically allows us to change the title of the "publish" metabox area
348
+		// on CPT pages by setting a 'publishbox' value in the $_labels property array in the child class.
349
+		if (! empty($this->_labels['publishbox'])) {
350
+			$box_label = is_array($this->_labels['publishbox'])
351
+						 && isset($this->_labels['publishbox'][ $this->_req_action ])
352
+				? $this->_labels['publishbox'][ $this->_req_action ]
353
+				: $this->_labels['publishbox'];
354
+			add_meta_box(
355
+				'submitdiv',
356
+				$box_label,
357
+				'post_submit_meta_box',
358
+				$this->_cpt_routes[ $this->_req_action ],
359
+				'side',
360
+				'core'
361
+			);
362
+		}
363
+		// let's add page_templates metabox if this cpt added support for it.
364
+		if ($this->_supports_page_templates($this->_cpt_object->name)) {
365
+			add_meta_box(
366
+				'page_templates',
367
+				__('Page Template', 'event_espresso'),
368
+				array($this, 'page_template_meta_box'),
369
+				$this->_cpt_routes[ $this->_req_action ],
370
+				'side',
371
+				'default'
372
+			);
373
+		}
374
+		// this is a filter that allows the addition of extra html after the permalink field on the wp post edit-form
375
+		if (method_exists($this, 'extra_permalink_field_buttons')) {
376
+			add_filter('get_sample_permalink_html', array($this, 'extra_permalink_field_buttons'), 10, 4);
377
+		}
378
+		// add preview button
379
+		add_filter('get_sample_permalink_html', array($this, 'preview_button_html'), 5, 4);
380
+		// insert our own post_stati dropdown
381
+		add_action('post_submitbox_misc_actions', array($this, 'custom_post_stati_dropdown'), 10);
382
+		// This allows adding additional information to the publish post submitbox on the wp post edit form
383
+		if (method_exists($this, 'extra_misc_actions_publish_box')) {
384
+			add_action('post_submitbox_misc_actions', array($this, 'extra_misc_actions_publish_box'), 10);
385
+		}
386
+		// This allows for adding additional stuff after the title field on the wp post edit form.
387
+		// This is also before the wp_editor for post description field.
388
+		if (method_exists($this, 'edit_form_after_title')) {
389
+			add_action('edit_form_after_title', array($this, 'edit_form_after_title'), 10);
390
+		}
391
+		/**
392
+		 * Filtering WP's esc_url to capture urls pointing to core wp routes so they point to our route.
393
+		 */
394
+		add_filter('clean_url', array($this, 'switch_core_wp_urls_with_ours'), 10, 3);
395
+		parent::_load_page_dependencies();
396
+		// notice we are ALSO going to load the pagenow hook set for this route
397
+		// (see _before_page_setup for the reset of the pagenow global ).
398
+		// This is for any plugins that are doing things properly
399
+		// and hooking into the load page hook for core wp cpt routes.
400
+		global $pagenow;
401
+		do_action('load-' . $pagenow);
402
+		$this->modify_current_screen();
403
+		add_action('admin_enqueue_scripts', array($this, 'setup_autosave_hooks'), 30);
404
+		// we route REALLY early.
405
+		try {
406
+			$this->_route_admin_request();
407
+		} catch (EE_Error $e) {
408
+			$e->get_error();
409
+		}
410
+	}
411
+
412
+
413
+	/**
414
+	 * Since we don't want users going to default core wp routes, this will check any wp urls run through the
415
+	 * esc_url() method and if we see a url matching a pattern for our routes, we'll modify it to point to OUR
416
+	 * route instead.
417
+	 *
418
+	 * @param string $good_protocol_url The escaped url.
419
+	 * @param string $original_url      The original url.
420
+	 * @param string $_context          The context sent to the esc_url method.
421
+	 * @return string possibly a new url for our route.
422
+	 */
423
+	public function switch_core_wp_urls_with_ours($good_protocol_url, $original_url, $_context)
424
+	{
425
+		$routes_to_match = array(
426
+			0 => array(
427
+				'edit.php?post_type=espresso_attendees',
428
+				'admin.php?page=espresso_registrations&action=contact_list',
429
+			),
430
+			1 => array(
431
+				'edit.php?post_type=' . $this->_cpt_object->name,
432
+				'admin.php?page=' . $this->_cpt_object->name,
433
+			),
434
+		);
435
+		foreach ($routes_to_match as $route_matches) {
436
+			if (strpos($good_protocol_url, $route_matches[0]) !== false) {
437
+				return str_replace($route_matches[0], $route_matches[1], $good_protocol_url);
438
+			}
439
+		}
440
+		return $good_protocol_url;
441
+	}
442
+
443
+
444
+	/**
445
+	 * Determine whether the current cpt supports page templates or not.
446
+	 *
447
+	 * @since %VER%
448
+	 * @param string $cpt_name The cpt slug we're checking on.
449
+	 * @return bool True supported, false not.
450
+	 * @throws InvalidArgumentException
451
+	 * @throws InvalidDataTypeException
452
+	 * @throws InvalidInterfaceException
453
+	 */
454
+	private function _supports_page_templates($cpt_name)
455
+	{
456
+		/** @var EventEspresso\core\domain\entities\custom_post_types\CustomPostTypeDefinitions $custom_post_types */
457
+		$custom_post_types = LoaderFactory::getLoader()->getShared(
458
+			'EventEspresso\core\domain\entities\custom_post_types\CustomPostTypeDefinitions'
459
+		);
460
+		$cpt_args = $custom_post_types->getDefinitions();
461
+		$cpt_args = isset($cpt_args[ $cpt_name ]) ? $cpt_args[ $cpt_name ]['args'] : array();
462
+		$cpt_has_support = ! empty($cpt_args['page_templates']);
463
+
464
+		// if the installed version of WP is > 4.7 we do some additional checks.
465
+		if (RecommendedVersions::compareWordPressVersion('4.7', '>=')) {
466
+			$post_templates = wp_get_theme()->get_post_templates();
467
+			// if there are $post_templates for this cpt, then we return false for this method because
468
+			// that means we aren't going to load our page template manager and leave that up to the native
469
+			// cpt template manager.
470
+			$cpt_has_support = ! isset($post_templates[ $cpt_name ]) ? $cpt_has_support : false;
471
+		}
472
+
473
+		return $cpt_has_support;
474
+	}
475
+
476
+
477
+	/**
478
+	 * Callback for the page_templates metabox selector.
479
+	 *
480
+	 * @since %VER%
481
+	 * @return void
482
+	 */
483
+	public function page_template_meta_box()
484
+	{
485
+		global $post;
486
+		$template = '';
487
+
488
+		if (RecommendedVersions::compareWordPressVersion('4.7', '>=')) {
489
+			$page_template_count = count(get_page_templates());
490
+		} else {
491
+			$page_template_count = count(get_page_templates($post));
492
+		};
493
+
494
+		if ($page_template_count) {
495
+			$page_template = get_post_meta($post->ID, '_wp_page_template', true);
496
+			$template = ! empty($page_template) ? $page_template : '';
497
+		}
498
+		?>
499 499
         <p><strong><?php _e('Template', 'event_espresso') ?></strong></p>
500 500
         <label class="screen-reader-text" for="page_template"><?php _e('Page Template', 'event_espresso') ?></label><select
501 501
         name="page_template" id="page_template">
@@ -503,507 +503,507 @@  discard block
 block discarded – undo
503 503
         <?php page_template_dropdown($template); ?>
504 504
     </select>
505 505
         <?php
506
-    }
507
-
508
-
509
-    /**
510
-     * if this post is a draft or scheduled post then we provide a preview button for user to click
511
-     * Method is called from parent and is hooked into the wp 'get_sample_permalink_html' filter.
512
-     *
513
-     * @param  string $return    the current html
514
-     * @param  int    $id        the post id for the page
515
-     * @param  string $new_title What the title is
516
-     * @param  string $new_slug  what the slug is
517
-     * @return string            The new html string for the permalink area
518
-     */
519
-    public function preview_button_html($return, $id, $new_title, $new_slug)
520
-    {
521
-        $post = get_post($id);
522
-        if ('publish' !== get_post_status($post)) {
523
-            $return .= '<span_id="view-post-btn"><a target="_blank" href="'
524
-                       . get_preview_post_link($id)
525
-                       . '" class="button button-small">'
526
-                       . __('Preview', 'event_espresso')
527
-                       . '</a></span>'
528
-                       . "\n";
529
-        }
530
-        return $return;
531
-    }
532
-
533
-
534
-    /**
535
-     * add our custom post stati dropdown on the wp post page for this cpt
536
-     *
537
-     * @return void
538
-     */
539
-    public function custom_post_stati_dropdown()
540
-    {
541
-
542
-        $statuses = $this->_cpt_model_obj->get_custom_post_statuses();
543
-        $cur_status_label = array_key_exists($this->_cpt_model_obj->status(), $statuses)
544
-            ? $statuses[ $this->_cpt_model_obj->status() ]
545
-            : '';
546
-        $template_args = array(
547
-            'cur_status'            => $this->_cpt_model_obj->status(),
548
-            'statuses'              => $statuses,
549
-            'cur_status_label'      => $cur_status_label,
550
-            'localized_status_save' => sprintf(__('Save %s', 'event_espresso'), $cur_status_label),
551
-        );
552
-        // we'll add a trash post status (WP doesn't add one for some reason)
553
-        if ($this->_cpt_model_obj->status() === 'trash') {
554
-            $template_args['cur_status_label'] = __('Trashed', 'event_espresso');
555
-            $statuses['trash'] = __('Trashed', 'event_espresso');
556
-            $template_args['statuses'] = $statuses;
557
-        }
558
-
559
-        $template = EE_ADMIN_TEMPLATE . 'status_dropdown.template.php';
560
-        EEH_Template::display_template($template, $template_args);
561
-    }
562
-
563
-
564
-    public function setup_autosave_hooks()
565
-    {
566
-        $this->_set_autosave_containers();
567
-        $this->_load_autosave_scripts_styles();
568
-    }
569
-
570
-
571
-    /**
572
-     * This is run on all WordPress autosaves AFTER the autosave is complete and sends along a $_POST object (available
573
-     * in $this->_req_data) containing: post_ID of the saved post autosavenonce for the saved post We'll do the check
574
-     * for the nonce in here, but then this method looks for two things:
575
-     * 1. Execute a method (if exists) matching 'ee_autosave_' and appended with the given route. OR
576
-     * 2. do_actions() for global or class specific actions that have been registered (for plugins/addons not in an
577
-     * EE_Admin_Page class. PLEASE NOTE: Data will be returned using the _return_json() object and so the
578
-     * $_template_args property should be used to hold the $data array.  We're expecting the following things set in
579
-     * template args.
580
-     *    1. $template_args['error'] = IF there is an error you can add the message in here.
581
-     *    2. $template_args['data']['items'] = an array of items that are setup in key index pairs of 'where_values_go'
582
-     *    => 'values_to_add'.  In other words, for the datetime metabox we'll have something like
583
-     *    $this->_template_args['data']['items'] = array(
584
-     *        'event-datetime-ids' => '1,2,3';
585
-     *    );
586
-     *    Keep in mind the following things:
587
-     *    - "where" index is for the input with the id as that string.
588
-     *    - "what" index is what will be used for the value of that input.
589
-     *
590
-     * @return void
591
-     */
592
-    public function do_extra_autosave_stuff()
593
-    {
594
-        // next let's check for the autosave nonce (we'll use _verify_nonce )
595
-        $nonce = isset($this->_req_data['autosavenonce'])
596
-            ? $this->_req_data['autosavenonce']
597
-            : null;
598
-        $this->_verify_nonce($nonce, 'autosave');
599
-        // make sure we define doing autosave (cause WP isn't triggering this we want to make sure we define it)
600
-        if (! defined('DOING_AUTOSAVE')) {
601
-            define('DOING_AUTOSAVE', true);
602
-        }
603
-        // if we made it here then the nonce checked out.  Let's run our methods and actions
604
-        $autosave = "_ee_autosave_{$this->_current_view}";
605
-        if (method_exists($this, $autosave)) {
606
-            $this->$autosave();
607
-        } else {
608
-            $this->_template_args['success'] = true;
609
-        }
610
-        do_action('AHEE__EE_Admin_Page_CPT__do_extra_autosave_stuff__global_after', $this);
611
-        do_action('AHEE__EE_Admin_Page_CPT__do_extra_autosave_stuff__after_' . get_class($this), $this);
612
-        // now let's return json
613
-        $this->_return_json();
614
-    }
615
-
616
-
617
-    /**
618
-     * This takes care of setting up default routes and pages that utilize the core WP admin pages.
619
-     * Child classes can override the defaults (in cases for adding metaboxes etc.)
620
-     * but take care that you include the defaults here otherwise your core WP admin pages for the cpt won't work!
621
-     *
622
-     * @access protected
623
-     * @throws EE_Error
624
-     * @return void
625
-     */
626
-    protected function _extend_page_config_for_cpt()
627
-    {
628
-        // before doing anything we need to make sure this runs ONLY when the loaded page matches the set page_slug
629
-        if (isset($this->_req_data['page']) && $this->_req_data['page'] !== $this->page_slug) {
630
-            return;
631
-        }
632
-        // set page routes and page config but ONLY if we're not viewing a custom setup cpt route as defined in _cpt_routes
633
-        if (! empty($this->_cpt_object)) {
634
-            $this->_page_routes = array_merge(
635
-                array(
636
-                    'create_new' => '_create_new_cpt_item',
637
-                    'edit'       => '_edit_cpt_item',
638
-                ),
639
-                $this->_page_routes
640
-            );
641
-            $this->_page_config = array_merge(
642
-                array(
643
-                    'create_new' => array(
644
-                        'nav'           => array(
645
-                            'label' => $this->_cpt_object->labels->add_new_item,
646
-                            'order' => 5,
647
-                        ),
648
-                        'require_nonce' => false,
649
-                    ),
650
-                    'edit'       => array(
651
-                        'nav'           => array(
652
-                            'label'      => $this->_cpt_object->labels->edit_item,
653
-                            'order'      => 5,
654
-                            'persistent' => false,
655
-                            'url'        => '',
656
-                        ),
657
-                        'require_nonce' => false,
658
-                    ),
659
-                ),
660
-                $this->_page_config
661
-            );
662
-        }
663
-        // load the next section only if this is a matching cpt route as set in the cpt routes array.
664
-        if (! isset($this->_cpt_routes[ $this->_req_action ])) {
665
-            return;
666
-        }
667
-        $this->_cpt_route = isset($this->_cpt_routes[ $this->_req_action ]) ? true : false;
668
-        // add_action('FHEE__EE_Admin_Page___load_page_dependencies__after_load', array( $this, 'modify_current_screen') );
669
-        if (empty($this->_cpt_object)) {
670
-            $msg = sprintf(
671
-                __(
672
-                    '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).',
673
-                    'event_espresso'
674
-                ),
675
-                $this->page_slug,
676
-                $this->_req_action,
677
-                get_class($this)
678
-            );
679
-            throw new EE_Error($msg);
680
-        }
681
-        if ($this->_cpt_route) {
682
-            $id = isset($this->_req_data['post']) ? $this->_req_data['post'] : null;
683
-            $this->_set_model_object($id);
684
-        }
685
-    }
686
-
687
-
688
-    /**
689
-     * Sets the _cpt_model_object property using what has been set for the _cpt_model_name and a given id.
690
-     *
691
-     * @access protected
692
-     * @param int    $id       The id to retrieve the model object for. If empty we set a default object.
693
-     * @param bool   $ignore_route_check
694
-     * @param string $req_type whether the current route is for inserting, updating, or deleting the CPT
695
-     * @throws EE_Error
696
-     * @throws InvalidArgumentException
697
-     * @throws InvalidDataTypeException
698
-     * @throws InvalidInterfaceException
699
-     * @throws ReflectionException
700
-     */
701
-    protected function _set_model_object($id = null, $ignore_route_check = false, $req_type = '')
702
-    {
703
-        $model = null;
704
-        if (empty($this->_cpt_model_names)
705
-            || (
706
-                ! $ignore_route_check
707
-                && ! isset($this->_cpt_routes[ $this->_req_action ])
708
-            ) || (
709
-                $this->_cpt_model_obj instanceof EE_CPT_Base
710
-                && $this->_cpt_model_obj->ID() === $id
711
-            )
712
-        ) {
713
-            // 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.
714
-            return;
715
-        }
716
-        // if ignore_route_check is true, then get the model name via CustomPostTypeDefinitions
717
-        if ($ignore_route_check) {
718
-            $post_type = get_post_type($id);
719
-            /** @var EventEspresso\core\domain\entities\custom_post_types\CustomPostTypeDefinitions $custom_post_types */
720
-            $custom_post_types = LoaderFactory::getLoader()->getShared(
721
-                'EventEspresso\core\domain\entities\custom_post_types\CustomPostTypeDefinitions'
722
-            );
723
-            $model_names = $custom_post_types->getCustomPostTypeModelNames($post_type);
724
-            if (isset($model_names[ $post_type ])) {
725
-                $model = EE_Registry::instance()->load_model($model_names[ $post_type ]);
726
-            }
727
-        } else {
728
-            $model = EE_Registry::instance()->load_model($this->_cpt_model_names[ $this->_req_action ]);
729
-        }
730
-        if ($model instanceof EEM_Base) {
731
-            $this->_cpt_model_obj = ! empty($id) ? $model->get_one_by_ID($id) : $model->create_default_object();
732
-        }
733
-        do_action(
734
-            'AHEE__EE_Admin_Page_CPT__set_model_object__after_set_object',
735
-            $this->_cpt_model_obj,
736
-            $req_type
737
-        );
738
-    }
739
-
740
-
741
-    /**
742
-     * admin_init_global
743
-     * This runs all the code that we want executed within the WP admin_init hook.
744
-     * This method executes for ALL EE Admin pages.
745
-     *
746
-     * @access public
747
-     * @return void
748
-     */
749
-    public function admin_init_global()
750
-    {
751
-        $post = isset($this->_req_data['post']) ? get_post($this->_req_data['post']) : null;
752
-        // its possible this is a new save so let's catch that instead
753
-        $post = isset($this->_req_data['post_ID']) ? get_post($this->_req_data['post_ID']) : $post;
754
-        $post_type = $post ? $post->post_type : false;
755
-        $current_route = isset($this->_req_data['current_route'])
756
-            ? $this->_req_data['current_route']
757
-            : 'shouldneverwork';
758
-        $route_to_check = $post_type && isset($this->_cpt_routes[ $current_route ])
759
-            ? $this->_cpt_routes[ $current_route ]
760
-            : '';
761
-        add_filter('get_delete_post_link', array($this, 'modify_delete_post_link'), 10, 3);
762
-        add_filter('get_edit_post_link', array($this, 'modify_edit_post_link'), 10, 3);
763
-        if ($post_type === $route_to_check) {
764
-            add_filter('redirect_post_location', array($this, 'cpt_post_location_redirect'), 10, 2);
765
-        }
766
-        // now let's filter redirect if we're on a revision page and the revision is for an event CPT.
767
-        $revision = isset($this->_req_data['revision']) ? $this->_req_data['revision'] : null;
768
-        if (! empty($revision)) {
769
-            $action = isset($this->_req_data['action']) ? $this->_req_data['action'] : null;
770
-            // doing a restore?
771
-            if (! empty($action) && $action === 'restore') {
772
-                // get post for revision
773
-                $rev_post = get_post($revision);
774
-                $rev_parent = get_post($rev_post->post_parent);
775
-                // only do our redirect filter AND our restore revision action if the post_type for the parent is one of our cpts.
776
-                if ($rev_parent && $rev_parent->post_type === $this->page_slug) {
777
-                    add_filter('wp_redirect', array($this, 'revision_redirect'), 10, 2);
778
-                    // restores of revisions
779
-                    add_action('wp_restore_post_revision', array($this, 'restore_revision'), 10, 2);
780
-                }
781
-            }
782
-        }
783
-        // 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!
784
-        if ($post_type && $post_type === $route_to_check) {
785
-            // $post_id, $post
786
-            add_action('save_post', array($this, 'insert_update'), 10, 3);
787
-            // $post_id
788
-            add_action('trashed_post', array($this, 'before_trash_cpt_item'), 10);
789
-            add_action('trashed_post', array($this, 'dont_permanently_delete_ee_cpts'), 10);
790
-            add_action('untrashed_post', array($this, 'before_restore_cpt_item'), 10);
791
-            add_action('after_delete_post', array($this, 'before_delete_cpt_item'), 10);
792
-        }
793
-    }
794
-
795
-
796
-    /**
797
-     * Callback for the WordPress trashed_post hook.
798
-     * Execute some basic checks before calling the trash_cpt_item declared in the child class.
799
-     *
800
-     * @param int $post_id
801
-     * @throws \EE_Error
802
-     */
803
-    public function before_trash_cpt_item($post_id)
804
-    {
805
-        $this->_set_model_object($post_id, true, 'trash');
806
-        // if our cpt object isn't existent then get out immediately.
807
-        if (! $this->_cpt_model_obj instanceof EE_CPT_Base || $this->_cpt_model_obj->ID() !== $post_id) {
808
-            return;
809
-        }
810
-        $this->trash_cpt_item($post_id);
811
-    }
812
-
813
-
814
-    /**
815
-     * Callback for the WordPress untrashed_post hook.
816
-     * Execute some basic checks before calling the restore_cpt_method in the child class.
817
-     *
818
-     * @param $post_id
819
-     * @throws \EE_Error
820
-     */
821
-    public function before_restore_cpt_item($post_id)
822
-    {
823
-        $this->_set_model_object($post_id, true, 'restore');
824
-        // if our cpt object isn't existent then get out immediately.
825
-        if (! $this->_cpt_model_obj instanceof EE_CPT_Base || $this->_cpt_model_obj->ID() !== $post_id) {
826
-            return;
827
-        }
828
-        $this->restore_cpt_item($post_id);
829
-    }
830
-
831
-
832
-    /**
833
-     * Callback for the WordPress after_delete_post hook.
834
-     * Execute some basic checks before calling the delete_cpt_item method in the child class.
835
-     *
836
-     * @param $post_id
837
-     * @throws \EE_Error
838
-     */
839
-    public function before_delete_cpt_item($post_id)
840
-    {
841
-        $this->_set_model_object($post_id, true, 'delete');
842
-        // if our cpt object isn't existent then get out immediately.
843
-        if (! $this->_cpt_model_obj instanceof EE_CPT_Base || $this->_cpt_model_obj->ID() !== $post_id) {
844
-            return;
845
-        }
846
-        $this->delete_cpt_item($post_id);
847
-    }
848
-
849
-
850
-    /**
851
-     * This simply verifies if the cpt_model_object is instantiated for the given page and throws an error message
852
-     * accordingly.
853
-     *
854
-     * @return void
855
-     * @throws EE_Error
856
-     * @throws InvalidArgumentException
857
-     * @throws InvalidDataTypeException
858
-     * @throws InvalidInterfaceException
859
-     * @throws ReflectionException
860
-     */
861
-    public function verify_cpt_object()
862
-    {
863
-        $label = ! empty($this->_cpt_object) ? $this->_cpt_object->labels->singular_name : $this->page_label;
864
-        // verify event object
865
-        if (! $this->_cpt_model_obj instanceof EE_CPT_Base) {
866
-            throw new EE_Error(
867
-                sprintf(
868
-                    __(
869
-                        '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',
870
-                        'event_espresso'
871
-                    ),
872
-                    $label
873
-                )
874
-            );
875
-        }
876
-        // if auto-draft then throw an error
877
-        if ($this->_cpt_model_obj->get('status') === 'auto-draft') {
878
-            EE_Error::overwrite_errors();
879
-            EE_Error::add_error(
880
-                sprintf(
881
-                    __(
882
-                        '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.',
883
-                        'event_espresso'
884
-                    ),
885
-                    $label
886
-                ),
887
-                __FILE__,
888
-                __FUNCTION__,
889
-                __LINE__
890
-            );
891
-        }
892
-        $this->loadEspressoEditorAssetManager();
893
-    }
894
-
895
-
896
-    /**
897
-     * admin_footer_scripts_global
898
-     * Anything triggered by the 'admin_print_footer_scripts' WP hook should be put in here. This particular method
899
-     * will apply on ALL EE_Admin pages.
900
-     *
901
-     * @access public
902
-     * @return void
903
-     */
904
-    public function admin_footer_scripts_global()
905
-    {
906
-        $this->_add_admin_page_ajax_loading_img();
907
-        $this->_add_admin_page_overlay();
908
-    }
909
-
910
-
911
-    /**
912
-     * add in any global scripts for cpt routes
913
-     *
914
-     * @return void
915
-     */
916
-    public function load_global_scripts_styles()
917
-    {
918
-        parent::load_global_scripts_styles();
919
-        if ($this->_cpt_model_obj instanceof EE_CPT_Base) {
920
-            // setup custom post status object for localize script but only if we've got a cpt object
921
-            $statuses = $this->_cpt_model_obj->get_custom_post_statuses();
922
-            if (! empty($statuses)) {
923
-                // get ALL statuses!
924
-                $statuses = $this->_cpt_model_obj->get_all_post_statuses();
925
-                // setup object
926
-                $ee_cpt_statuses = array();
927
-                foreach ($statuses as $status => $label) {
928
-                    $ee_cpt_statuses[ $status ] = array(
929
-                        'label'      => $label,
930
-                        'save_label' => sprintf(__('Save as %s', 'event_espresso'), $label),
931
-                    );
932
-                }
933
-                wp_localize_script('ee_admin_js', 'eeCPTstatuses', $ee_cpt_statuses);
934
-            }
935
-        }
936
-    }
937
-
938
-
939
-    /**
940
-     * @throws InvalidArgumentException
941
-     * @throws InvalidDataTypeException
942
-     * @throws InvalidInterfaceException
943
-     */
944
-    private function loadEspressoEditorAssetManager()
945
-    {
946
-        EE_Dependency_Map::register_dependencies(
947
-            'EventEspresso\core\domain\services\assets\EspressoEditorAssetManager',
948
-            array(
949
-                'EventEspresso\core\domain\Domain'                   => EE_Dependency_Map::load_from_cache,
950
-                'EventEspresso\core\services\assets\AssetCollection' => EE_Dependency_Map::load_from_cache,
951
-                'EventEspresso\core\services\assets\Registry'        => EE_Dependency_Map::load_from_cache,
952
-            )
953
-        );
954
-        LoaderFactory::getLoader()->getShared(
955
-            'EventEspresso\core\domain\services\assets\EspressoEditorAssetManager'
956
-        );
957
-        add_action('admin_enqueue_scripts', array($this, 'enqueueEspressoEditorAssets'), 100);
958
-    }
959
-
960
-
961
-    /**
962
-     * enqueue_scripts - Load the scripts and css
963
-     *
964
-     * @return void
965
-     * @throws DomainException
966
-     */
967
-    public function enqueueEspressoEditorAssets()
968
-    {
969
-        wp_enqueue_style(EspressoEditorAssetManager::CSS_HANDLE_EDITOR);
970
-        wp_enqueue_script(EspressoEditorAssetManager::JS_HANDLE_EDITOR);
971
-    }
972
-
973
-
974
-    /**
975
-     * This is a wrapper for the insert/update routes for cpt items so we can add things that are common to ALL
976
-     * insert/updates
977
-     *
978
-     * @param  int     $post_id ID of post being updated
979
-     * @param  WP_Post $post    Post object from WP
980
-     * @param  bool    $update  Whether this is an update or a new save.
981
-     * @return void
982
-     * @throws \EE_Error
983
-     */
984
-    public function insert_update($post_id, $post, $update)
985
-    {
986
-        // make sure that if this is a revision OR trash action that we don't do any updates!
987
-        if (isset($this->_req_data['action'])
988
-            && (
989
-                $this->_req_data['action'] === 'restore'
990
-                || $this->_req_data['action'] === 'trash'
991
-            )
992
-        ) {
993
-            return;
994
-        }
995
-        $this->_set_model_object($post_id, true, 'insert_update');
996
-        // if our cpt object is not instantiated and its NOT the same post_id as what is triggering this callback, then exit.
997
-        if ($update
998
-            && (
999
-                ! $this->_cpt_model_obj instanceof EE_CPT_Base
1000
-                || $this->_cpt_model_obj->ID() !== $post_id
1001
-            )
1002
-        ) {
1003
-            return;
1004
-        }
1005
-        // check for autosave and update our req_data property accordingly.
1006
-        /*if ( defined('DOING_AUTOSAVE') && DOING_AUTOSAVE && isset( $this->_req_data['ee_autosave_data'] ) ) {
506
+	}
507
+
508
+
509
+	/**
510
+	 * if this post is a draft or scheduled post then we provide a preview button for user to click
511
+	 * Method is called from parent and is hooked into the wp 'get_sample_permalink_html' filter.
512
+	 *
513
+	 * @param  string $return    the current html
514
+	 * @param  int    $id        the post id for the page
515
+	 * @param  string $new_title What the title is
516
+	 * @param  string $new_slug  what the slug is
517
+	 * @return string            The new html string for the permalink area
518
+	 */
519
+	public function preview_button_html($return, $id, $new_title, $new_slug)
520
+	{
521
+		$post = get_post($id);
522
+		if ('publish' !== get_post_status($post)) {
523
+			$return .= '<span_id="view-post-btn"><a target="_blank" href="'
524
+					   . get_preview_post_link($id)
525
+					   . '" class="button button-small">'
526
+					   . __('Preview', 'event_espresso')
527
+					   . '</a></span>'
528
+					   . "\n";
529
+		}
530
+		return $return;
531
+	}
532
+
533
+
534
+	/**
535
+	 * add our custom post stati dropdown on the wp post page for this cpt
536
+	 *
537
+	 * @return void
538
+	 */
539
+	public function custom_post_stati_dropdown()
540
+	{
541
+
542
+		$statuses = $this->_cpt_model_obj->get_custom_post_statuses();
543
+		$cur_status_label = array_key_exists($this->_cpt_model_obj->status(), $statuses)
544
+			? $statuses[ $this->_cpt_model_obj->status() ]
545
+			: '';
546
+		$template_args = array(
547
+			'cur_status'            => $this->_cpt_model_obj->status(),
548
+			'statuses'              => $statuses,
549
+			'cur_status_label'      => $cur_status_label,
550
+			'localized_status_save' => sprintf(__('Save %s', 'event_espresso'), $cur_status_label),
551
+		);
552
+		// we'll add a trash post status (WP doesn't add one for some reason)
553
+		if ($this->_cpt_model_obj->status() === 'trash') {
554
+			$template_args['cur_status_label'] = __('Trashed', 'event_espresso');
555
+			$statuses['trash'] = __('Trashed', 'event_espresso');
556
+			$template_args['statuses'] = $statuses;
557
+		}
558
+
559
+		$template = EE_ADMIN_TEMPLATE . 'status_dropdown.template.php';
560
+		EEH_Template::display_template($template, $template_args);
561
+	}
562
+
563
+
564
+	public function setup_autosave_hooks()
565
+	{
566
+		$this->_set_autosave_containers();
567
+		$this->_load_autosave_scripts_styles();
568
+	}
569
+
570
+
571
+	/**
572
+	 * This is run on all WordPress autosaves AFTER the autosave is complete and sends along a $_POST object (available
573
+	 * in $this->_req_data) containing: post_ID of the saved post autosavenonce for the saved post We'll do the check
574
+	 * for the nonce in here, but then this method looks for two things:
575
+	 * 1. Execute a method (if exists) matching 'ee_autosave_' and appended with the given route. OR
576
+	 * 2. do_actions() for global or class specific actions that have been registered (for plugins/addons not in an
577
+	 * EE_Admin_Page class. PLEASE NOTE: Data will be returned using the _return_json() object and so the
578
+	 * $_template_args property should be used to hold the $data array.  We're expecting the following things set in
579
+	 * template args.
580
+	 *    1. $template_args['error'] = IF there is an error you can add the message in here.
581
+	 *    2. $template_args['data']['items'] = an array of items that are setup in key index pairs of 'where_values_go'
582
+	 *    => 'values_to_add'.  In other words, for the datetime metabox we'll have something like
583
+	 *    $this->_template_args['data']['items'] = array(
584
+	 *        'event-datetime-ids' => '1,2,3';
585
+	 *    );
586
+	 *    Keep in mind the following things:
587
+	 *    - "where" index is for the input with the id as that string.
588
+	 *    - "what" index is what will be used for the value of that input.
589
+	 *
590
+	 * @return void
591
+	 */
592
+	public function do_extra_autosave_stuff()
593
+	{
594
+		// next let's check for the autosave nonce (we'll use _verify_nonce )
595
+		$nonce = isset($this->_req_data['autosavenonce'])
596
+			? $this->_req_data['autosavenonce']
597
+			: null;
598
+		$this->_verify_nonce($nonce, 'autosave');
599
+		// make sure we define doing autosave (cause WP isn't triggering this we want to make sure we define it)
600
+		if (! defined('DOING_AUTOSAVE')) {
601
+			define('DOING_AUTOSAVE', true);
602
+		}
603
+		// if we made it here then the nonce checked out.  Let's run our methods and actions
604
+		$autosave = "_ee_autosave_{$this->_current_view}";
605
+		if (method_exists($this, $autosave)) {
606
+			$this->$autosave();
607
+		} else {
608
+			$this->_template_args['success'] = true;
609
+		}
610
+		do_action('AHEE__EE_Admin_Page_CPT__do_extra_autosave_stuff__global_after', $this);
611
+		do_action('AHEE__EE_Admin_Page_CPT__do_extra_autosave_stuff__after_' . get_class($this), $this);
612
+		// now let's return json
613
+		$this->_return_json();
614
+	}
615
+
616
+
617
+	/**
618
+	 * This takes care of setting up default routes and pages that utilize the core WP admin pages.
619
+	 * Child classes can override the defaults (in cases for adding metaboxes etc.)
620
+	 * but take care that you include the defaults here otherwise your core WP admin pages for the cpt won't work!
621
+	 *
622
+	 * @access protected
623
+	 * @throws EE_Error
624
+	 * @return void
625
+	 */
626
+	protected function _extend_page_config_for_cpt()
627
+	{
628
+		// before doing anything we need to make sure this runs ONLY when the loaded page matches the set page_slug
629
+		if (isset($this->_req_data['page']) && $this->_req_data['page'] !== $this->page_slug) {
630
+			return;
631
+		}
632
+		// set page routes and page config but ONLY if we're not viewing a custom setup cpt route as defined in _cpt_routes
633
+		if (! empty($this->_cpt_object)) {
634
+			$this->_page_routes = array_merge(
635
+				array(
636
+					'create_new' => '_create_new_cpt_item',
637
+					'edit'       => '_edit_cpt_item',
638
+				),
639
+				$this->_page_routes
640
+			);
641
+			$this->_page_config = array_merge(
642
+				array(
643
+					'create_new' => array(
644
+						'nav'           => array(
645
+							'label' => $this->_cpt_object->labels->add_new_item,
646
+							'order' => 5,
647
+						),
648
+						'require_nonce' => false,
649
+					),
650
+					'edit'       => array(
651
+						'nav'           => array(
652
+							'label'      => $this->_cpt_object->labels->edit_item,
653
+							'order'      => 5,
654
+							'persistent' => false,
655
+							'url'        => '',
656
+						),
657
+						'require_nonce' => false,
658
+					),
659
+				),
660
+				$this->_page_config
661
+			);
662
+		}
663
+		// load the next section only if this is a matching cpt route as set in the cpt routes array.
664
+		if (! isset($this->_cpt_routes[ $this->_req_action ])) {
665
+			return;
666
+		}
667
+		$this->_cpt_route = isset($this->_cpt_routes[ $this->_req_action ]) ? true : false;
668
+		// add_action('FHEE__EE_Admin_Page___load_page_dependencies__after_load', array( $this, 'modify_current_screen') );
669
+		if (empty($this->_cpt_object)) {
670
+			$msg = sprintf(
671
+				__(
672
+					'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).',
673
+					'event_espresso'
674
+				),
675
+				$this->page_slug,
676
+				$this->_req_action,
677
+				get_class($this)
678
+			);
679
+			throw new EE_Error($msg);
680
+		}
681
+		if ($this->_cpt_route) {
682
+			$id = isset($this->_req_data['post']) ? $this->_req_data['post'] : null;
683
+			$this->_set_model_object($id);
684
+		}
685
+	}
686
+
687
+
688
+	/**
689
+	 * Sets the _cpt_model_object property using what has been set for the _cpt_model_name and a given id.
690
+	 *
691
+	 * @access protected
692
+	 * @param int    $id       The id to retrieve the model object for. If empty we set a default object.
693
+	 * @param bool   $ignore_route_check
694
+	 * @param string $req_type whether the current route is for inserting, updating, or deleting the CPT
695
+	 * @throws EE_Error
696
+	 * @throws InvalidArgumentException
697
+	 * @throws InvalidDataTypeException
698
+	 * @throws InvalidInterfaceException
699
+	 * @throws ReflectionException
700
+	 */
701
+	protected function _set_model_object($id = null, $ignore_route_check = false, $req_type = '')
702
+	{
703
+		$model = null;
704
+		if (empty($this->_cpt_model_names)
705
+			|| (
706
+				! $ignore_route_check
707
+				&& ! isset($this->_cpt_routes[ $this->_req_action ])
708
+			) || (
709
+				$this->_cpt_model_obj instanceof EE_CPT_Base
710
+				&& $this->_cpt_model_obj->ID() === $id
711
+			)
712
+		) {
713
+			// 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.
714
+			return;
715
+		}
716
+		// if ignore_route_check is true, then get the model name via CustomPostTypeDefinitions
717
+		if ($ignore_route_check) {
718
+			$post_type = get_post_type($id);
719
+			/** @var EventEspresso\core\domain\entities\custom_post_types\CustomPostTypeDefinitions $custom_post_types */
720
+			$custom_post_types = LoaderFactory::getLoader()->getShared(
721
+				'EventEspresso\core\domain\entities\custom_post_types\CustomPostTypeDefinitions'
722
+			);
723
+			$model_names = $custom_post_types->getCustomPostTypeModelNames($post_type);
724
+			if (isset($model_names[ $post_type ])) {
725
+				$model = EE_Registry::instance()->load_model($model_names[ $post_type ]);
726
+			}
727
+		} else {
728
+			$model = EE_Registry::instance()->load_model($this->_cpt_model_names[ $this->_req_action ]);
729
+		}
730
+		if ($model instanceof EEM_Base) {
731
+			$this->_cpt_model_obj = ! empty($id) ? $model->get_one_by_ID($id) : $model->create_default_object();
732
+		}
733
+		do_action(
734
+			'AHEE__EE_Admin_Page_CPT__set_model_object__after_set_object',
735
+			$this->_cpt_model_obj,
736
+			$req_type
737
+		);
738
+	}
739
+
740
+
741
+	/**
742
+	 * admin_init_global
743
+	 * This runs all the code that we want executed within the WP admin_init hook.
744
+	 * This method executes for ALL EE Admin pages.
745
+	 *
746
+	 * @access public
747
+	 * @return void
748
+	 */
749
+	public function admin_init_global()
750
+	{
751
+		$post = isset($this->_req_data['post']) ? get_post($this->_req_data['post']) : null;
752
+		// its possible this is a new save so let's catch that instead
753
+		$post = isset($this->_req_data['post_ID']) ? get_post($this->_req_data['post_ID']) : $post;
754
+		$post_type = $post ? $post->post_type : false;
755
+		$current_route = isset($this->_req_data['current_route'])
756
+			? $this->_req_data['current_route']
757
+			: 'shouldneverwork';
758
+		$route_to_check = $post_type && isset($this->_cpt_routes[ $current_route ])
759
+			? $this->_cpt_routes[ $current_route ]
760
+			: '';
761
+		add_filter('get_delete_post_link', array($this, 'modify_delete_post_link'), 10, 3);
762
+		add_filter('get_edit_post_link', array($this, 'modify_edit_post_link'), 10, 3);
763
+		if ($post_type === $route_to_check) {
764
+			add_filter('redirect_post_location', array($this, 'cpt_post_location_redirect'), 10, 2);
765
+		}
766
+		// now let's filter redirect if we're on a revision page and the revision is for an event CPT.
767
+		$revision = isset($this->_req_data['revision']) ? $this->_req_data['revision'] : null;
768
+		if (! empty($revision)) {
769
+			$action = isset($this->_req_data['action']) ? $this->_req_data['action'] : null;
770
+			// doing a restore?
771
+			if (! empty($action) && $action === 'restore') {
772
+				// get post for revision
773
+				$rev_post = get_post($revision);
774
+				$rev_parent = get_post($rev_post->post_parent);
775
+				// only do our redirect filter AND our restore revision action if the post_type for the parent is one of our cpts.
776
+				if ($rev_parent && $rev_parent->post_type === $this->page_slug) {
777
+					add_filter('wp_redirect', array($this, 'revision_redirect'), 10, 2);
778
+					// restores of revisions
779
+					add_action('wp_restore_post_revision', array($this, 'restore_revision'), 10, 2);
780
+				}
781
+			}
782
+		}
783
+		// 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!
784
+		if ($post_type && $post_type === $route_to_check) {
785
+			// $post_id, $post
786
+			add_action('save_post', array($this, 'insert_update'), 10, 3);
787
+			// $post_id
788
+			add_action('trashed_post', array($this, 'before_trash_cpt_item'), 10);
789
+			add_action('trashed_post', array($this, 'dont_permanently_delete_ee_cpts'), 10);
790
+			add_action('untrashed_post', array($this, 'before_restore_cpt_item'), 10);
791
+			add_action('after_delete_post', array($this, 'before_delete_cpt_item'), 10);
792
+		}
793
+	}
794
+
795
+
796
+	/**
797
+	 * Callback for the WordPress trashed_post hook.
798
+	 * Execute some basic checks before calling the trash_cpt_item declared in the child class.
799
+	 *
800
+	 * @param int $post_id
801
+	 * @throws \EE_Error
802
+	 */
803
+	public function before_trash_cpt_item($post_id)
804
+	{
805
+		$this->_set_model_object($post_id, true, 'trash');
806
+		// if our cpt object isn't existent then get out immediately.
807
+		if (! $this->_cpt_model_obj instanceof EE_CPT_Base || $this->_cpt_model_obj->ID() !== $post_id) {
808
+			return;
809
+		}
810
+		$this->trash_cpt_item($post_id);
811
+	}
812
+
813
+
814
+	/**
815
+	 * Callback for the WordPress untrashed_post hook.
816
+	 * Execute some basic checks before calling the restore_cpt_method in the child class.
817
+	 *
818
+	 * @param $post_id
819
+	 * @throws \EE_Error
820
+	 */
821
+	public function before_restore_cpt_item($post_id)
822
+	{
823
+		$this->_set_model_object($post_id, true, 'restore');
824
+		// if our cpt object isn't existent then get out immediately.
825
+		if (! $this->_cpt_model_obj instanceof EE_CPT_Base || $this->_cpt_model_obj->ID() !== $post_id) {
826
+			return;
827
+		}
828
+		$this->restore_cpt_item($post_id);
829
+	}
830
+
831
+
832
+	/**
833
+	 * Callback for the WordPress after_delete_post hook.
834
+	 * Execute some basic checks before calling the delete_cpt_item method in the child class.
835
+	 *
836
+	 * @param $post_id
837
+	 * @throws \EE_Error
838
+	 */
839
+	public function before_delete_cpt_item($post_id)
840
+	{
841
+		$this->_set_model_object($post_id, true, 'delete');
842
+		// if our cpt object isn't existent then get out immediately.
843
+		if (! $this->_cpt_model_obj instanceof EE_CPT_Base || $this->_cpt_model_obj->ID() !== $post_id) {
844
+			return;
845
+		}
846
+		$this->delete_cpt_item($post_id);
847
+	}
848
+
849
+
850
+	/**
851
+	 * This simply verifies if the cpt_model_object is instantiated for the given page and throws an error message
852
+	 * accordingly.
853
+	 *
854
+	 * @return void
855
+	 * @throws EE_Error
856
+	 * @throws InvalidArgumentException
857
+	 * @throws InvalidDataTypeException
858
+	 * @throws InvalidInterfaceException
859
+	 * @throws ReflectionException
860
+	 */
861
+	public function verify_cpt_object()
862
+	{
863
+		$label = ! empty($this->_cpt_object) ? $this->_cpt_object->labels->singular_name : $this->page_label;
864
+		// verify event object
865
+		if (! $this->_cpt_model_obj instanceof EE_CPT_Base) {
866
+			throw new EE_Error(
867
+				sprintf(
868
+					__(
869
+						'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',
870
+						'event_espresso'
871
+					),
872
+					$label
873
+				)
874
+			);
875
+		}
876
+		// if auto-draft then throw an error
877
+		if ($this->_cpt_model_obj->get('status') === 'auto-draft') {
878
+			EE_Error::overwrite_errors();
879
+			EE_Error::add_error(
880
+				sprintf(
881
+					__(
882
+						'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.',
883
+						'event_espresso'
884
+					),
885
+					$label
886
+				),
887
+				__FILE__,
888
+				__FUNCTION__,
889
+				__LINE__
890
+			);
891
+		}
892
+		$this->loadEspressoEditorAssetManager();
893
+	}
894
+
895
+
896
+	/**
897
+	 * admin_footer_scripts_global
898
+	 * Anything triggered by the 'admin_print_footer_scripts' WP hook should be put in here. This particular method
899
+	 * will apply on ALL EE_Admin pages.
900
+	 *
901
+	 * @access public
902
+	 * @return void
903
+	 */
904
+	public function admin_footer_scripts_global()
905
+	{
906
+		$this->_add_admin_page_ajax_loading_img();
907
+		$this->_add_admin_page_overlay();
908
+	}
909
+
910
+
911
+	/**
912
+	 * add in any global scripts for cpt routes
913
+	 *
914
+	 * @return void
915
+	 */
916
+	public function load_global_scripts_styles()
917
+	{
918
+		parent::load_global_scripts_styles();
919
+		if ($this->_cpt_model_obj instanceof EE_CPT_Base) {
920
+			// setup custom post status object for localize script but only if we've got a cpt object
921
+			$statuses = $this->_cpt_model_obj->get_custom_post_statuses();
922
+			if (! empty($statuses)) {
923
+				// get ALL statuses!
924
+				$statuses = $this->_cpt_model_obj->get_all_post_statuses();
925
+				// setup object
926
+				$ee_cpt_statuses = array();
927
+				foreach ($statuses as $status => $label) {
928
+					$ee_cpt_statuses[ $status ] = array(
929
+						'label'      => $label,
930
+						'save_label' => sprintf(__('Save as %s', 'event_espresso'), $label),
931
+					);
932
+				}
933
+				wp_localize_script('ee_admin_js', 'eeCPTstatuses', $ee_cpt_statuses);
934
+			}
935
+		}
936
+	}
937
+
938
+
939
+	/**
940
+	 * @throws InvalidArgumentException
941
+	 * @throws InvalidDataTypeException
942
+	 * @throws InvalidInterfaceException
943
+	 */
944
+	private function loadEspressoEditorAssetManager()
945
+	{
946
+		EE_Dependency_Map::register_dependencies(
947
+			'EventEspresso\core\domain\services\assets\EspressoEditorAssetManager',
948
+			array(
949
+				'EventEspresso\core\domain\Domain'                   => EE_Dependency_Map::load_from_cache,
950
+				'EventEspresso\core\services\assets\AssetCollection' => EE_Dependency_Map::load_from_cache,
951
+				'EventEspresso\core\services\assets\Registry'        => EE_Dependency_Map::load_from_cache,
952
+			)
953
+		);
954
+		LoaderFactory::getLoader()->getShared(
955
+			'EventEspresso\core\domain\services\assets\EspressoEditorAssetManager'
956
+		);
957
+		add_action('admin_enqueue_scripts', array($this, 'enqueueEspressoEditorAssets'), 100);
958
+	}
959
+
960
+
961
+	/**
962
+	 * enqueue_scripts - Load the scripts and css
963
+	 *
964
+	 * @return void
965
+	 * @throws DomainException
966
+	 */
967
+	public function enqueueEspressoEditorAssets()
968
+	{
969
+		wp_enqueue_style(EspressoEditorAssetManager::CSS_HANDLE_EDITOR);
970
+		wp_enqueue_script(EspressoEditorAssetManager::JS_HANDLE_EDITOR);
971
+	}
972
+
973
+
974
+	/**
975
+	 * This is a wrapper for the insert/update routes for cpt items so we can add things that are common to ALL
976
+	 * insert/updates
977
+	 *
978
+	 * @param  int     $post_id ID of post being updated
979
+	 * @param  WP_Post $post    Post object from WP
980
+	 * @param  bool    $update  Whether this is an update or a new save.
981
+	 * @return void
982
+	 * @throws \EE_Error
983
+	 */
984
+	public function insert_update($post_id, $post, $update)
985
+	{
986
+		// make sure that if this is a revision OR trash action that we don't do any updates!
987
+		if (isset($this->_req_data['action'])
988
+			&& (
989
+				$this->_req_data['action'] === 'restore'
990
+				|| $this->_req_data['action'] === 'trash'
991
+			)
992
+		) {
993
+			return;
994
+		}
995
+		$this->_set_model_object($post_id, true, 'insert_update');
996
+		// if our cpt object is not instantiated and its NOT the same post_id as what is triggering this callback, then exit.
997
+		if ($update
998
+			&& (
999
+				! $this->_cpt_model_obj instanceof EE_CPT_Base
1000
+				|| $this->_cpt_model_obj->ID() !== $post_id
1001
+			)
1002
+		) {
1003
+			return;
1004
+		}
1005
+		// check for autosave and update our req_data property accordingly.
1006
+		/*if ( defined('DOING_AUTOSAVE') && DOING_AUTOSAVE && isset( $this->_req_data['ee_autosave_data'] ) ) {
1007 1007
             foreach( (array) $this->_req_data['ee_autosave_data'] as $id => $values ) {
1008 1008
 
1009 1009
                 foreach ( (array) $values as $key => $value ) {
@@ -1013,532 +1013,532 @@  discard block
 block discarded – undo
1013 1013
 
1014 1014
         }/**/ // TODO reactivate after autosave is implemented in 4.2
1015 1015
 
1016
-        // take care of updating any selected page_template IF this cpt supports it.
1017
-        if ($this->_supports_page_templates($post->post_type) && ! empty($this->_req_data['page_template'])) {
1018
-            // wp version aware.
1019
-            if (RecommendedVersions::compareWordPressVersion('4.7', '>=')) {
1020
-                $page_templates = wp_get_theme()->get_page_templates();
1021
-            } else {
1022
-                $post->page_template = $this->_req_data['page_template'];
1023
-                $page_templates = wp_get_theme()->get_page_templates($post);
1024
-            }
1025
-            if ('default' != $this->_req_data['page_template'] && ! isset($page_templates[ $this->_req_data['page_template'] ])) {
1026
-                EE_Error::add_error(__('Invalid Page Template.', 'event_espresso'), __FILE__, __FUNCTION__, __LINE__);
1027
-            } else {
1028
-                update_post_meta($post_id, '_wp_page_template', $this->_req_data['page_template']);
1029
-            }
1030
-        }
1031
-        if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
1032
-            return;
1033
-        } //TODO we'll remove this after reimplementing autosave in 4.2
1034
-        $this->_insert_update_cpt_item($post_id, $post);
1035
-    }
1036
-
1037
-
1038
-    /**
1039
-     * This hooks into the wp_trash_post() function and removes the `_wp_trash_meta_status` and `_wp_trash_meta_time`
1040
-     * post meta IF the trashed post is one of our CPT's - note this method should only be called with our cpt routes
1041
-     * so we don't have to check for our CPT.
1042
-     *
1043
-     * @param  int $post_id ID of the post
1044
-     * @return void
1045
-     */
1046
-    public function dont_permanently_delete_ee_cpts($post_id)
1047
-    {
1048
-        // only do this if we're actually processing one of our CPTs
1049
-        // if our cpt object isn't existent then get out immediately.
1050
-        if (! $this->_cpt_model_obj instanceof EE_CPT_Base) {
1051
-            return;
1052
-        }
1053
-        delete_post_meta($post_id, '_wp_trash_meta_status');
1054
-        delete_post_meta($post_id, '_wp_trash_meta_time');
1055
-        // our cpts may have comments so let's take care of that too
1056
-        delete_post_meta($post_id, '_wp_trash_meta_comments_status');
1057
-    }
1058
-
1059
-
1060
-    /**
1061
-     * This is a wrapper for the restore_cpt_revision route for cpt items so we can make sure that when a revision is
1062
-     * triggered that we restore related items.  In order to work cpt classes MUST have a restore_cpt_revision method
1063
-     * in them. We also have our OWN action in here so addons can hook into the restore process easily.
1064
-     *
1065
-     * @param  int $post_id     ID of cpt item
1066
-     * @param  int $revision_id ID of revision being restored
1067
-     * @return void
1068
-     */
1069
-    public function restore_revision($post_id, $revision_id)
1070
-    {
1071
-        $this->_restore_cpt_item($post_id, $revision_id);
1072
-        // global action
1073
-        do_action('AHEE_EE_Admin_Page_CPT__restore_revision', $post_id, $revision_id);
1074
-        // class specific action so you can limit hooking into a specific page.
1075
-        do_action('AHEE_EE_Admin_Page_CPT_' . get_class($this) . '__restore_revision', $post_id, $revision_id);
1076
-    }
1077
-
1078
-
1079
-    /**
1080
-     * @see restore_revision() for details
1081
-     * @param  int $post_id     ID of cpt item
1082
-     * @param  int $revision_id ID of revision for item
1083
-     * @return void
1084
-     */
1085
-    abstract protected function _restore_cpt_item($post_id, $revision_id);
1086
-
1087
-
1088
-    /**
1089
-     * Execution of this method is added to the end of the load_page_dependencies method in the parent
1090
-     * so that we can fix a bug where default core metaboxes were not being called in the sidebar.
1091
-     * To fix we have to reset the current_screen using the page_slug
1092
-     * (which is identical - or should be - to our registered_post_type id.)
1093
-     * Also, since the core WP file loads the admin_header.php for WP
1094
-     * (and there are a bunch of other things edit-form-advanced.php loads that need to happen really early)
1095
-     * we need to load it NOW, hence our _route_admin_request in here. (Otherwise screen options won't be set).
1096
-     *
1097
-     * @return void
1098
-     */
1099
-    public function modify_current_screen()
1100
-    {
1101
-        // ONLY do this if the current page_route IS a cpt route
1102
-        if (! $this->_cpt_route) {
1103
-            return;
1104
-        }
1105
-        // routing things REALLY early b/c this is a cpt admin page
1106
-        set_current_screen($this->_cpt_routes[ $this->_req_action ]);
1107
-        $this->_current_screen = get_current_screen();
1108
-        $this->_current_screen->base = 'event-espresso';
1109
-        $this->_add_help_tabs(); // we make sure we add any help tabs back in!
1110
-        /*try {
1016
+		// take care of updating any selected page_template IF this cpt supports it.
1017
+		if ($this->_supports_page_templates($post->post_type) && ! empty($this->_req_data['page_template'])) {
1018
+			// wp version aware.
1019
+			if (RecommendedVersions::compareWordPressVersion('4.7', '>=')) {
1020
+				$page_templates = wp_get_theme()->get_page_templates();
1021
+			} else {
1022
+				$post->page_template = $this->_req_data['page_template'];
1023
+				$page_templates = wp_get_theme()->get_page_templates($post);
1024
+			}
1025
+			if ('default' != $this->_req_data['page_template'] && ! isset($page_templates[ $this->_req_data['page_template'] ])) {
1026
+				EE_Error::add_error(__('Invalid Page Template.', 'event_espresso'), __FILE__, __FUNCTION__, __LINE__);
1027
+			} else {
1028
+				update_post_meta($post_id, '_wp_page_template', $this->_req_data['page_template']);
1029
+			}
1030
+		}
1031
+		if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
1032
+			return;
1033
+		} //TODO we'll remove this after reimplementing autosave in 4.2
1034
+		$this->_insert_update_cpt_item($post_id, $post);
1035
+	}
1036
+
1037
+
1038
+	/**
1039
+	 * This hooks into the wp_trash_post() function and removes the `_wp_trash_meta_status` and `_wp_trash_meta_time`
1040
+	 * post meta IF the trashed post is one of our CPT's - note this method should only be called with our cpt routes
1041
+	 * so we don't have to check for our CPT.
1042
+	 *
1043
+	 * @param  int $post_id ID of the post
1044
+	 * @return void
1045
+	 */
1046
+	public function dont_permanently_delete_ee_cpts($post_id)
1047
+	{
1048
+		// only do this if we're actually processing one of our CPTs
1049
+		// if our cpt object isn't existent then get out immediately.
1050
+		if (! $this->_cpt_model_obj instanceof EE_CPT_Base) {
1051
+			return;
1052
+		}
1053
+		delete_post_meta($post_id, '_wp_trash_meta_status');
1054
+		delete_post_meta($post_id, '_wp_trash_meta_time');
1055
+		// our cpts may have comments so let's take care of that too
1056
+		delete_post_meta($post_id, '_wp_trash_meta_comments_status');
1057
+	}
1058
+
1059
+
1060
+	/**
1061
+	 * This is a wrapper for the restore_cpt_revision route for cpt items so we can make sure that when a revision is
1062
+	 * triggered that we restore related items.  In order to work cpt classes MUST have a restore_cpt_revision method
1063
+	 * in them. We also have our OWN action in here so addons can hook into the restore process easily.
1064
+	 *
1065
+	 * @param  int $post_id     ID of cpt item
1066
+	 * @param  int $revision_id ID of revision being restored
1067
+	 * @return void
1068
+	 */
1069
+	public function restore_revision($post_id, $revision_id)
1070
+	{
1071
+		$this->_restore_cpt_item($post_id, $revision_id);
1072
+		// global action
1073
+		do_action('AHEE_EE_Admin_Page_CPT__restore_revision', $post_id, $revision_id);
1074
+		// class specific action so you can limit hooking into a specific page.
1075
+		do_action('AHEE_EE_Admin_Page_CPT_' . get_class($this) . '__restore_revision', $post_id, $revision_id);
1076
+	}
1077
+
1078
+
1079
+	/**
1080
+	 * @see restore_revision() for details
1081
+	 * @param  int $post_id     ID of cpt item
1082
+	 * @param  int $revision_id ID of revision for item
1083
+	 * @return void
1084
+	 */
1085
+	abstract protected function _restore_cpt_item($post_id, $revision_id);
1086
+
1087
+
1088
+	/**
1089
+	 * Execution of this method is added to the end of the load_page_dependencies method in the parent
1090
+	 * so that we can fix a bug where default core metaboxes were not being called in the sidebar.
1091
+	 * To fix we have to reset the current_screen using the page_slug
1092
+	 * (which is identical - or should be - to our registered_post_type id.)
1093
+	 * Also, since the core WP file loads the admin_header.php for WP
1094
+	 * (and there are a bunch of other things edit-form-advanced.php loads that need to happen really early)
1095
+	 * we need to load it NOW, hence our _route_admin_request in here. (Otherwise screen options won't be set).
1096
+	 *
1097
+	 * @return void
1098
+	 */
1099
+	public function modify_current_screen()
1100
+	{
1101
+		// ONLY do this if the current page_route IS a cpt route
1102
+		if (! $this->_cpt_route) {
1103
+			return;
1104
+		}
1105
+		// routing things REALLY early b/c this is a cpt admin page
1106
+		set_current_screen($this->_cpt_routes[ $this->_req_action ]);
1107
+		$this->_current_screen = get_current_screen();
1108
+		$this->_current_screen->base = 'event-espresso';
1109
+		$this->_add_help_tabs(); // we make sure we add any help tabs back in!
1110
+		/*try {
1111 1111
             $this->_route_admin_request();
1112 1112
         } catch ( EE_Error $e ) {
1113 1113
             $e->get_error();
1114 1114
         }/**/
1115
-    }
1116
-
1117
-
1118
-    /**
1119
-     * This allows child classes to modify the default editor title that appears when people add a new or edit an
1120
-     * existing CPT item.     * This uses the _labels property set by the child class via _define_page_props. Just make
1121
-     * sure you have a key in _labels property that equals 'editor_title' and the value can be whatever you want the
1122
-     * default to be.
1123
-     *
1124
-     * @param string $title The new title (or existing if there is no editor_title defined)
1125
-     * @return string
1126
-     */
1127
-    public function add_custom_editor_default_title($title)
1128
-    {
1129
-        return isset($this->_labels['editor_title'][ $this->_cpt_routes[ $this->_req_action ] ])
1130
-            ? $this->_labels['editor_title'][ $this->_cpt_routes[ $this->_req_action ] ]
1131
-            : $title;
1132
-    }
1133
-
1134
-
1135
-    /**
1136
-     * hooks into the wp_get_shortlink button and makes sure that the shortlink gets generated
1137
-     *
1138
-     * @param string $shortlink   The already generated shortlink
1139
-     * @param int    $id          Post ID for this item
1140
-     * @param string $context     The context for the link
1141
-     * @param bool   $allow_slugs Whether to allow post slugs in the shortlink.
1142
-     * @return string
1143
-     */
1144
-    public function add_shortlink_button_to_editor($shortlink, $id, $context, $allow_slugs)
1145
-    {
1146
-        if (! empty($id) && get_option('permalink_structure') !== '') {
1147
-            $post = get_post($id);
1148
-            if (isset($post->post_type) && $this->page_slug === $post->post_type) {
1149
-                $shortlink = home_url('?p=' . $post->ID);
1150
-            }
1151
-        }
1152
-        return $shortlink;
1153
-    }
1154
-
1155
-
1156
-    /**
1157
-     * overriding the parent route_admin_request method so we DON'T run the route twice on cpt core page loads (it's
1158
-     * already run in modify_current_screen())
1159
-     *
1160
-     * @return void
1161
-     */
1162
-    public function route_admin_request()
1163
-    {
1164
-        if ($this->_cpt_route) {
1165
-            return;
1166
-        }
1167
-        try {
1168
-            $this->_route_admin_request();
1169
-        } catch (EE_Error $e) {
1170
-            $e->get_error();
1171
-        }
1172
-    }
1173
-
1174
-
1175
-    /**
1176
-     * Add a hidden form input to cpt core pages so that we know to do redirects to our routes on saves
1177
-     *
1178
-     * @return void
1179
-     */
1180
-    public function cpt_post_form_hidden_input()
1181
-    {
1182
-        echo '<input type="hidden" name="ee_cpt_item_redirect_url" value="' . $this->_admin_base_url . '" />';
1183
-        // we're also going to add the route value and the current page so we can direct autosave parsing correctly
1184
-        echo '<div id="ee-cpt-hidden-inputs">';
1185
-        echo '<input type="hidden" id="current_route" name="current_route" value="' . $this->_current_view . '" />';
1186
-        echo '<input type="hidden" id="current_page" name="current_page" value="' . $this->page_slug . '" />';
1187
-        echo '</div>';
1188
-    }
1189
-
1190
-
1191
-    /**
1192
-     * This allows us to redirect the location of revision restores when they happen so it goes to our CPT routes.
1193
-     *
1194
-     * @param  string $location Original location url
1195
-     * @param  int    $status   Status for http header
1196
-     * @return string           new (or original) url to redirect to.
1197
-     */
1198
-    public function revision_redirect($location, $status)
1199
-    {
1200
-        // get revision
1201
-        $rev_id = isset($this->_req_data['revision']) ? $this->_req_data['revision'] : null;
1202
-        // can't do anything without revision so let's get out if not present
1203
-        if (empty($rev_id)) {
1204
-            return $location;
1205
-        }
1206
-        // get rev_post_data
1207
-        $rev = get_post($rev_id);
1208
-        $admin_url = $this->_admin_base_url;
1209
-        $query_args = array(
1210
-            'action'   => 'edit',
1211
-            'post'     => $rev->post_parent,
1212
-            'revision' => $rev_id,
1213
-            'message'  => 5,
1214
-        );
1215
-        $this->_process_notices($query_args, true);
1216
-        return self::add_query_args_and_nonce($query_args, $admin_url);
1217
-    }
1218
-
1219
-
1220
-    /**
1221
-     * Modify the edit post link generated by wp core function so that EE CPTs get setup differently.
1222
-     *
1223
-     * @param  string $link    the original generated link
1224
-     * @param  int    $id      post id
1225
-     * @param  string $context optional, defaults to display.  How to write the '&'
1226
-     * @return string          the link
1227
-     */
1228
-    public function modify_edit_post_link($link, $id, $context)
1229
-    {
1230
-        $post = get_post($id);
1231
-        if (! isset($this->_req_data['action'])
1232
-            || ! isset($this->_cpt_routes[ $this->_req_data['action'] ])
1233
-            || $post->post_type !== $this->_cpt_routes[ $this->_req_data['action'] ]
1234
-        ) {
1235
-            return $link;
1236
-        }
1237
-        $query_args = array(
1238
-            'action' => isset($this->_cpt_edit_routes[ $post->post_type ])
1239
-                ? $this->_cpt_edit_routes[ $post->post_type ]
1240
-                : 'edit',
1241
-            'post'   => $id,
1242
-        );
1243
-        return self::add_query_args_and_nonce($query_args, $this->_admin_base_url);
1244
-    }
1245
-
1246
-
1247
-    /**
1248
-     * Modify the trash link on our cpt edit pages so it has the required query var for triggering redirect properly on
1249
-     * our routes.
1250
-     *
1251
-     * @param  string $delete_link  original delete link
1252
-     * @param  int    $post_id      id of cpt object
1253
-     * @param  bool   $force_delete whether this is forcing a hard delete instead of trash
1254
-     * @return string new delete link
1255
-     * @throws EE_Error
1256
-     */
1257
-    public function modify_delete_post_link($delete_link, $post_id, $force_delete)
1258
-    {
1259
-        $post = get_post($post_id);
1260
-
1261
-        if (empty($this->_req_data['action'])
1262
-            || ! isset($this->_cpt_routes[ $this->_req_data['action'] ])
1263
-            || ! $post instanceof WP_Post
1264
-            || $post->post_type !== $this->_cpt_routes[ $this->_req_data['action'] ]
1265
-        ) {
1266
-            return $delete_link;
1267
-        }
1268
-        $this->_set_model_object($post->ID, true);
1269
-
1270
-        // returns something like `trash_event` or `trash_attendee` or `trash_venue`
1271
-        $action = 'trash_' . str_replace('ee_', '', strtolower(get_class($this->_cpt_model_obj)));
1272
-
1273
-        return EE_Admin_Page::add_query_args_and_nonce(
1274
-            array(
1275
-                'page'   => $this->_req_data['page'],
1276
-                'action' => $action,
1277
-                $this->_cpt_model_obj->get_model()->get_primary_key_field()->get_name()
1278
-                         => $post->ID,
1279
-            ),
1280
-            admin_url()
1281
-        );
1282
-    }
1283
-
1284
-
1285
-    /**
1286
-     * This is the callback for the 'redirect_post_location' filter in wp-admin/post.php
1287
-     * so that we can hijack the default redirect locations for wp custom post types
1288
-     * that WE'RE using and send back to OUR routes.  This should only be hooked in on the right route.
1289
-     *
1290
-     * @param  string $location This is the incoming currently set redirect location
1291
-     * @param  string $post_id  This is the 'ID' value of the wp_posts table
1292
-     * @return string           the new location to redirect to
1293
-     */
1294
-    public function cpt_post_location_redirect($location, $post_id)
1295
-    {
1296
-        // we DO have a match so let's setup the url
1297
-        // we have to get the post to determine our route
1298
-        $post = get_post($post_id);
1299
-        $edit_route = $this->_cpt_edit_routes[ $post->post_type ];
1300
-        // shared query_args
1301
-        $query_args = array('action' => $edit_route, 'post' => $post_id);
1302
-        $admin_url = $this->_admin_base_url;
1303
-        if (isset($this->_req_data['save']) || isset($this->_req_data['publish'])) {
1304
-            $status = get_post_status($post_id);
1305
-            if (isset($this->_req_data['publish'])) {
1306
-                switch ($status) {
1307
-                    case 'pending':
1308
-                        $message = 8;
1309
-                        break;
1310
-                    case 'future':
1311
-                        $message = 9;
1312
-                        break;
1313
-                    default:
1314
-                        $message = 6;
1315
-                }
1316
-            } else {
1317
-                $message = 'draft' === $status ? 10 : 1;
1318
-            }
1319
-        } elseif (isset($this->_req_data['addmeta']) && $this->_req_data['addmeta']) {
1320
-            $message = 2;
1321
-        } elseif (isset($this->_req_data['deletemeta']) && $this->_req_data['deletemeta']) {
1322
-            $message = 3;
1323
-        } elseif ($this->_req_data['action'] === 'post-quickpress-save-cont') {
1324
-            $message = 7;
1325
-        } else {
1326
-            $message = 4;
1327
-        }
1328
-        // change the message if the post type is not viewable on the frontend
1329
-        $this->_cpt_object = get_post_type_object($post->post_type);
1330
-        $message = $message === 1 && ! $this->_cpt_object->publicly_queryable ? 4 : $message;
1331
-        $query_args = array_merge(array('message' => $message), $query_args);
1332
-        $this->_process_notices($query_args, true);
1333
-        return self::add_query_args_and_nonce($query_args, $admin_url);
1334
-    }
1335
-
1336
-
1337
-    /**
1338
-     * This method is called to inject nav tabs on core WP cpt pages
1339
-     *
1340
-     * @access public
1341
-     * @return void
1342
-     */
1343
-    public function inject_nav_tabs()
1344
-    {
1345
-        // can we hijack and insert the nav_tabs?
1346
-        $nav_tabs = $this->_get_main_nav_tabs();
1347
-        // first close off existing form tag
1348
-        $html = '>';
1349
-        $html .= $nav_tabs;
1350
-        // now let's handle the remaining tag ( missing ">" is CORRECT )
1351
-        $html .= '<span></span';
1352
-        echo $html;
1353
-    }
1354
-
1355
-
1356
-    /**
1357
-     * This just sets up the post update messages when an update form is loaded
1358
-     *
1359
-     * @access public
1360
-     * @param  array $messages the original messages array
1361
-     * @return array           the new messages array
1362
-     */
1363
-    public function post_update_messages($messages)
1364
-    {
1365
-        global $post;
1366
-        $id = isset($this->_req_data['post']) ? $this->_req_data['post'] : null;
1367
-        $id = empty($id) && is_object($post) ? $post->ID : null;
1368
-        /*$current_route = isset($this->_req_data['current_route']) ? $this->_req_data['current_route'] : 'shouldneverwork';
1115
+	}
1116
+
1117
+
1118
+	/**
1119
+	 * This allows child classes to modify the default editor title that appears when people add a new or edit an
1120
+	 * existing CPT item.     * This uses the _labels property set by the child class via _define_page_props. Just make
1121
+	 * sure you have a key in _labels property that equals 'editor_title' and the value can be whatever you want the
1122
+	 * default to be.
1123
+	 *
1124
+	 * @param string $title The new title (or existing if there is no editor_title defined)
1125
+	 * @return string
1126
+	 */
1127
+	public function add_custom_editor_default_title($title)
1128
+	{
1129
+		return isset($this->_labels['editor_title'][ $this->_cpt_routes[ $this->_req_action ] ])
1130
+			? $this->_labels['editor_title'][ $this->_cpt_routes[ $this->_req_action ] ]
1131
+			: $title;
1132
+	}
1133
+
1134
+
1135
+	/**
1136
+	 * hooks into the wp_get_shortlink button and makes sure that the shortlink gets generated
1137
+	 *
1138
+	 * @param string $shortlink   The already generated shortlink
1139
+	 * @param int    $id          Post ID for this item
1140
+	 * @param string $context     The context for the link
1141
+	 * @param bool   $allow_slugs Whether to allow post slugs in the shortlink.
1142
+	 * @return string
1143
+	 */
1144
+	public function add_shortlink_button_to_editor($shortlink, $id, $context, $allow_slugs)
1145
+	{
1146
+		if (! empty($id) && get_option('permalink_structure') !== '') {
1147
+			$post = get_post($id);
1148
+			if (isset($post->post_type) && $this->page_slug === $post->post_type) {
1149
+				$shortlink = home_url('?p=' . $post->ID);
1150
+			}
1151
+		}
1152
+		return $shortlink;
1153
+	}
1154
+
1155
+
1156
+	/**
1157
+	 * overriding the parent route_admin_request method so we DON'T run the route twice on cpt core page loads (it's
1158
+	 * already run in modify_current_screen())
1159
+	 *
1160
+	 * @return void
1161
+	 */
1162
+	public function route_admin_request()
1163
+	{
1164
+		if ($this->_cpt_route) {
1165
+			return;
1166
+		}
1167
+		try {
1168
+			$this->_route_admin_request();
1169
+		} catch (EE_Error $e) {
1170
+			$e->get_error();
1171
+		}
1172
+	}
1173
+
1174
+
1175
+	/**
1176
+	 * Add a hidden form input to cpt core pages so that we know to do redirects to our routes on saves
1177
+	 *
1178
+	 * @return void
1179
+	 */
1180
+	public function cpt_post_form_hidden_input()
1181
+	{
1182
+		echo '<input type="hidden" name="ee_cpt_item_redirect_url" value="' . $this->_admin_base_url . '" />';
1183
+		// we're also going to add the route value and the current page so we can direct autosave parsing correctly
1184
+		echo '<div id="ee-cpt-hidden-inputs">';
1185
+		echo '<input type="hidden" id="current_route" name="current_route" value="' . $this->_current_view . '" />';
1186
+		echo '<input type="hidden" id="current_page" name="current_page" value="' . $this->page_slug . '" />';
1187
+		echo '</div>';
1188
+	}
1189
+
1190
+
1191
+	/**
1192
+	 * This allows us to redirect the location of revision restores when they happen so it goes to our CPT routes.
1193
+	 *
1194
+	 * @param  string $location Original location url
1195
+	 * @param  int    $status   Status for http header
1196
+	 * @return string           new (or original) url to redirect to.
1197
+	 */
1198
+	public function revision_redirect($location, $status)
1199
+	{
1200
+		// get revision
1201
+		$rev_id = isset($this->_req_data['revision']) ? $this->_req_data['revision'] : null;
1202
+		// can't do anything without revision so let's get out if not present
1203
+		if (empty($rev_id)) {
1204
+			return $location;
1205
+		}
1206
+		// get rev_post_data
1207
+		$rev = get_post($rev_id);
1208
+		$admin_url = $this->_admin_base_url;
1209
+		$query_args = array(
1210
+			'action'   => 'edit',
1211
+			'post'     => $rev->post_parent,
1212
+			'revision' => $rev_id,
1213
+			'message'  => 5,
1214
+		);
1215
+		$this->_process_notices($query_args, true);
1216
+		return self::add_query_args_and_nonce($query_args, $admin_url);
1217
+	}
1218
+
1219
+
1220
+	/**
1221
+	 * Modify the edit post link generated by wp core function so that EE CPTs get setup differently.
1222
+	 *
1223
+	 * @param  string $link    the original generated link
1224
+	 * @param  int    $id      post id
1225
+	 * @param  string $context optional, defaults to display.  How to write the '&'
1226
+	 * @return string          the link
1227
+	 */
1228
+	public function modify_edit_post_link($link, $id, $context)
1229
+	{
1230
+		$post = get_post($id);
1231
+		if (! isset($this->_req_data['action'])
1232
+			|| ! isset($this->_cpt_routes[ $this->_req_data['action'] ])
1233
+			|| $post->post_type !== $this->_cpt_routes[ $this->_req_data['action'] ]
1234
+		) {
1235
+			return $link;
1236
+		}
1237
+		$query_args = array(
1238
+			'action' => isset($this->_cpt_edit_routes[ $post->post_type ])
1239
+				? $this->_cpt_edit_routes[ $post->post_type ]
1240
+				: 'edit',
1241
+			'post'   => $id,
1242
+		);
1243
+		return self::add_query_args_and_nonce($query_args, $this->_admin_base_url);
1244
+	}
1245
+
1246
+
1247
+	/**
1248
+	 * Modify the trash link on our cpt edit pages so it has the required query var for triggering redirect properly on
1249
+	 * our routes.
1250
+	 *
1251
+	 * @param  string $delete_link  original delete link
1252
+	 * @param  int    $post_id      id of cpt object
1253
+	 * @param  bool   $force_delete whether this is forcing a hard delete instead of trash
1254
+	 * @return string new delete link
1255
+	 * @throws EE_Error
1256
+	 */
1257
+	public function modify_delete_post_link($delete_link, $post_id, $force_delete)
1258
+	{
1259
+		$post = get_post($post_id);
1260
+
1261
+		if (empty($this->_req_data['action'])
1262
+			|| ! isset($this->_cpt_routes[ $this->_req_data['action'] ])
1263
+			|| ! $post instanceof WP_Post
1264
+			|| $post->post_type !== $this->_cpt_routes[ $this->_req_data['action'] ]
1265
+		) {
1266
+			return $delete_link;
1267
+		}
1268
+		$this->_set_model_object($post->ID, true);
1269
+
1270
+		// returns something like `trash_event` or `trash_attendee` or `trash_venue`
1271
+		$action = 'trash_' . str_replace('ee_', '', strtolower(get_class($this->_cpt_model_obj)));
1272
+
1273
+		return EE_Admin_Page::add_query_args_and_nonce(
1274
+			array(
1275
+				'page'   => $this->_req_data['page'],
1276
+				'action' => $action,
1277
+				$this->_cpt_model_obj->get_model()->get_primary_key_field()->get_name()
1278
+						 => $post->ID,
1279
+			),
1280
+			admin_url()
1281
+		);
1282
+	}
1283
+
1284
+
1285
+	/**
1286
+	 * This is the callback for the 'redirect_post_location' filter in wp-admin/post.php
1287
+	 * so that we can hijack the default redirect locations for wp custom post types
1288
+	 * that WE'RE using and send back to OUR routes.  This should only be hooked in on the right route.
1289
+	 *
1290
+	 * @param  string $location This is the incoming currently set redirect location
1291
+	 * @param  string $post_id  This is the 'ID' value of the wp_posts table
1292
+	 * @return string           the new location to redirect to
1293
+	 */
1294
+	public function cpt_post_location_redirect($location, $post_id)
1295
+	{
1296
+		// we DO have a match so let's setup the url
1297
+		// we have to get the post to determine our route
1298
+		$post = get_post($post_id);
1299
+		$edit_route = $this->_cpt_edit_routes[ $post->post_type ];
1300
+		// shared query_args
1301
+		$query_args = array('action' => $edit_route, 'post' => $post_id);
1302
+		$admin_url = $this->_admin_base_url;
1303
+		if (isset($this->_req_data['save']) || isset($this->_req_data['publish'])) {
1304
+			$status = get_post_status($post_id);
1305
+			if (isset($this->_req_data['publish'])) {
1306
+				switch ($status) {
1307
+					case 'pending':
1308
+						$message = 8;
1309
+						break;
1310
+					case 'future':
1311
+						$message = 9;
1312
+						break;
1313
+					default:
1314
+						$message = 6;
1315
+				}
1316
+			} else {
1317
+				$message = 'draft' === $status ? 10 : 1;
1318
+			}
1319
+		} elseif (isset($this->_req_data['addmeta']) && $this->_req_data['addmeta']) {
1320
+			$message = 2;
1321
+		} elseif (isset($this->_req_data['deletemeta']) && $this->_req_data['deletemeta']) {
1322
+			$message = 3;
1323
+		} elseif ($this->_req_data['action'] === 'post-quickpress-save-cont') {
1324
+			$message = 7;
1325
+		} else {
1326
+			$message = 4;
1327
+		}
1328
+		// change the message if the post type is not viewable on the frontend
1329
+		$this->_cpt_object = get_post_type_object($post->post_type);
1330
+		$message = $message === 1 && ! $this->_cpt_object->publicly_queryable ? 4 : $message;
1331
+		$query_args = array_merge(array('message' => $message), $query_args);
1332
+		$this->_process_notices($query_args, true);
1333
+		return self::add_query_args_and_nonce($query_args, $admin_url);
1334
+	}
1335
+
1336
+
1337
+	/**
1338
+	 * This method is called to inject nav tabs on core WP cpt pages
1339
+	 *
1340
+	 * @access public
1341
+	 * @return void
1342
+	 */
1343
+	public function inject_nav_tabs()
1344
+	{
1345
+		// can we hijack and insert the nav_tabs?
1346
+		$nav_tabs = $this->_get_main_nav_tabs();
1347
+		// first close off existing form tag
1348
+		$html = '>';
1349
+		$html .= $nav_tabs;
1350
+		// now let's handle the remaining tag ( missing ">" is CORRECT )
1351
+		$html .= '<span></span';
1352
+		echo $html;
1353
+	}
1354
+
1355
+
1356
+	/**
1357
+	 * This just sets up the post update messages when an update form is loaded
1358
+	 *
1359
+	 * @access public
1360
+	 * @param  array $messages the original messages array
1361
+	 * @return array           the new messages array
1362
+	 */
1363
+	public function post_update_messages($messages)
1364
+	{
1365
+		global $post;
1366
+		$id = isset($this->_req_data['post']) ? $this->_req_data['post'] : null;
1367
+		$id = empty($id) && is_object($post) ? $post->ID : null;
1368
+		/*$current_route = isset($this->_req_data['current_route']) ? $this->_req_data['current_route'] : 'shouldneverwork';
1369 1369
 
1370 1370
         $route_to_check = $post_type && isset( $this->_cpt_routes[$current_route]) ? $this->_cpt_routes[$current_route] : '';/**/
1371
-        $messages[ $post->post_type ] = array(
1372
-            0  => '', // Unused. Messages start at index 1.
1373
-            1  => sprintf(
1374
-                __('%1$s updated. %2$sView %1$s%3$s', 'event_espresso'),
1375
-                $this->_cpt_object->labels->singular_name,
1376
-                '<a href="' . esc_url(get_permalink($id)) . '">',
1377
-                '</a>'
1378
-            ),
1379
-            2  => __('Custom field updated', 'event_espresso'),
1380
-            3  => __('Custom field deleted.', 'event_espresso'),
1381
-            4  => sprintf(__('%1$s updated.', 'event_espresso'), $this->_cpt_object->labels->singular_name),
1382
-            5  => isset($_GET['revision']) ? sprintf(
1383
-                __('%s restored to revision from %s', 'event_espresso'),
1384
-                $this->_cpt_object->labels->singular_name,
1385
-                wp_post_revision_title((int) $_GET['revision'], false)
1386
-            )
1387
-                : false,
1388
-            6  => sprintf(
1389
-                __('%1$s published. %2$sView %1$s%3$s', 'event_espresso'),
1390
-                $this->_cpt_object->labels->singular_name,
1391
-                '<a href="' . esc_url(get_permalink($id)) . '">',
1392
-                '</a>'
1393
-            ),
1394
-            7  => sprintf(__('%1$s saved.', 'event_espresso'), $this->_cpt_object->labels->singular_name),
1395
-            8  => sprintf(
1396
-                __('%1$s submitted. %2$sPreview %1$s%3$s', 'event_espresso'),
1397
-                $this->_cpt_object->labels->singular_name,
1398
-                '<a target="_blank" href="' . esc_url(add_query_arg('preview', 'true', get_permalink($id))) . '">',
1399
-                '</a>'
1400
-            ),
1401
-            9  => sprintf(
1402
-                __('%1$s scheduled for: %2$s. %3$s">Preview %1$s%3$s', 'event_espresso'),
1403
-                $this->_cpt_object->labels->singular_name,
1404
-                '<strong>' . date_i18n('M j, Y @ G:i', strtotime($post->post_date)) . '</strong>',
1405
-                '<a target="_blank" href="' . esc_url(get_permalink($id)),
1406
-                '</a>'
1407
-            ),
1408
-            10 => sprintf(
1409
-                __('%1$s draft updated. %2$s">Preview page%3$s', 'event_espresso'),
1410
-                $this->_cpt_object->labels->singular_name,
1411
-                '<a target="_blank" href="' . esc_url(add_query_arg('preview', 'true', get_permalink($id))),
1412
-                '</a>'
1413
-            ),
1414
-        );
1415
-        return $messages;
1416
-    }
1417
-
1418
-
1419
-    /**
1420
-     * default method for the 'create_new' route for cpt admin pages.
1421
-     * For reference what to include in here, see wp-admin/post-new.php
1422
-     *
1423
-     * @access  protected
1424
-     * @return void
1425
-     */
1426
-    protected function _create_new_cpt_item()
1427
-    {
1428
-        // gather template vars for WP_ADMIN_PATH . 'edit-form-advanced.php'
1429
-        global $post, $title, $is_IE, $post_type, $post_type_object;
1430
-        $post_type = $this->_cpt_routes[ $this->_req_action ];
1431
-        $post_type_object = $this->_cpt_object;
1432
-        $title = $post_type_object->labels->add_new_item;
1433
-        $post = $post = get_default_post_to_edit($this->_cpt_routes[ $this->_req_action ], true);
1434
-        add_action('admin_print_styles', array($this, 'add_new_admin_page_global'));
1435
-        // modify the default editor title field with default title.
1436
-        add_filter('enter_title_here', array($this, 'add_custom_editor_default_title'), 10);
1437
-        $this->loadEditorTemplate(true);
1438
-    }
1439
-
1440
-
1441
-    /**
1442
-     * Enqueues auto-save and loads the editor template
1443
-     *
1444
-     * @param bool $creating
1445
-     */
1446
-    private function loadEditorTemplate($creating = true)
1447
-    {
1448
-        global $post, $title, $is_IE, $post_type, $post_type_object;
1449
-        // these vars are used by the template
1450
-        $editing = true;
1451
-        $post_ID = $post->ID;
1452
-        if (apply_filters('FHEE__EE_Admin_Page_CPT___create_new_cpt_item__replace_editor', false, $post) === false) {
1453
-            // only enqueue autosave when creating event (necessary to get permalink/url generated)
1454
-            // otherwise EE doesn't support autosave fully, so to prevent user confusion we disable it in edit context.
1455
-            if ($creating) {
1456
-                wp_enqueue_script('autosave');
1457
-            } else {
1458
-                if (isset($this->_cpt_routes[ $this->_req_data['action'] ])
1459
-                    && ! isset($this->_labels['hide_add_button_on_cpt_route'][ $this->_req_data['action'] ])
1460
-                ) {
1461
-                    $create_new_action = apply_filters(
1462
-                        'FHEE__EE_Admin_Page_CPT___edit_cpt_item__create_new_action',
1463
-                        'create_new',
1464
-                        $this
1465
-                    );
1466
-                    $post_new_file = EE_Admin_Page::add_query_args_and_nonce(
1467
-                        array(
1468
-                            'action' => $create_new_action,
1469
-                            'page'   => $this->page_slug,
1470
-                        ),
1471
-                        'admin.php'
1472
-                    );
1473
-                }
1474
-            }
1475
-            include_once WP_ADMIN_PATH . 'edit-form-advanced.php';
1476
-        }
1477
-    }
1478
-
1479
-
1480
-    public function add_new_admin_page_global()
1481
-    {
1482
-        $admin_page = ! empty($this->_req_data['post']) ? 'post-php' : 'post-new-php';
1483
-        ?>
1371
+		$messages[ $post->post_type ] = array(
1372
+			0  => '', // Unused. Messages start at index 1.
1373
+			1  => sprintf(
1374
+				__('%1$s updated. %2$sView %1$s%3$s', 'event_espresso'),
1375
+				$this->_cpt_object->labels->singular_name,
1376
+				'<a href="' . esc_url(get_permalink($id)) . '">',
1377
+				'</a>'
1378
+			),
1379
+			2  => __('Custom field updated', 'event_espresso'),
1380
+			3  => __('Custom field deleted.', 'event_espresso'),
1381
+			4  => sprintf(__('%1$s updated.', 'event_espresso'), $this->_cpt_object->labels->singular_name),
1382
+			5  => isset($_GET['revision']) ? sprintf(
1383
+				__('%s restored to revision from %s', 'event_espresso'),
1384
+				$this->_cpt_object->labels->singular_name,
1385
+				wp_post_revision_title((int) $_GET['revision'], false)
1386
+			)
1387
+				: false,
1388
+			6  => sprintf(
1389
+				__('%1$s published. %2$sView %1$s%3$s', 'event_espresso'),
1390
+				$this->_cpt_object->labels->singular_name,
1391
+				'<a href="' . esc_url(get_permalink($id)) . '">',
1392
+				'</a>'
1393
+			),
1394
+			7  => sprintf(__('%1$s saved.', 'event_espresso'), $this->_cpt_object->labels->singular_name),
1395
+			8  => sprintf(
1396
+				__('%1$s submitted. %2$sPreview %1$s%3$s', 'event_espresso'),
1397
+				$this->_cpt_object->labels->singular_name,
1398
+				'<a target="_blank" href="' . esc_url(add_query_arg('preview', 'true', get_permalink($id))) . '">',
1399
+				'</a>'
1400
+			),
1401
+			9  => sprintf(
1402
+				__('%1$s scheduled for: %2$s. %3$s">Preview %1$s%3$s', 'event_espresso'),
1403
+				$this->_cpt_object->labels->singular_name,
1404
+				'<strong>' . date_i18n('M j, Y @ G:i', strtotime($post->post_date)) . '</strong>',
1405
+				'<a target="_blank" href="' . esc_url(get_permalink($id)),
1406
+				'</a>'
1407
+			),
1408
+			10 => sprintf(
1409
+				__('%1$s draft updated. %2$s">Preview page%3$s', 'event_espresso'),
1410
+				$this->_cpt_object->labels->singular_name,
1411
+				'<a target="_blank" href="' . esc_url(add_query_arg('preview', 'true', get_permalink($id))),
1412
+				'</a>'
1413
+			),
1414
+		);
1415
+		return $messages;
1416
+	}
1417
+
1418
+
1419
+	/**
1420
+	 * default method for the 'create_new' route for cpt admin pages.
1421
+	 * For reference what to include in here, see wp-admin/post-new.php
1422
+	 *
1423
+	 * @access  protected
1424
+	 * @return void
1425
+	 */
1426
+	protected function _create_new_cpt_item()
1427
+	{
1428
+		// gather template vars for WP_ADMIN_PATH . 'edit-form-advanced.php'
1429
+		global $post, $title, $is_IE, $post_type, $post_type_object;
1430
+		$post_type = $this->_cpt_routes[ $this->_req_action ];
1431
+		$post_type_object = $this->_cpt_object;
1432
+		$title = $post_type_object->labels->add_new_item;
1433
+		$post = $post = get_default_post_to_edit($this->_cpt_routes[ $this->_req_action ], true);
1434
+		add_action('admin_print_styles', array($this, 'add_new_admin_page_global'));
1435
+		// modify the default editor title field with default title.
1436
+		add_filter('enter_title_here', array($this, 'add_custom_editor_default_title'), 10);
1437
+		$this->loadEditorTemplate(true);
1438
+	}
1439
+
1440
+
1441
+	/**
1442
+	 * Enqueues auto-save and loads the editor template
1443
+	 *
1444
+	 * @param bool $creating
1445
+	 */
1446
+	private function loadEditorTemplate($creating = true)
1447
+	{
1448
+		global $post, $title, $is_IE, $post_type, $post_type_object;
1449
+		// these vars are used by the template
1450
+		$editing = true;
1451
+		$post_ID = $post->ID;
1452
+		if (apply_filters('FHEE__EE_Admin_Page_CPT___create_new_cpt_item__replace_editor', false, $post) === false) {
1453
+			// only enqueue autosave when creating event (necessary to get permalink/url generated)
1454
+			// otherwise EE doesn't support autosave fully, so to prevent user confusion we disable it in edit context.
1455
+			if ($creating) {
1456
+				wp_enqueue_script('autosave');
1457
+			} else {
1458
+				if (isset($this->_cpt_routes[ $this->_req_data['action'] ])
1459
+					&& ! isset($this->_labels['hide_add_button_on_cpt_route'][ $this->_req_data['action'] ])
1460
+				) {
1461
+					$create_new_action = apply_filters(
1462
+						'FHEE__EE_Admin_Page_CPT___edit_cpt_item__create_new_action',
1463
+						'create_new',
1464
+						$this
1465
+					);
1466
+					$post_new_file = EE_Admin_Page::add_query_args_and_nonce(
1467
+						array(
1468
+							'action' => $create_new_action,
1469
+							'page'   => $this->page_slug,
1470
+						),
1471
+						'admin.php'
1472
+					);
1473
+				}
1474
+			}
1475
+			include_once WP_ADMIN_PATH . 'edit-form-advanced.php';
1476
+		}
1477
+	}
1478
+
1479
+
1480
+	public function add_new_admin_page_global()
1481
+	{
1482
+		$admin_page = ! empty($this->_req_data['post']) ? 'post-php' : 'post-new-php';
1483
+		?>
1484 1484
         <script type="text/javascript">
1485 1485
             adminpage = '<?php echo $admin_page; ?>';
1486 1486
         </script>
1487 1487
         <?php
1488
-    }
1489
-
1490
-
1491
-    /**
1492
-     * default method for the 'edit' route for cpt admin pages
1493
-     * For reference on what to put in here, refer to wp-admin/post.php
1494
-     *
1495
-     * @access protected
1496
-     * @return string   template for edit cpt form
1497
-     */
1498
-    protected function _edit_cpt_item()
1499
-    {
1500
-        global $post, $title, $is_IE, $post_type, $post_type_object;
1501
-        $post_id = isset($this->_req_data['post']) ? $this->_req_data['post'] : null;
1502
-        $post = ! empty($post_id) ? get_post($post_id, OBJECT, 'edit') : null;
1503
-        if (empty($post)) {
1504
-            wp_die(__('You attempted to edit an item that doesn&#8217;t exist. Perhaps it was deleted?', 'event_espresso'));
1505
-        }
1506
-        if (! empty($_GET['get-post-lock'])) {
1507
-            wp_set_post_lock($post_id);
1508
-            wp_redirect(get_edit_post_link($post_id, 'url'));
1509
-            exit();
1510
-        }
1511
-
1512
-        // template vars for WP_ADMIN_PATH . 'edit-form-advanced.php'
1513
-        $post_type = $this->_cpt_routes[ $this->_req_action ];
1514
-        $post_type_object = $this->_cpt_object;
1515
-
1516
-        if (! wp_check_post_lock($post->ID)) {
1517
-            wp_set_post_lock($post->ID);
1518
-        }
1519
-        add_action('admin_footer', '_admin_notice_post_locked');
1520
-        if (post_type_supports($this->_cpt_routes[ $this->_req_action ], 'comments')) {
1521
-            wp_enqueue_script('admin-comments');
1522
-            enqueue_comment_hotkeys_js();
1523
-        }
1524
-        add_action('admin_print_styles', array($this, 'add_new_admin_page_global'));
1525
-        // modify the default editor title field with default title.
1526
-        add_filter('enter_title_here', array($this, 'add_custom_editor_default_title'), 10);
1527
-        $this->loadEditorTemplate(false);
1528
-    }
1529
-
1530
-
1531
-
1532
-    /**
1533
-     * some getters
1534
-     */
1535
-    /**
1536
-     * This returns the protected _cpt_model_obj property
1537
-     *
1538
-     * @return EE_CPT_Base
1539
-     */
1540
-    public function get_cpt_model_obj()
1541
-    {
1542
-        return $this->_cpt_model_obj;
1543
-    }
1488
+	}
1489
+
1490
+
1491
+	/**
1492
+	 * default method for the 'edit' route for cpt admin pages
1493
+	 * For reference on what to put in here, refer to wp-admin/post.php
1494
+	 *
1495
+	 * @access protected
1496
+	 * @return string   template for edit cpt form
1497
+	 */
1498
+	protected function _edit_cpt_item()
1499
+	{
1500
+		global $post, $title, $is_IE, $post_type, $post_type_object;
1501
+		$post_id = isset($this->_req_data['post']) ? $this->_req_data['post'] : null;
1502
+		$post = ! empty($post_id) ? get_post($post_id, OBJECT, 'edit') : null;
1503
+		if (empty($post)) {
1504
+			wp_die(__('You attempted to edit an item that doesn&#8217;t exist. Perhaps it was deleted?', 'event_espresso'));
1505
+		}
1506
+		if (! empty($_GET['get-post-lock'])) {
1507
+			wp_set_post_lock($post_id);
1508
+			wp_redirect(get_edit_post_link($post_id, 'url'));
1509
+			exit();
1510
+		}
1511
+
1512
+		// template vars for WP_ADMIN_PATH . 'edit-form-advanced.php'
1513
+		$post_type = $this->_cpt_routes[ $this->_req_action ];
1514
+		$post_type_object = $this->_cpt_object;
1515
+
1516
+		if (! wp_check_post_lock($post->ID)) {
1517
+			wp_set_post_lock($post->ID);
1518
+		}
1519
+		add_action('admin_footer', '_admin_notice_post_locked');
1520
+		if (post_type_supports($this->_cpt_routes[ $this->_req_action ], 'comments')) {
1521
+			wp_enqueue_script('admin-comments');
1522
+			enqueue_comment_hotkeys_js();
1523
+		}
1524
+		add_action('admin_print_styles', array($this, 'add_new_admin_page_global'));
1525
+		// modify the default editor title field with default title.
1526
+		add_filter('enter_title_here', array($this, 'add_custom_editor_default_title'), 10);
1527
+		$this->loadEditorTemplate(false);
1528
+	}
1529
+
1530
+
1531
+
1532
+	/**
1533
+	 * some getters
1534
+	 */
1535
+	/**
1536
+	 * This returns the protected _cpt_model_obj property
1537
+	 *
1538
+	 * @return EE_CPT_Base
1539
+	 */
1540
+	public function get_cpt_model_obj()
1541
+	{
1542
+		return $this->_cpt_model_obj;
1543
+	}
1544 1544
 }
Please login to merge, or discard this patch.
core/domain/services/assets/EspressoEditorAssetManager.php 2 patches
Indentation   +58 added lines, -58 removed lines patch added patch discarded remove patch
@@ -19,67 +19,67 @@
 block discarded – undo
19 19
  */
20 20
 class EspressoEditorAssetManager extends AssetManager
21 21
 {
22
-    const JS_HANDLE_EDITOR = 'eventespresso-editor';
23
-    const CSS_HANDLE_EDITOR = 'eventespresso-editor';
24
-    const ASSET_CHUNK_NAME_EDITOR = 'editor';
22
+	const JS_HANDLE_EDITOR = 'eventespresso-editor';
23
+	const CSS_HANDLE_EDITOR = 'eventespresso-editor';
24
+	const ASSET_CHUNK_NAME_EDITOR = 'editor';
25 25
 
26
-    /**
27
-     * @since 4.9.62.p
28
-     * @throws DomainException
29
-     * @throws InvalidDataTypeException
30
-     * @throws InvalidEntityException
31
-     * @throws DuplicateCollectionIdentifierException
32
-     */
33
-    public function addAssets()
34
-    {
35
-        $this->registerJavascript();
36
-        $this->registerStyleSheets();
37
-    }
26
+	/**
27
+	 * @since 4.9.62.p
28
+	 * @throws DomainException
29
+	 * @throws InvalidDataTypeException
30
+	 * @throws InvalidEntityException
31
+	 * @throws DuplicateCollectionIdentifierException
32
+	 */
33
+	public function addAssets()
34
+	{
35
+		$this->registerJavascript();
36
+		$this->registerStyleSheets();
37
+	}
38 38
 
39 39
 
40
-    /**
41
-     * Register javascript assets
42
-     *
43
-     * @throws DomainException
44
-     * @throws InvalidDataTypeException
45
-     * @throws InvalidEntityException
46
-     * @throws DuplicateCollectionIdentifierException
47
-     */
48
-    private function registerJavascript()
49
-    {
50
-        $this->addJavascript(
51
-            self::JS_HANDLE_EDITOR,
52
-            $this->registry->getJsUrl(
53
-                $this->domain->assetNamespace(),
54
-                self::ASSET_CHUNK_NAME_EDITOR
55
-            ),
56
-            [
57
-                CoreAssetManager::JS_HANDLE_COMPONENTS,
58
-                CoreAssetManager::JS_HANDLE_HOCS,
59
-                'ee-datepicker'
60
-            ]
61
-        )
62
-            ->setRequiresTranslation();
63
-    }
40
+	/**
41
+	 * Register javascript assets
42
+	 *
43
+	 * @throws DomainException
44
+	 * @throws InvalidDataTypeException
45
+	 * @throws InvalidEntityException
46
+	 * @throws DuplicateCollectionIdentifierException
47
+	 */
48
+	private function registerJavascript()
49
+	{
50
+		$this->addJavascript(
51
+			self::JS_HANDLE_EDITOR,
52
+			$this->registry->getJsUrl(
53
+				$this->domain->assetNamespace(),
54
+				self::ASSET_CHUNK_NAME_EDITOR
55
+			),
56
+			[
57
+				CoreAssetManager::JS_HANDLE_COMPONENTS,
58
+				CoreAssetManager::JS_HANDLE_HOCS,
59
+				'ee-datepicker'
60
+			]
61
+		)
62
+			->setRequiresTranslation();
63
+	}
64 64
 
65 65
 
66
-    /**
67
-     * Register CSS assets.
68
-     *
69
-     * @throws DomainException
70
-     * @throws DuplicateCollectionIdentifierException
71
-     * @throws InvalidDataTypeException
72
-     * @throws InvalidEntityException
73
-     */
74
-    private function registerStyleSheets()
75
-    {
76
-        $this->addStylesheet(
77
-            self::CSS_HANDLE_EDITOR,
78
-            $this->registry->getCssUrl(
79
-                $this->domain->assetNamespace(),
80
-                self::ASSET_CHUNK_NAME_EDITOR
81
-            ),
82
-            [ CoreAssetManager::CSS_HANDLE_COMPONENTS ]
83
-        );
84
-    }
66
+	/**
67
+	 * Register CSS assets.
68
+	 *
69
+	 * @throws DomainException
70
+	 * @throws DuplicateCollectionIdentifierException
71
+	 * @throws InvalidDataTypeException
72
+	 * @throws InvalidEntityException
73
+	 */
74
+	private function registerStyleSheets()
75
+	{
76
+		$this->addStylesheet(
77
+			self::CSS_HANDLE_EDITOR,
78
+			$this->registry->getCssUrl(
79
+				$this->domain->assetNamespace(),
80
+				self::ASSET_CHUNK_NAME_EDITOR
81
+			),
82
+			[ CoreAssetManager::CSS_HANDLE_COMPONENTS ]
83
+		);
84
+	}
85 85
 }
Please login to merge, or discard this patch.
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -79,7 +79,7 @@
 block discarded – undo
79 79
                 $this->domain->assetNamespace(),
80 80
                 self::ASSET_CHUNK_NAME_EDITOR
81 81
             ),
82
-            [ CoreAssetManager::CSS_HANDLE_COMPONENTS ]
82
+            [CoreAssetManager::CSS_HANDLE_COMPONENTS]
83 83
         );
84 84
     }
85 85
 }
Please login to merge, or discard this patch.
admin_pages/events/Events_Admin_Page.core.php 2 patches
Indentation   +2676 added lines, -2676 removed lines patch added patch discarded remove patch
@@ -12,2683 +12,2683 @@
 block discarded – undo
12 12
 class Events_Admin_Page extends EE_Admin_Page_CPT
13 13
 {
14 14
 
15
-    /**
16
-     * This will hold the event object for event_details screen.
17
-     *
18
-     * @access protected
19
-     * @var EE_Event $_event
20
-     */
21
-    protected $_event;
22
-
23
-
24
-    /**
25
-     * This will hold the category object for category_details screen.
26
-     *
27
-     * @var stdClass $_category
28
-     */
29
-    protected $_category;
30
-
31
-
32
-    /**
33
-     * This will hold the event model instance
34
-     *
35
-     * @var EEM_Event $_event_model
36
-     */
37
-    protected $_event_model;
38
-
39
-
40
-    /**
41
-     * @var EE_Event
42
-     */
43
-    protected $_cpt_model_obj = false;
44
-
45
-
46
-    /**
47
-     * Initialize page props for this admin page group.
48
-     */
49
-    protected function _init_page_props()
50
-    {
51
-        $this->page_slug = EVENTS_PG_SLUG;
52
-        $this->page_label = EVENTS_LABEL;
53
-        $this->_admin_base_url = EVENTS_ADMIN_URL;
54
-        $this->_admin_base_path = EVENTS_ADMIN;
55
-        $this->_cpt_model_names = array(
56
-            'create_new' => 'EEM_Event',
57
-            'edit'       => 'EEM_Event',
58
-        );
59
-        $this->_cpt_edit_routes = array(
60
-            'espresso_events' => 'edit',
61
-        );
62
-        add_action(
63
-            'AHEE__EE_Admin_Page_CPT__set_model_object__after_set_object',
64
-            array($this, 'verify_event_edit'),
65
-            10,
66
-            2
67
-        );
68
-    }
69
-
70
-
71
-    /**
72
-     * Sets the ajax hooks used for this admin page group.
73
-     */
74
-    protected function _ajax_hooks()
75
-    {
76
-        add_action('wp_ajax_ee_save_timezone_setting', array($this, 'save_timezonestring_setting'));
77
-    }
78
-
79
-
80
-    /**
81
-     * Sets the page properties for this admin page group.
82
-     */
83
-    protected function _define_page_props()
84
-    {
85
-        $this->_admin_page_title = EVENTS_LABEL;
86
-        $this->_labels = array(
87
-            'buttons'      => array(
88
-                'add'             => esc_html__('Add New Event', 'event_espresso'),
89
-                'edit'            => esc_html__('Edit Event', 'event_espresso'),
90
-                'delete'          => esc_html__('Delete Event', 'event_espresso'),
91
-                'add_category'    => esc_html__('Add New Category', 'event_espresso'),
92
-                'edit_category'   => esc_html__('Edit Category', 'event_espresso'),
93
-                'delete_category' => esc_html__('Delete Category', 'event_espresso'),
94
-            ),
95
-            'editor_title' => array(
96
-                'espresso_events' => esc_html__('Enter event title here', 'event_espresso'),
97
-            ),
98
-            'publishbox'   => array(
99
-                'create_new'        => esc_html__('Save New Event', 'event_espresso'),
100
-                'edit'              => esc_html__('Update Event', 'event_espresso'),
101
-                'add_category'      => esc_html__('Save New Category', 'event_espresso'),
102
-                'edit_category'     => esc_html__('Update Category', 'event_espresso'),
103
-                'template_settings' => esc_html__('Update Settings', 'event_espresso'),
104
-            ),
105
-        );
106
-    }
107
-
108
-
109
-    /**
110
-     * Sets the page routes property for this admin page group.
111
-     */
112
-    protected function _set_page_routes()
113
-    {
114
-        // load formatter helper
115
-        // load field generator helper
116
-        // is there a evt_id in the request?
117
-        $evt_id = ! empty($this->_req_data['EVT_ID']) && ! is_array($this->_req_data['EVT_ID'])
118
-            ? $this->_req_data['EVT_ID']
119
-            : 0;
120
-        $evt_id = ! empty($this->_req_data['post']) ? $this->_req_data['post'] : $evt_id;
121
-        $this->_page_routes = array(
122
-            'default'                       => array(
123
-                'func'       => '_events_overview_list_table',
124
-                'capability' => 'ee_read_events',
125
-            ),
126
-            'create_new'                    => array(
127
-                'func'       => '_create_new_cpt_item',
128
-                'capability' => 'ee_edit_events',
129
-            ),
130
-            'edit'                          => array(
131
-                'func'       => '_edit_cpt_item',
132
-                'capability' => 'ee_edit_event',
133
-                'obj_id'     => $evt_id,
134
-            ),
135
-            'copy_event'                    => array(
136
-                'func'       => '_copy_events',
137
-                'capability' => 'ee_edit_event',
138
-                'obj_id'     => $evt_id,
139
-                'noheader'   => true,
140
-            ),
141
-            'trash_event'                   => array(
142
-                'func'       => '_trash_or_restore_event',
143
-                'args'       => array('event_status' => 'trash'),
144
-                'capability' => 'ee_delete_event',
145
-                'obj_id'     => $evt_id,
146
-                'noheader'   => true,
147
-            ),
148
-            'trash_events'                  => array(
149
-                'func'       => '_trash_or_restore_events',
150
-                'args'       => array('event_status' => 'trash'),
151
-                'capability' => 'ee_delete_events',
152
-                'noheader'   => true,
153
-            ),
154
-            'restore_event'                 => array(
155
-                'func'       => '_trash_or_restore_event',
156
-                'args'       => array('event_status' => 'draft'),
157
-                'capability' => 'ee_delete_event',
158
-                'obj_id'     => $evt_id,
159
-                'noheader'   => true,
160
-            ),
161
-            'restore_events'                => array(
162
-                'func'       => '_trash_or_restore_events',
163
-                'args'       => array('event_status' => 'draft'),
164
-                'capability' => 'ee_delete_events',
165
-                'noheader'   => true,
166
-            ),
167
-            'delete_event'                  => array(
168
-                'func'       => '_delete_event',
169
-                'capability' => 'ee_delete_event',
170
-                'obj_id'     => $evt_id,
171
-                'noheader'   => true,
172
-            ),
173
-            'delete_events'                 => array(
174
-                'func'       => '_delete_events',
175
-                'capability' => 'ee_delete_events',
176
-                'noheader'   => true,
177
-            ),
178
-            'view_report'                   => array(
179
-                'func'      => '_view_report',
180
-                'capablity' => 'ee_edit_events',
181
-            ),
182
-            'default_event_settings'        => array(
183
-                'func'       => '_default_event_settings',
184
-                'capability' => 'manage_options',
185
-            ),
186
-            'update_default_event_settings' => array(
187
-                'func'       => '_update_default_event_settings',
188
-                'capability' => 'manage_options',
189
-                'noheader'   => true,
190
-            ),
191
-            'template_settings'             => array(
192
-                'func'       => '_template_settings',
193
-                'capability' => 'manage_options',
194
-            ),
195
-            // event category tab related
196
-            'add_category'                  => array(
197
-                'func'       => '_category_details',
198
-                'capability' => 'ee_edit_event_category',
199
-                'args'       => array('add'),
200
-            ),
201
-            'edit_category'                 => array(
202
-                'func'       => '_category_details',
203
-                'capability' => 'ee_edit_event_category',
204
-                'args'       => array('edit'),
205
-            ),
206
-            'delete_categories'             => array(
207
-                'func'       => '_delete_categories',
208
-                'capability' => 'ee_delete_event_category',
209
-                'noheader'   => true,
210
-            ),
211
-            'delete_category'               => array(
212
-                'func'       => '_delete_categories',
213
-                'capability' => 'ee_delete_event_category',
214
-                'noheader'   => true,
215
-            ),
216
-            'insert_category'               => array(
217
-                'func'       => '_insert_or_update_category',
218
-                'args'       => array('new_category' => true),
219
-                'capability' => 'ee_edit_event_category',
220
-                'noheader'   => true,
221
-            ),
222
-            'update_category'               => array(
223
-                'func'       => '_insert_or_update_category',
224
-                'args'       => array('new_category' => false),
225
-                'capability' => 'ee_edit_event_category',
226
-                'noheader'   => true,
227
-            ),
228
-            'category_list'                 => array(
229
-                'func'       => '_category_list_table',
230
-                'capability' => 'ee_manage_event_categories',
231
-            ),
232
-        );
233
-    }
234
-
235
-
236
-    /**
237
-     * Set the _page_config property for this admin page group.
238
-     */
239
-    protected function _set_page_config()
240
-    {
241
-        $this->_page_config = array(
242
-            'default'                => array(
243
-                'nav'           => array(
244
-                    'label' => esc_html__('Overview', 'event_espresso'),
245
-                    'order' => 10,
246
-                ),
247
-                'list_table'    => 'Events_Admin_List_Table',
248
-                'help_tabs'     => array(
249
-                    'events_overview_help_tab'                       => array(
250
-                        'title'    => esc_html__('Events Overview', 'event_espresso'),
251
-                        'filename' => 'events_overview',
252
-                    ),
253
-                    'events_overview_table_column_headings_help_tab' => array(
254
-                        'title'    => esc_html__('Events Overview Table Column Headings', 'event_espresso'),
255
-                        'filename' => 'events_overview_table_column_headings',
256
-                    ),
257
-                    'events_overview_filters_help_tab'               => array(
258
-                        'title'    => esc_html__('Events Overview Filters', 'event_espresso'),
259
-                        'filename' => 'events_overview_filters',
260
-                    ),
261
-                    'events_overview_view_help_tab'                  => array(
262
-                        'title'    => esc_html__('Events Overview Views', 'event_espresso'),
263
-                        'filename' => 'events_overview_views',
264
-                    ),
265
-                    'events_overview_other_help_tab'                 => array(
266
-                        'title'    => esc_html__('Events Overview Other', 'event_espresso'),
267
-                        'filename' => 'events_overview_other',
268
-                    ),
269
-                ),
270
-                'help_tour'     => array(
271
-                    'Event_Overview_Help_Tour',
272
-                    // 'New_Features_Test_Help_Tour' for testing multiple help tour
273
-                ),
274
-                'qtips'         => array(
275
-                    'EE_Event_List_Table_Tips',
276
-                ),
277
-                'require_nonce' => false,
278
-            ),
279
-            'create_new'             => array(
280
-                'nav'           => array(
281
-                    'label'      => esc_html__('Add Event', 'event_espresso'),
282
-                    'order'      => 5,
283
-                    'persistent' => false,
284
-                ),
285
-                'metaboxes'     => array('_register_event_editor_meta_boxes'),
286
-                'help_tabs'     => array(
287
-                    'event_editor_help_tab'                            => array(
288
-                        'title'    => esc_html__('Event Editor', 'event_espresso'),
289
-                        'filename' => 'event_editor',
290
-                    ),
291
-                    'event_editor_title_richtexteditor_help_tab'       => array(
292
-                        'title'    => esc_html__('Event Title & Rich Text Editor', 'event_espresso'),
293
-                        'filename' => 'event_editor_title_richtexteditor',
294
-                    ),
295
-                    'event_editor_venue_details_help_tab'              => array(
296
-                        'title'    => esc_html__('Event Venue Details', 'event_espresso'),
297
-                        'filename' => 'event_editor_venue_details',
298
-                    ),
299
-                    'event_editor_event_datetimes_help_tab'            => array(
300
-                        'title'    => esc_html__('Event Datetimes', 'event_espresso'),
301
-                        'filename' => 'event_editor_event_datetimes',
302
-                    ),
303
-                    'event_editor_event_tickets_help_tab'              => array(
304
-                        'title'    => esc_html__('Event Tickets', 'event_espresso'),
305
-                        'filename' => 'event_editor_event_tickets',
306
-                    ),
307
-                    'event_editor_event_registration_options_help_tab' => array(
308
-                        'title'    => esc_html__('Event Registration Options', 'event_espresso'),
309
-                        'filename' => 'event_editor_event_registration_options',
310
-                    ),
311
-                    'event_editor_tags_categories_help_tab'            => array(
312
-                        'title'    => esc_html__('Event Tags & Categories', 'event_espresso'),
313
-                        'filename' => 'event_editor_tags_categories',
314
-                    ),
315
-                    'event_editor_questions_registrants_help_tab'      => array(
316
-                        'title'    => esc_html__('Questions for Registrants', 'event_espresso'),
317
-                        'filename' => 'event_editor_questions_registrants',
318
-                    ),
319
-                    'event_editor_save_new_event_help_tab'             => array(
320
-                        'title'    => esc_html__('Save New Event', 'event_espresso'),
321
-                        'filename' => 'event_editor_save_new_event',
322
-                    ),
323
-                    'event_editor_other_help_tab'                      => array(
324
-                        'title'    => esc_html__('Event Other', 'event_espresso'),
325
-                        'filename' => 'event_editor_other',
326
-                    ),
327
-                ),
328
-                'help_tour'     => array(
329
-                    'Event_Editor_Help_Tour',
330
-                ),
331
-                'qtips'         => array('EE_Event_Editor_Decaf_Tips'),
332
-                'require_nonce' => false,
333
-            ),
334
-            'edit'                   => array(
335
-                'nav'           => array(
336
-                    'label'      => esc_html__('Edit Event', 'event_espresso'),
337
-                    'order'      => 5,
338
-                    'persistent' => false,
339
-                    'url'        => isset($this->_req_data['post'])
340
-                        ? EE_Admin_Page::add_query_args_and_nonce(
341
-                            array('post' => $this->_req_data['post'], 'action' => 'edit'),
342
-                            $this->_current_page_view_url
343
-                        )
344
-                        : $this->_admin_base_url,
345
-                ),
346
-                'metaboxes'     => array('_register_event_editor_meta_boxes'),
347
-                'help_tabs'     => array(
348
-                    'event_editor_help_tab'                            => array(
349
-                        'title'    => esc_html__('Event Editor', 'event_espresso'),
350
-                        'filename' => 'event_editor',
351
-                    ),
352
-                    'event_editor_title_richtexteditor_help_tab'       => array(
353
-                        'title'    => esc_html__('Event Title & Rich Text Editor', 'event_espresso'),
354
-                        'filename' => 'event_editor_title_richtexteditor',
355
-                    ),
356
-                    'event_editor_venue_details_help_tab'              => array(
357
-                        'title'    => esc_html__('Event Venue Details', 'event_espresso'),
358
-                        'filename' => 'event_editor_venue_details',
359
-                    ),
360
-                    'event_editor_event_datetimes_help_tab'            => array(
361
-                        'title'    => esc_html__('Event Datetimes', 'event_espresso'),
362
-                        'filename' => 'event_editor_event_datetimes',
363
-                    ),
364
-                    'event_editor_event_tickets_help_tab'              => array(
365
-                        'title'    => esc_html__('Event Tickets', 'event_espresso'),
366
-                        'filename' => 'event_editor_event_tickets',
367
-                    ),
368
-                    'event_editor_event_registration_options_help_tab' => array(
369
-                        'title'    => esc_html__('Event Registration Options', 'event_espresso'),
370
-                        'filename' => 'event_editor_event_registration_options',
371
-                    ),
372
-                    'event_editor_tags_categories_help_tab'            => array(
373
-                        'title'    => esc_html__('Event Tags & Categories', 'event_espresso'),
374
-                        'filename' => 'event_editor_tags_categories',
375
-                    ),
376
-                    'event_editor_questions_registrants_help_tab'      => array(
377
-                        'title'    => esc_html__('Questions for Registrants', 'event_espresso'),
378
-                        'filename' => 'event_editor_questions_registrants',
379
-                    ),
380
-                    'event_editor_save_new_event_help_tab'             => array(
381
-                        'title'    => esc_html__('Save New Event', 'event_espresso'),
382
-                        'filename' => 'event_editor_save_new_event',
383
-                    ),
384
-                    'event_editor_other_help_tab'                      => array(
385
-                        'title'    => esc_html__('Event Other', 'event_espresso'),
386
-                        'filename' => 'event_editor_other',
387
-                    ),
388
-                ),
389
-                'qtips'         => array('EE_Event_Editor_Decaf_Tips'),
390
-                'require_nonce' => false,
391
-            ),
392
-            'default_event_settings' => array(
393
-                'nav'           => array(
394
-                    'label' => esc_html__('Default Settings', 'event_espresso'),
395
-                    'order' => 40,
396
-                ),
397
-                'metaboxes'     => array_merge($this->_default_espresso_metaboxes, array('_publish_post_box')),
398
-                'labels'        => array(
399
-                    'publishbox' => esc_html__('Update Settings', 'event_espresso'),
400
-                ),
401
-                'help_tabs'     => array(
402
-                    'default_settings_help_tab'        => array(
403
-                        'title'    => esc_html__('Default Event Settings', 'event_espresso'),
404
-                        'filename' => 'events_default_settings',
405
-                    ),
406
-                    'default_settings_status_help_tab' => array(
407
-                        'title'    => esc_html__('Default Registration Status', 'event_espresso'),
408
-                        'filename' => 'events_default_settings_status',
409
-                    ),
410
-                    'default_maximum_tickets_help_tab' => array(
411
-                        'title'    => esc_html__('Default Maximum Tickets Per Order', 'event_espresso'),
412
-                        'filename' => 'events_default_settings_max_tickets',
413
-                    ),
414
-                ),
415
-                'help_tour'     => array('Event_Default_Settings_Help_Tour'),
416
-                'require_nonce' => false,
417
-            ),
418
-            // template settings
419
-            'template_settings'      => array(
420
-                'nav'           => array(
421
-                    'label' => esc_html__('Templates', 'event_espresso'),
422
-                    'order' => 30,
423
-                ),
424
-                'metaboxes'     => $this->_default_espresso_metaboxes,
425
-                'help_tabs'     => array(
426
-                    'general_settings_templates_help_tab' => array(
427
-                        'title'    => esc_html__('Templates', 'event_espresso'),
428
-                        'filename' => 'general_settings_templates',
429
-                    ),
430
-                ),
431
-                'help_tour'     => array('Templates_Help_Tour'),
432
-                'require_nonce' => false,
433
-            ),
434
-            // event category stuff
435
-            'add_category'           => array(
436
-                'nav'           => array(
437
-                    'label'      => esc_html__('Add Category', 'event_espresso'),
438
-                    'order'      => 15,
439
-                    'persistent' => false,
440
-                ),
441
-                'help_tabs'     => array(
442
-                    'add_category_help_tab' => array(
443
-                        'title'    => esc_html__('Add New Event Category', 'event_espresso'),
444
-                        'filename' => 'events_add_category',
445
-                    ),
446
-                ),
447
-                'help_tour'     => array('Event_Add_Category_Help_Tour'),
448
-                'metaboxes'     => array('_publish_post_box'),
449
-                'require_nonce' => false,
450
-            ),
451
-            'edit_category'          => array(
452
-                'nav'           => array(
453
-                    'label'      => esc_html__('Edit Category', 'event_espresso'),
454
-                    'order'      => 15,
455
-                    'persistent' => false,
456
-                    'url'        => isset($this->_req_data['EVT_CAT_ID'])
457
-                        ? add_query_arg(
458
-                            array('EVT_CAT_ID' => $this->_req_data['EVT_CAT_ID']),
459
-                            $this->_current_page_view_url
460
-                        )
461
-                        : $this->_admin_base_url,
462
-                ),
463
-                'help_tabs'     => array(
464
-                    'edit_category_help_tab' => array(
465
-                        'title'    => esc_html__('Edit Event Category', 'event_espresso'),
466
-                        'filename' => 'events_edit_category',
467
-                    ),
468
-                ),
469
-                /*'help_tour' => array('Event_Edit_Category_Help_Tour'),*/
470
-                'metaboxes'     => array('_publish_post_box'),
471
-                'require_nonce' => false,
472
-            ),
473
-            'category_list'          => array(
474
-                'nav'           => array(
475
-                    'label' => esc_html__('Categories', 'event_espresso'),
476
-                    'order' => 20,
477
-                ),
478
-                'list_table'    => 'Event_Categories_Admin_List_Table',
479
-                'help_tabs'     => array(
480
-                    'events_categories_help_tab'                       => array(
481
-                        'title'    => esc_html__('Event Categories', 'event_espresso'),
482
-                        'filename' => 'events_categories',
483
-                    ),
484
-                    'events_categories_table_column_headings_help_tab' => array(
485
-                        'title'    => esc_html__('Event Categories Table Column Headings', 'event_espresso'),
486
-                        'filename' => 'events_categories_table_column_headings',
487
-                    ),
488
-                    'events_categories_view_help_tab'                  => array(
489
-                        'title'    => esc_html__('Event Categories Views', 'event_espresso'),
490
-                        'filename' => 'events_categories_views',
491
-                    ),
492
-                    'events_categories_other_help_tab'                 => array(
493
-                        'title'    => esc_html__('Event Categories Other', 'event_espresso'),
494
-                        'filename' => 'events_categories_other',
495
-                    ),
496
-                ),
497
-                'help_tour'     => array(
498
-                    'Event_Categories_Help_Tour',
499
-                ),
500
-                'metaboxes'     => $this->_default_espresso_metaboxes,
501
-                'require_nonce' => false,
502
-            ),
503
-        );
504
-    }
505
-
506
-
507
-    /**
508
-     * Used to register any global screen options if necessary for every route in this admin page group.
509
-     */
510
-    protected function _add_screen_options()
511
-    {
512
-    }
513
-
514
-
515
-    /**
516
-     * Implementing the screen options for the 'default' route.
517
-     */
518
-    protected function _add_screen_options_default()
519
-    {
520
-        $this->_per_page_screen_option();
521
-    }
522
-
523
-
524
-    /**
525
-     * Implementing screen options for the category list route.
526
-     */
527
-    protected function _add_screen_options_category_list()
528
-    {
529
-        $page_title = $this->_admin_page_title;
530
-        $this->_admin_page_title = esc_html__('Categories', 'event_espresso');
531
-        $this->_per_page_screen_option();
532
-        $this->_admin_page_title = $page_title;
533
-    }
534
-
535
-
536
-    /**
537
-     * Used to register any global feature pointers for the admin page group.
538
-     */
539
-    protected function _add_feature_pointers()
540
-    {
541
-    }
542
-
543
-
544
-    /**
545
-     * Registers and enqueues any global scripts and styles for the entire admin page group.
546
-     */
547
-    public function load_scripts_styles()
548
-    {
549
-        wp_register_style(
550
-            'events-admin-css',
551
-            EVENTS_ASSETS_URL . 'events-admin-page.css',
552
-            array(),
553
-            EVENT_ESPRESSO_VERSION
554
-        );
555
-        wp_register_style('ee-cat-admin', EVENTS_ASSETS_URL . 'ee-cat-admin.css', array(), EVENT_ESPRESSO_VERSION);
556
-        wp_enqueue_style('events-admin-css');
557
-        wp_enqueue_style('ee-cat-admin');
558
-        // todo note: we also need to load_scripts_styles per view (i.e. default/view_report/event_details
559
-        // registers for all views
560
-        // scripts
561
-        wp_register_script(
562
-            'event_editor_js',
563
-            EVENTS_ASSETS_URL . 'event_editor.js',
564
-            array('ee_admin_js', 'jquery-ui-slider', 'jquery-ui-timepicker-addon'),
565
-            EVENT_ESPRESSO_VERSION,
566
-            true
567
-        );
568
-        add_action(
569
-            'admin_footer',
570
-            function () {
571
-                $eventId = isset($_REQUEST['post']) ? absint($_REQUEST['post']) : 0;
572
-                if ($eventId) {
573
-                    echo '
15
+	/**
16
+	 * This will hold the event object for event_details screen.
17
+	 *
18
+	 * @access protected
19
+	 * @var EE_Event $_event
20
+	 */
21
+	protected $_event;
22
+
23
+
24
+	/**
25
+	 * This will hold the category object for category_details screen.
26
+	 *
27
+	 * @var stdClass $_category
28
+	 */
29
+	protected $_category;
30
+
31
+
32
+	/**
33
+	 * This will hold the event model instance
34
+	 *
35
+	 * @var EEM_Event $_event_model
36
+	 */
37
+	protected $_event_model;
38
+
39
+
40
+	/**
41
+	 * @var EE_Event
42
+	 */
43
+	protected $_cpt_model_obj = false;
44
+
45
+
46
+	/**
47
+	 * Initialize page props for this admin page group.
48
+	 */
49
+	protected function _init_page_props()
50
+	{
51
+		$this->page_slug = EVENTS_PG_SLUG;
52
+		$this->page_label = EVENTS_LABEL;
53
+		$this->_admin_base_url = EVENTS_ADMIN_URL;
54
+		$this->_admin_base_path = EVENTS_ADMIN;
55
+		$this->_cpt_model_names = array(
56
+			'create_new' => 'EEM_Event',
57
+			'edit'       => 'EEM_Event',
58
+		);
59
+		$this->_cpt_edit_routes = array(
60
+			'espresso_events' => 'edit',
61
+		);
62
+		add_action(
63
+			'AHEE__EE_Admin_Page_CPT__set_model_object__after_set_object',
64
+			array($this, 'verify_event_edit'),
65
+			10,
66
+			2
67
+		);
68
+	}
69
+
70
+
71
+	/**
72
+	 * Sets the ajax hooks used for this admin page group.
73
+	 */
74
+	protected function _ajax_hooks()
75
+	{
76
+		add_action('wp_ajax_ee_save_timezone_setting', array($this, 'save_timezonestring_setting'));
77
+	}
78
+
79
+
80
+	/**
81
+	 * Sets the page properties for this admin page group.
82
+	 */
83
+	protected function _define_page_props()
84
+	{
85
+		$this->_admin_page_title = EVENTS_LABEL;
86
+		$this->_labels = array(
87
+			'buttons'      => array(
88
+				'add'             => esc_html__('Add New Event', 'event_espresso'),
89
+				'edit'            => esc_html__('Edit Event', 'event_espresso'),
90
+				'delete'          => esc_html__('Delete Event', 'event_espresso'),
91
+				'add_category'    => esc_html__('Add New Category', 'event_espresso'),
92
+				'edit_category'   => esc_html__('Edit Category', 'event_espresso'),
93
+				'delete_category' => esc_html__('Delete Category', 'event_espresso'),
94
+			),
95
+			'editor_title' => array(
96
+				'espresso_events' => esc_html__('Enter event title here', 'event_espresso'),
97
+			),
98
+			'publishbox'   => array(
99
+				'create_new'        => esc_html__('Save New Event', 'event_espresso'),
100
+				'edit'              => esc_html__('Update Event', 'event_espresso'),
101
+				'add_category'      => esc_html__('Save New Category', 'event_espresso'),
102
+				'edit_category'     => esc_html__('Update Category', 'event_espresso'),
103
+				'template_settings' => esc_html__('Update Settings', 'event_espresso'),
104
+			),
105
+		);
106
+	}
107
+
108
+
109
+	/**
110
+	 * Sets the page routes property for this admin page group.
111
+	 */
112
+	protected function _set_page_routes()
113
+	{
114
+		// load formatter helper
115
+		// load field generator helper
116
+		// is there a evt_id in the request?
117
+		$evt_id = ! empty($this->_req_data['EVT_ID']) && ! is_array($this->_req_data['EVT_ID'])
118
+			? $this->_req_data['EVT_ID']
119
+			: 0;
120
+		$evt_id = ! empty($this->_req_data['post']) ? $this->_req_data['post'] : $evt_id;
121
+		$this->_page_routes = array(
122
+			'default'                       => array(
123
+				'func'       => '_events_overview_list_table',
124
+				'capability' => 'ee_read_events',
125
+			),
126
+			'create_new'                    => array(
127
+				'func'       => '_create_new_cpt_item',
128
+				'capability' => 'ee_edit_events',
129
+			),
130
+			'edit'                          => array(
131
+				'func'       => '_edit_cpt_item',
132
+				'capability' => 'ee_edit_event',
133
+				'obj_id'     => $evt_id,
134
+			),
135
+			'copy_event'                    => array(
136
+				'func'       => '_copy_events',
137
+				'capability' => 'ee_edit_event',
138
+				'obj_id'     => $evt_id,
139
+				'noheader'   => true,
140
+			),
141
+			'trash_event'                   => array(
142
+				'func'       => '_trash_or_restore_event',
143
+				'args'       => array('event_status' => 'trash'),
144
+				'capability' => 'ee_delete_event',
145
+				'obj_id'     => $evt_id,
146
+				'noheader'   => true,
147
+			),
148
+			'trash_events'                  => array(
149
+				'func'       => '_trash_or_restore_events',
150
+				'args'       => array('event_status' => 'trash'),
151
+				'capability' => 'ee_delete_events',
152
+				'noheader'   => true,
153
+			),
154
+			'restore_event'                 => array(
155
+				'func'       => '_trash_or_restore_event',
156
+				'args'       => array('event_status' => 'draft'),
157
+				'capability' => 'ee_delete_event',
158
+				'obj_id'     => $evt_id,
159
+				'noheader'   => true,
160
+			),
161
+			'restore_events'                => array(
162
+				'func'       => '_trash_or_restore_events',
163
+				'args'       => array('event_status' => 'draft'),
164
+				'capability' => 'ee_delete_events',
165
+				'noheader'   => true,
166
+			),
167
+			'delete_event'                  => array(
168
+				'func'       => '_delete_event',
169
+				'capability' => 'ee_delete_event',
170
+				'obj_id'     => $evt_id,
171
+				'noheader'   => true,
172
+			),
173
+			'delete_events'                 => array(
174
+				'func'       => '_delete_events',
175
+				'capability' => 'ee_delete_events',
176
+				'noheader'   => true,
177
+			),
178
+			'view_report'                   => array(
179
+				'func'      => '_view_report',
180
+				'capablity' => 'ee_edit_events',
181
+			),
182
+			'default_event_settings'        => array(
183
+				'func'       => '_default_event_settings',
184
+				'capability' => 'manage_options',
185
+			),
186
+			'update_default_event_settings' => array(
187
+				'func'       => '_update_default_event_settings',
188
+				'capability' => 'manage_options',
189
+				'noheader'   => true,
190
+			),
191
+			'template_settings'             => array(
192
+				'func'       => '_template_settings',
193
+				'capability' => 'manage_options',
194
+			),
195
+			// event category tab related
196
+			'add_category'                  => array(
197
+				'func'       => '_category_details',
198
+				'capability' => 'ee_edit_event_category',
199
+				'args'       => array('add'),
200
+			),
201
+			'edit_category'                 => array(
202
+				'func'       => '_category_details',
203
+				'capability' => 'ee_edit_event_category',
204
+				'args'       => array('edit'),
205
+			),
206
+			'delete_categories'             => array(
207
+				'func'       => '_delete_categories',
208
+				'capability' => 'ee_delete_event_category',
209
+				'noheader'   => true,
210
+			),
211
+			'delete_category'               => array(
212
+				'func'       => '_delete_categories',
213
+				'capability' => 'ee_delete_event_category',
214
+				'noheader'   => true,
215
+			),
216
+			'insert_category'               => array(
217
+				'func'       => '_insert_or_update_category',
218
+				'args'       => array('new_category' => true),
219
+				'capability' => 'ee_edit_event_category',
220
+				'noheader'   => true,
221
+			),
222
+			'update_category'               => array(
223
+				'func'       => '_insert_or_update_category',
224
+				'args'       => array('new_category' => false),
225
+				'capability' => 'ee_edit_event_category',
226
+				'noheader'   => true,
227
+			),
228
+			'category_list'                 => array(
229
+				'func'       => '_category_list_table',
230
+				'capability' => 'ee_manage_event_categories',
231
+			),
232
+		);
233
+	}
234
+
235
+
236
+	/**
237
+	 * Set the _page_config property for this admin page group.
238
+	 */
239
+	protected function _set_page_config()
240
+	{
241
+		$this->_page_config = array(
242
+			'default'                => array(
243
+				'nav'           => array(
244
+					'label' => esc_html__('Overview', 'event_espresso'),
245
+					'order' => 10,
246
+				),
247
+				'list_table'    => 'Events_Admin_List_Table',
248
+				'help_tabs'     => array(
249
+					'events_overview_help_tab'                       => array(
250
+						'title'    => esc_html__('Events Overview', 'event_espresso'),
251
+						'filename' => 'events_overview',
252
+					),
253
+					'events_overview_table_column_headings_help_tab' => array(
254
+						'title'    => esc_html__('Events Overview Table Column Headings', 'event_espresso'),
255
+						'filename' => 'events_overview_table_column_headings',
256
+					),
257
+					'events_overview_filters_help_tab'               => array(
258
+						'title'    => esc_html__('Events Overview Filters', 'event_espresso'),
259
+						'filename' => 'events_overview_filters',
260
+					),
261
+					'events_overview_view_help_tab'                  => array(
262
+						'title'    => esc_html__('Events Overview Views', 'event_espresso'),
263
+						'filename' => 'events_overview_views',
264
+					),
265
+					'events_overview_other_help_tab'                 => array(
266
+						'title'    => esc_html__('Events Overview Other', 'event_espresso'),
267
+						'filename' => 'events_overview_other',
268
+					),
269
+				),
270
+				'help_tour'     => array(
271
+					'Event_Overview_Help_Tour',
272
+					// 'New_Features_Test_Help_Tour' for testing multiple help tour
273
+				),
274
+				'qtips'         => array(
275
+					'EE_Event_List_Table_Tips',
276
+				),
277
+				'require_nonce' => false,
278
+			),
279
+			'create_new'             => array(
280
+				'nav'           => array(
281
+					'label'      => esc_html__('Add Event', 'event_espresso'),
282
+					'order'      => 5,
283
+					'persistent' => false,
284
+				),
285
+				'metaboxes'     => array('_register_event_editor_meta_boxes'),
286
+				'help_tabs'     => array(
287
+					'event_editor_help_tab'                            => array(
288
+						'title'    => esc_html__('Event Editor', 'event_espresso'),
289
+						'filename' => 'event_editor',
290
+					),
291
+					'event_editor_title_richtexteditor_help_tab'       => array(
292
+						'title'    => esc_html__('Event Title & Rich Text Editor', 'event_espresso'),
293
+						'filename' => 'event_editor_title_richtexteditor',
294
+					),
295
+					'event_editor_venue_details_help_tab'              => array(
296
+						'title'    => esc_html__('Event Venue Details', 'event_espresso'),
297
+						'filename' => 'event_editor_venue_details',
298
+					),
299
+					'event_editor_event_datetimes_help_tab'            => array(
300
+						'title'    => esc_html__('Event Datetimes', 'event_espresso'),
301
+						'filename' => 'event_editor_event_datetimes',
302
+					),
303
+					'event_editor_event_tickets_help_tab'              => array(
304
+						'title'    => esc_html__('Event Tickets', 'event_espresso'),
305
+						'filename' => 'event_editor_event_tickets',
306
+					),
307
+					'event_editor_event_registration_options_help_tab' => array(
308
+						'title'    => esc_html__('Event Registration Options', 'event_espresso'),
309
+						'filename' => 'event_editor_event_registration_options',
310
+					),
311
+					'event_editor_tags_categories_help_tab'            => array(
312
+						'title'    => esc_html__('Event Tags & Categories', 'event_espresso'),
313
+						'filename' => 'event_editor_tags_categories',
314
+					),
315
+					'event_editor_questions_registrants_help_tab'      => array(
316
+						'title'    => esc_html__('Questions for Registrants', 'event_espresso'),
317
+						'filename' => 'event_editor_questions_registrants',
318
+					),
319
+					'event_editor_save_new_event_help_tab'             => array(
320
+						'title'    => esc_html__('Save New Event', 'event_espresso'),
321
+						'filename' => 'event_editor_save_new_event',
322
+					),
323
+					'event_editor_other_help_tab'                      => array(
324
+						'title'    => esc_html__('Event Other', 'event_espresso'),
325
+						'filename' => 'event_editor_other',
326
+					),
327
+				),
328
+				'help_tour'     => array(
329
+					'Event_Editor_Help_Tour',
330
+				),
331
+				'qtips'         => array('EE_Event_Editor_Decaf_Tips'),
332
+				'require_nonce' => false,
333
+			),
334
+			'edit'                   => array(
335
+				'nav'           => array(
336
+					'label'      => esc_html__('Edit Event', 'event_espresso'),
337
+					'order'      => 5,
338
+					'persistent' => false,
339
+					'url'        => isset($this->_req_data['post'])
340
+						? EE_Admin_Page::add_query_args_and_nonce(
341
+							array('post' => $this->_req_data['post'], 'action' => 'edit'),
342
+							$this->_current_page_view_url
343
+						)
344
+						: $this->_admin_base_url,
345
+				),
346
+				'metaboxes'     => array('_register_event_editor_meta_boxes'),
347
+				'help_tabs'     => array(
348
+					'event_editor_help_tab'                            => array(
349
+						'title'    => esc_html__('Event Editor', 'event_espresso'),
350
+						'filename' => 'event_editor',
351
+					),
352
+					'event_editor_title_richtexteditor_help_tab'       => array(
353
+						'title'    => esc_html__('Event Title & Rich Text Editor', 'event_espresso'),
354
+						'filename' => 'event_editor_title_richtexteditor',
355
+					),
356
+					'event_editor_venue_details_help_tab'              => array(
357
+						'title'    => esc_html__('Event Venue Details', 'event_espresso'),
358
+						'filename' => 'event_editor_venue_details',
359
+					),
360
+					'event_editor_event_datetimes_help_tab'            => array(
361
+						'title'    => esc_html__('Event Datetimes', 'event_espresso'),
362
+						'filename' => 'event_editor_event_datetimes',
363
+					),
364
+					'event_editor_event_tickets_help_tab'              => array(
365
+						'title'    => esc_html__('Event Tickets', 'event_espresso'),
366
+						'filename' => 'event_editor_event_tickets',
367
+					),
368
+					'event_editor_event_registration_options_help_tab' => array(
369
+						'title'    => esc_html__('Event Registration Options', 'event_espresso'),
370
+						'filename' => 'event_editor_event_registration_options',
371
+					),
372
+					'event_editor_tags_categories_help_tab'            => array(
373
+						'title'    => esc_html__('Event Tags & Categories', 'event_espresso'),
374
+						'filename' => 'event_editor_tags_categories',
375
+					),
376
+					'event_editor_questions_registrants_help_tab'      => array(
377
+						'title'    => esc_html__('Questions for Registrants', 'event_espresso'),
378
+						'filename' => 'event_editor_questions_registrants',
379
+					),
380
+					'event_editor_save_new_event_help_tab'             => array(
381
+						'title'    => esc_html__('Save New Event', 'event_espresso'),
382
+						'filename' => 'event_editor_save_new_event',
383
+					),
384
+					'event_editor_other_help_tab'                      => array(
385
+						'title'    => esc_html__('Event Other', 'event_espresso'),
386
+						'filename' => 'event_editor_other',
387
+					),
388
+				),
389
+				'qtips'         => array('EE_Event_Editor_Decaf_Tips'),
390
+				'require_nonce' => false,
391
+			),
392
+			'default_event_settings' => array(
393
+				'nav'           => array(
394
+					'label' => esc_html__('Default Settings', 'event_espresso'),
395
+					'order' => 40,
396
+				),
397
+				'metaboxes'     => array_merge($this->_default_espresso_metaboxes, array('_publish_post_box')),
398
+				'labels'        => array(
399
+					'publishbox' => esc_html__('Update Settings', 'event_espresso'),
400
+				),
401
+				'help_tabs'     => array(
402
+					'default_settings_help_tab'        => array(
403
+						'title'    => esc_html__('Default Event Settings', 'event_espresso'),
404
+						'filename' => 'events_default_settings',
405
+					),
406
+					'default_settings_status_help_tab' => array(
407
+						'title'    => esc_html__('Default Registration Status', 'event_espresso'),
408
+						'filename' => 'events_default_settings_status',
409
+					),
410
+					'default_maximum_tickets_help_tab' => array(
411
+						'title'    => esc_html__('Default Maximum Tickets Per Order', 'event_espresso'),
412
+						'filename' => 'events_default_settings_max_tickets',
413
+					),
414
+				),
415
+				'help_tour'     => array('Event_Default_Settings_Help_Tour'),
416
+				'require_nonce' => false,
417
+			),
418
+			// template settings
419
+			'template_settings'      => array(
420
+				'nav'           => array(
421
+					'label' => esc_html__('Templates', 'event_espresso'),
422
+					'order' => 30,
423
+				),
424
+				'metaboxes'     => $this->_default_espresso_metaboxes,
425
+				'help_tabs'     => array(
426
+					'general_settings_templates_help_tab' => array(
427
+						'title'    => esc_html__('Templates', 'event_espresso'),
428
+						'filename' => 'general_settings_templates',
429
+					),
430
+				),
431
+				'help_tour'     => array('Templates_Help_Tour'),
432
+				'require_nonce' => false,
433
+			),
434
+			// event category stuff
435
+			'add_category'           => array(
436
+				'nav'           => array(
437
+					'label'      => esc_html__('Add Category', 'event_espresso'),
438
+					'order'      => 15,
439
+					'persistent' => false,
440
+				),
441
+				'help_tabs'     => array(
442
+					'add_category_help_tab' => array(
443
+						'title'    => esc_html__('Add New Event Category', 'event_espresso'),
444
+						'filename' => 'events_add_category',
445
+					),
446
+				),
447
+				'help_tour'     => array('Event_Add_Category_Help_Tour'),
448
+				'metaboxes'     => array('_publish_post_box'),
449
+				'require_nonce' => false,
450
+			),
451
+			'edit_category'          => array(
452
+				'nav'           => array(
453
+					'label'      => esc_html__('Edit Category', 'event_espresso'),
454
+					'order'      => 15,
455
+					'persistent' => false,
456
+					'url'        => isset($this->_req_data['EVT_CAT_ID'])
457
+						? add_query_arg(
458
+							array('EVT_CAT_ID' => $this->_req_data['EVT_CAT_ID']),
459
+							$this->_current_page_view_url
460
+						)
461
+						: $this->_admin_base_url,
462
+				),
463
+				'help_tabs'     => array(
464
+					'edit_category_help_tab' => array(
465
+						'title'    => esc_html__('Edit Event Category', 'event_espresso'),
466
+						'filename' => 'events_edit_category',
467
+					),
468
+				),
469
+				/*'help_tour' => array('Event_Edit_Category_Help_Tour'),*/
470
+				'metaboxes'     => array('_publish_post_box'),
471
+				'require_nonce' => false,
472
+			),
473
+			'category_list'          => array(
474
+				'nav'           => array(
475
+					'label' => esc_html__('Categories', 'event_espresso'),
476
+					'order' => 20,
477
+				),
478
+				'list_table'    => 'Event_Categories_Admin_List_Table',
479
+				'help_tabs'     => array(
480
+					'events_categories_help_tab'                       => array(
481
+						'title'    => esc_html__('Event Categories', 'event_espresso'),
482
+						'filename' => 'events_categories',
483
+					),
484
+					'events_categories_table_column_headings_help_tab' => array(
485
+						'title'    => esc_html__('Event Categories Table Column Headings', 'event_espresso'),
486
+						'filename' => 'events_categories_table_column_headings',
487
+					),
488
+					'events_categories_view_help_tab'                  => array(
489
+						'title'    => esc_html__('Event Categories Views', 'event_espresso'),
490
+						'filename' => 'events_categories_views',
491
+					),
492
+					'events_categories_other_help_tab'                 => array(
493
+						'title'    => esc_html__('Event Categories Other', 'event_espresso'),
494
+						'filename' => 'events_categories_other',
495
+					),
496
+				),
497
+				'help_tour'     => array(
498
+					'Event_Categories_Help_Tour',
499
+				),
500
+				'metaboxes'     => $this->_default_espresso_metaboxes,
501
+				'require_nonce' => false,
502
+			),
503
+		);
504
+	}
505
+
506
+
507
+	/**
508
+	 * Used to register any global screen options if necessary for every route in this admin page group.
509
+	 */
510
+	protected function _add_screen_options()
511
+	{
512
+	}
513
+
514
+
515
+	/**
516
+	 * Implementing the screen options for the 'default' route.
517
+	 */
518
+	protected function _add_screen_options_default()
519
+	{
520
+		$this->_per_page_screen_option();
521
+	}
522
+
523
+
524
+	/**
525
+	 * Implementing screen options for the category list route.
526
+	 */
527
+	protected function _add_screen_options_category_list()
528
+	{
529
+		$page_title = $this->_admin_page_title;
530
+		$this->_admin_page_title = esc_html__('Categories', 'event_espresso');
531
+		$this->_per_page_screen_option();
532
+		$this->_admin_page_title = $page_title;
533
+	}
534
+
535
+
536
+	/**
537
+	 * Used to register any global feature pointers for the admin page group.
538
+	 */
539
+	protected function _add_feature_pointers()
540
+	{
541
+	}
542
+
543
+
544
+	/**
545
+	 * Registers and enqueues any global scripts and styles for the entire admin page group.
546
+	 */
547
+	public function load_scripts_styles()
548
+	{
549
+		wp_register_style(
550
+			'events-admin-css',
551
+			EVENTS_ASSETS_URL . 'events-admin-page.css',
552
+			array(),
553
+			EVENT_ESPRESSO_VERSION
554
+		);
555
+		wp_register_style('ee-cat-admin', EVENTS_ASSETS_URL . 'ee-cat-admin.css', array(), EVENT_ESPRESSO_VERSION);
556
+		wp_enqueue_style('events-admin-css');
557
+		wp_enqueue_style('ee-cat-admin');
558
+		// todo note: we also need to load_scripts_styles per view (i.e. default/view_report/event_details
559
+		// registers for all views
560
+		// scripts
561
+		wp_register_script(
562
+			'event_editor_js',
563
+			EVENTS_ASSETS_URL . 'event_editor.js',
564
+			array('ee_admin_js', 'jquery-ui-slider', 'jquery-ui-timepicker-addon'),
565
+			EVENT_ESPRESSO_VERSION,
566
+			true
567
+		);
568
+		add_action(
569
+			'admin_footer',
570
+			function () {
571
+				$eventId = isset($_REQUEST['post']) ? absint($_REQUEST['post']) : 0;
572
+				if ($eventId) {
573
+					echo '
574 574
         <script type="text/javascript">
575 575
             /* <![CDATA[ */ var eeEditorEventId = ' . $eventId . ' /* ]]> */
576 576
         </script>';
577
-                }
578
-            }
579
-        );
580
-    }
581
-
582
-
583
-    /**
584
-     * Enqueuing scripts and styles specific to this view
585
-     */
586
-    public function load_scripts_styles_create_new()
587
-    {
588
-        $this->load_scripts_styles_edit();
589
-    }
590
-
591
-
592
-    /**
593
-     * Enqueuing scripts and styles specific to this view
594
-     */
595
-    public function load_scripts_styles_edit()
596
-    {
597
-        // styles
598
-        wp_enqueue_style('espresso-ui-theme');
599
-        wp_register_style(
600
-            'event-editor-css',
601
-            EVENTS_ASSETS_URL . 'event-editor.css',
602
-            array('ee-admin-css'),
603
-            EVENT_ESPRESSO_VERSION
604
-        );
605
-        wp_enqueue_style('event-editor-css');
606
-        // scripts
607
-        wp_register_script(
608
-            'event-datetime-metabox',
609
-            EVENTS_ASSETS_URL . 'event-datetime-metabox.js',
610
-            array('event_editor_js', 'ee-datepicker'),
611
-            EVENT_ESPRESSO_VERSION
612
-        );
613
-        wp_enqueue_script('event-datetime-metabox');
614
-    }
615
-
616
-
617
-    /**
618
-     * Populating the _views property for the category list table view.
619
-     */
620
-    protected function _set_list_table_views_category_list()
621
-    {
622
-        $this->_views = array(
623
-            'all' => array(
624
-                'slug'        => 'all',
625
-                'label'       => esc_html__('All', 'event_espresso'),
626
-                'count'       => 0,
627
-                'bulk_action' => array(
628
-                    'delete_categories' => esc_html__('Delete Permanently', 'event_espresso'),
629
-                ),
630
-            ),
631
-        );
632
-    }
633
-
634
-
635
-    /**
636
-     * For adding anything that fires on the admin_init hook for any route within this admin page group.
637
-     */
638
-    public function admin_init()
639
-    {
640
-        EE_Registry::$i18n_js_strings['image_confirm'] = esc_html__(
641
-            'Do you really want to delete this image? Please remember to update your event to complete the removal.',
642
-            'event_espresso'
643
-        );
644
-    }
645
-
646
-
647
-    /**
648
-     * For adding anything that should be triggered on the admin_notices hook for any route within this admin page
649
-     * group.
650
-     */
651
-    public function admin_notices()
652
-    {
653
-    }
654
-
655
-
656
-    /**
657
-     * For adding anything that should be triggered on the `admin_print_footer_scripts` hook for any route within
658
-     * this admin page group.
659
-     */
660
-    public function admin_footer_scripts()
661
-    {
662
-    }
663
-
664
-
665
-    /**
666
-     * Call this function to verify if an event is public and has tickets for sale.  If it does, then we need to show a
667
-     * warning (via EE_Error::add_error());
668
-     *
669
-     * @param  EE_Event $event Event object
670
-     * @param string    $req_type
671
-     * @return void
672
-     * @throws EE_Error
673
-     * @access public
674
-     */
675
-    public function verify_event_edit($event = null, $req_type = '')
676
-    {
677
-        // don't need to do this when processing
678
-        if (! empty($req_type)) {
679
-            return;
680
-        }
681
-        // no event?
682
-        if (empty($event)) {
683
-            // set event
684
-            $event = $this->_cpt_model_obj;
685
-        }
686
-        // STILL no event?
687
-        if (! $event instanceof EE_Event) {
688
-            return;
689
-        }
690
-        $orig_status = $event->status();
691
-        // first check if event is active.
692
-        if ($orig_status === EEM_Event::cancelled
693
-            || $orig_status === EEM_Event::postponed
694
-            || $event->is_expired()
695
-            || $event->is_inactive()
696
-        ) {
697
-            return;
698
-        }
699
-        // made it here so it IS active... next check that any of the tickets are sold.
700
-        if ($event->is_sold_out(true)) {
701
-            if ($orig_status !== EEM_Event::sold_out && $event->status() !== $orig_status) {
702
-                EE_Error::add_attention(
703
-                    sprintf(
704
-                        esc_html__(
705
-                            'Please note that the Event Status has automatically been changed to %s because there are no more spaces available for this event.  However, this change is not permanent until you update the event.  You can change the status back to something else before updating if you wish.',
706
-                            'event_espresso'
707
-                        ),
708
-                        EEH_Template::pretty_status(EEM_Event::sold_out, false, 'sentence')
709
-                    )
710
-                );
711
-            }
712
-            return;
713
-        } elseif ($orig_status === EEM_Event::sold_out) {
714
-            EE_Error::add_attention(
715
-                sprintf(
716
-                    esc_html__(
717
-                        'Please note that the Event Status has automatically been changed to %s because more spaces have become available for this event, most likely due to abandoned transactions freeing up reserved tickets.  However, this change is not permanent until you update the event. If you wish, you can change the status back to something else before updating.',
718
-                        'event_espresso'
719
-                    ),
720
-                    EEH_Template::pretty_status($event->status(), false, 'sentence')
721
-                )
722
-            );
723
-        }
724
-        // now we need to determine if the event has any tickets on sale.  If not then we dont' show the error
725
-        if (! $event->tickets_on_sale()) {
726
-            return;
727
-        }
728
-        // made it here so show warning
729
-        $this->_edit_event_warning();
730
-    }
731
-
732
-
733
-    /**
734
-     * This is the text used for when an event is being edited that is public and has tickets for sale.
735
-     * When needed, hook this into a EE_Error::add_error() notice.
736
-     *
737
-     * @access protected
738
-     * @return void
739
-     */
740
-    protected function _edit_event_warning()
741
-    {
742
-        // we don't want to add warnings during these requests
743
-        if (isset($this->_req_data['action']) && $this->_req_data['action'] === 'editpost') {
744
-            return;
745
-        }
746
-        EE_Error::add_attention(
747
-            sprintf(
748
-                esc_html__(
749
-                    'Your event is open for registration. Making changes may disrupt any transactions in progress. %sLearn more%s',
750
-                    'event_espresso'
751
-                ),
752
-                '<a class="espresso-help-tab-lnk">',
753
-                '</a>'
754
-            )
755
-        );
756
-    }
757
-
758
-
759
-    /**
760
-     * When a user is creating a new event, notify them if they haven't set their timezone.
761
-     * Otherwise, do the normal logic
762
-     *
763
-     * @return string
764
-     * @throws \EE_Error
765
-     */
766
-    protected function _create_new_cpt_item()
767
-    {
768
-        $has_timezone_string = get_option('timezone_string');
769
-        // only nag them about setting their timezone if it's their first event, and they haven't already done it
770
-        if (! $has_timezone_string && ! EEM_Event::instance()->exists(array())) {
771
-            EE_Error::add_attention(
772
-                sprintf(
773
-                    __(
774
-                        'Your website\'s timezone is currently set to a UTC offset. We recommend updating your timezone to a city or region near you before you create an event. Change your timezone now:%1$s%2$s%3$sChange Timezone%4$s',
775
-                        'event_espresso'
776
-                    ),
777
-                    '<br>',
778
-                    '<select id="timezone_string" name="timezone_string" aria-describedby="timezone-description">'
779
-                    . EEH_DTT_Helper::wp_timezone_choice('', EEH_DTT_Helper::get_user_locale())
780
-                    . '</select>',
781
-                    '<button class="button button-secondary timezone-submit">',
782
-                    '</button><span class="spinner"></span>'
783
-                ),
784
-                __FILE__,
785
-                __FUNCTION__,
786
-                __LINE__
787
-            );
788
-        }
789
-        return parent::_create_new_cpt_item();
790
-    }
791
-
792
-
793
-    /**
794
-     * Sets the _views property for the default route in this admin page group.
795
-     */
796
-    protected function _set_list_table_views_default()
797
-    {
798
-        $this->_views = array(
799
-            'all'   => array(
800
-                'slug'        => 'all',
801
-                'label'       => esc_html__('View All Events', 'event_espresso'),
802
-                'count'       => 0,
803
-                'bulk_action' => array(
804
-                    'trash_events' => esc_html__('Move to Trash', 'event_espresso'),
805
-                ),
806
-            ),
807
-            'draft' => array(
808
-                'slug'        => 'draft',
809
-                'label'       => esc_html__('Draft', 'event_espresso'),
810
-                'count'       => 0,
811
-                'bulk_action' => array(
812
-                    'trash_events' => esc_html__('Move to Trash', 'event_espresso'),
813
-                ),
814
-            ),
815
-        );
816
-        if (EE_Registry::instance()->CAP->current_user_can('ee_delete_events', 'espresso_events_trash_events')) {
817
-            $this->_views['trash'] = array(
818
-                'slug'        => 'trash',
819
-                'label'       => esc_html__('Trash', 'event_espresso'),
820
-                'count'       => 0,
821
-                'bulk_action' => array(
822
-                    'restore_events' => esc_html__('Restore From Trash', 'event_espresso'),
823
-                    'delete_events'  => esc_html__('Delete Permanently', 'event_espresso'),
824
-                ),
825
-            );
826
-        }
827
-    }
828
-
829
-
830
-    /**
831
-     * Provides the legend item array for the default list table view.
832
-     *
833
-     * @return array
834
-     */
835
-    protected function _event_legend_items()
836
-    {
837
-        $items = array(
838
-            'view_details'   => array(
839
-                'class' => 'dashicons dashicons-search',
840
-                'desc'  => esc_html__('View Event', 'event_espresso'),
841
-            ),
842
-            'edit_event'     => array(
843
-                'class' => 'ee-icon ee-icon-calendar-edit',
844
-                'desc'  => esc_html__('Edit Event Details', 'event_espresso'),
845
-            ),
846
-            'view_attendees' => array(
847
-                'class' => 'dashicons dashicons-groups',
848
-                'desc'  => esc_html__('View Registrations for Event', 'event_espresso'),
849
-            ),
850
-        );
851
-        $items = apply_filters('FHEE__Events_Admin_Page___event_legend_items__items', $items);
852
-        $statuses = array(
853
-            'sold_out_status'  => array(
854
-                'class' => 'ee-status-legend ee-status-legend-' . EE_Datetime::sold_out,
855
-                'desc'  => EEH_Template::pretty_status(EE_Datetime::sold_out, false, 'sentence'),
856
-            ),
857
-            'active_status'    => array(
858
-                'class' => 'ee-status-legend ee-status-legend-' . EE_Datetime::active,
859
-                'desc'  => EEH_Template::pretty_status(EE_Datetime::active, false, 'sentence'),
860
-            ),
861
-            'upcoming_status'  => array(
862
-                'class' => 'ee-status-legend ee-status-legend-' . EE_Datetime::upcoming,
863
-                'desc'  => EEH_Template::pretty_status(EE_Datetime::upcoming, false, 'sentence'),
864
-            ),
865
-            'postponed_status' => array(
866
-                'class' => 'ee-status-legend ee-status-legend-' . EE_Datetime::postponed,
867
-                'desc'  => EEH_Template::pretty_status(EE_Datetime::postponed, false, 'sentence'),
868
-            ),
869
-            'cancelled_status' => array(
870
-                'class' => 'ee-status-legend ee-status-legend-' . EE_Datetime::cancelled,
871
-                'desc'  => EEH_Template::pretty_status(EE_Datetime::cancelled, false, 'sentence'),
872
-            ),
873
-            'expired_status'   => array(
874
-                'class' => 'ee-status-legend ee-status-legend-' . EE_Datetime::expired,
875
-                'desc'  => EEH_Template::pretty_status(EE_Datetime::expired, false, 'sentence'),
876
-            ),
877
-            'inactive_status'  => array(
878
-                'class' => 'ee-status-legend ee-status-legend-' . EE_Datetime::inactive,
879
-                'desc'  => EEH_Template::pretty_status(EE_Datetime::inactive, false, 'sentence'),
880
-            ),
881
-        );
882
-        $statuses = apply_filters('FHEE__Events_Admin_Page__event_legend_items__statuses', $statuses);
883
-        return array_merge($items, $statuses);
884
-    }
885
-
886
-
887
-    /**
888
-     * @return EEM_Event
889
-     */
890
-    private function _event_model()
891
-    {
892
-        if (! $this->_event_model instanceof EEM_Event) {
893
-            $this->_event_model = EE_Registry::instance()->load_model('Event');
894
-        }
895
-        return $this->_event_model;
896
-    }
897
-
898
-
899
-    /**
900
-     * Adds extra buttons to the WP CPT permalink field row.
901
-     * Method is called from parent and is hooked into the wp 'get_sample_permalink_html' filter.
902
-     *
903
-     * @param  string $return    the current html
904
-     * @param  int    $id        the post id for the page
905
-     * @param  string $new_title What the title is
906
-     * @param  string $new_slug  what the slug is
907
-     * @return string            The new html string for the permalink area
908
-     */
909
-    public function extra_permalink_field_buttons($return, $id, $new_title, $new_slug)
910
-    {
911
-        // make sure this is only when editing
912
-        if (! empty($id)) {
913
-            $post = get_post($id);
914
-            $return .= '<a class="button button-small" onclick="prompt(\'Shortcode:\', jQuery(\'#shortcode\').val()); return false;" href="#"  tabindex="-1">'
915
-                       . esc_html__('Shortcode', 'event_espresso')
916
-                       . '</a> ';
917
-            $return .= '<input id="shortcode" type="hidden" value="[ESPRESSO_TICKET_SELECTOR event_id='
918
-                       . $post->ID
919
-                       . ']">';
920
-        }
921
-        return $return;
922
-    }
923
-
924
-
925
-    /**
926
-     * _events_overview_list_table
927
-     * This contains the logic for showing the events_overview list
928
-     *
929
-     * @access protected
930
-     * @return void
931
-     * @throws \EE_Error
932
-     */
933
-    protected function _events_overview_list_table()
934
-    {
935
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
936
-        $this->_template_args['after_list_table'] = ! empty($this->_template_args['after_list_table'])
937
-            ? (array) $this->_template_args['after_list_table']
938
-            : array();
939
-        $this->_template_args['after_list_table']['view_event_list_button'] = EEH_HTML::br()
940
-                . EEH_Template::get_button_or_link(
941
-                    get_post_type_archive_link('espresso_events'),
942
-                    esc_html__("View Event Archive Page", "event_espresso"),
943
-                    'button'
944
-                );
945
-        $this->_template_args['after_list_table']['legend'] = $this->_display_legend($this->_event_legend_items());
946
-        $this->_admin_page_title .= ' ' . $this->get_action_link_or_button(
947
-            'create_new',
948
-            'add',
949
-            array(),
950
-            'add-new-h2'
951
-        );
952
-        $this->display_admin_list_table_page_with_no_sidebar();
953
-    }
954
-
955
-
956
-    /**
957
-     * this allows for extra misc actions in the default WP publish box
958
-     *
959
-     * @return void
960
-     */
961
-    public function extra_misc_actions_publish_box()
962
-    {
963
-        $this->_generate_publish_box_extra_content();
964
-    }
965
-
966
-
967
-    /**
968
-     * This is hooked into the WordPress do_action('save_post') hook and runs after the custom post type has been
969
-     * saved.
970
-     * Typically you would use this to save any additional data.
971
-     * Keep in mind also that "save_post" runs on EVERY post update to the database.
972
-     * ALSO very important.  When a post transitions from scheduled to published,
973
-     * the save_post action is fired but you will NOT have any _POST data containing any extra info you may have from
974
-     * other meta saves. So MAKE sure that you handle this accordingly.
975
-     *
976
-     * @access protected
977
-     * @abstract
978
-     * @param  string $post_id The ID of the cpt that was saved (so you can link relationally)
979
-     * @param  object $post    The post object of the cpt that was saved.
980
-     * @return void
981
-     * @throws \EE_Error
982
-     */
983
-    protected function _insert_update_cpt_item($post_id, $post)
984
-    {
985
-        if ($post instanceof WP_Post && $post->post_type !== 'espresso_events') {
986
-            // get out we're not processing an event save.
987
-            return;
988
-        }
989
-        $event_values = array(
990
-            'EVT_display_desc'                => ! empty($this->_req_data['display_desc']) ? 1 : 0,
991
-            'EVT_display_ticket_selector'     => ! empty($this->_req_data['display_ticket_selector']) ? 1 : 0,
992
-            'EVT_additional_limit'            => min(
993
-                apply_filters('FHEE__EE_Events_Admin__insert_update_cpt_item__EVT_additional_limit_max', 255),
994
-                ! empty($this->_req_data['additional_limit']) ? $this->_req_data['additional_limit'] : null
995
-            ),
996
-            'EVT_default_registration_status' => ! empty($this->_req_data['EVT_default_registration_status'])
997
-                ? $this->_req_data['EVT_default_registration_status']
998
-                : EE_Registry::instance()->CFG->registration->default_STS_ID,
999
-            'EVT_member_only'                 => ! empty($this->_req_data['member_only']) ? 1 : 0,
1000
-            'EVT_allow_overflow'              => ! empty($this->_req_data['EVT_allow_overflow']) ? 1 : 0,
1001
-            'EVT_timezone_string'             => ! empty($this->_req_data['timezone_string'])
1002
-                ? $this->_req_data['timezone_string'] : null,
1003
-            'EVT_external_URL'                => ! empty($this->_req_data['externalURL'])
1004
-                ? $this->_req_data['externalURL'] : null,
1005
-            'EVT_phone'                       => ! empty($this->_req_data['event_phone'])
1006
-                ? $this->_req_data['event_phone'] : null,
1007
-        );
1008
-        // update event
1009
-        $success = $this->_event_model()->update_by_ID($event_values, $post_id);
1010
-        // get event_object for other metaboxes... though it would seem to make sense to just use $this->_event_model()->get_one_by_ID( $post_id ).. i have to setup where conditions to override the filters in the model that filter out autodraft and inherit statuses so we GET the inherit id!
1011
-        $get_one_where = array(
1012
-            $this->_event_model()->primary_key_name() => $post_id,
1013
-            'OR'                                      => array(
1014
-                'status'   => $post->post_status,
1015
-                // if trying to "Publish" a sold out event, it's status will get switched back to "sold_out" in the db,
1016
-                // but the returned object here has a status of "publish", so use the original post status as well
1017
-                'status*1' => $this->_req_data['original_post_status'],
1018
-            ),
1019
-        );
1020
-        $event = $this->_event_model()->get_one(array($get_one_where));
1021
-        // the following are default callbacks for event attachment updates that can be overridden by caffeinated functionality and/or addons.
1022
-        $event_update_callbacks = apply_filters(
1023
-            'FHEE__Events_Admin_Page___insert_update_cpt_item__event_update_callbacks',
1024
-            array(
1025
-                array($this, '_default_venue_update'),
1026
-                array($this, '_default_tickets_update'),
1027
-            )
1028
-        );
1029
-        $att_success = true;
1030
-        foreach ($event_update_callbacks as $e_callback) {
1031
-            $_success = is_callable($e_callback)
1032
-                ? call_user_func($e_callback, $event, $this->_req_data)
1033
-                : false;
1034
-            // if ANY of these updates fail then we want the appropriate global error message
1035
-            $att_success = ! $att_success ? $att_success : $_success;
1036
-        }
1037
-        // any errors?
1038
-        if ($success && false === $att_success) {
1039
-            EE_Error::add_error(
1040
-                esc_html__(
1041
-                    'Event Details saved successfully but something went wrong with saving attachments.',
1042
-                    'event_espresso'
1043
-                ),
1044
-                __FILE__,
1045
-                __FUNCTION__,
1046
-                __LINE__
1047
-            );
1048
-        } elseif ($success === false) {
1049
-            EE_Error::add_error(
1050
-                esc_html__('Event Details did not save successfully.', 'event_espresso'),
1051
-                __FILE__,
1052
-                __FUNCTION__,
1053
-                __LINE__
1054
-            );
1055
-        }
1056
-    }
1057
-
1058
-
1059
-    /**
1060
-     * @see parent::restore_item()
1061
-     * @param int $post_id
1062
-     * @param int $revision_id
1063
-     */
1064
-    protected function _restore_cpt_item($post_id, $revision_id)
1065
-    {
1066
-        // copy existing event meta to new post
1067
-        $post_evt = $this->_event_model()->get_one_by_ID($post_id);
1068
-        if ($post_evt instanceof EE_Event) {
1069
-            // meta revision restore
1070
-            $post_evt->restore_revision($revision_id);
1071
-            // related objs restore
1072
-            $post_evt->restore_revision($revision_id, array('Venue', 'Datetime', 'Price'));
1073
-        }
1074
-    }
1075
-
1076
-
1077
-    /**
1078
-     * Attach the venue to the Event
1079
-     *
1080
-     * @param  \EE_Event $evtobj Event Object to add the venue to
1081
-     * @param  array     $data   The request data from the form
1082
-     * @return bool           Success or fail.
1083
-     */
1084
-    protected function _default_venue_update(\EE_Event $evtobj, $data)
1085
-    {
1086
-        require_once(EE_MODELS . 'EEM_Venue.model.php');
1087
-        $venue_model = EE_Registry::instance()->load_model('Venue');
1088
-        $rows_affected = null;
1089
-        $venue_id = ! empty($data['venue_id']) ? $data['venue_id'] : null;
1090
-        // very important.  If we don't have a venue name...
1091
-        // then we'll get out because not necessary to create empty venue
1092
-        if (empty($data['venue_title'])) {
1093
-            return false;
1094
-        }
1095
-        $venue_array = array(
1096
-            'VNU_wp_user'         => $evtobj->get('EVT_wp_user'),
1097
-            'VNU_name'            => ! empty($data['venue_title']) ? $data['venue_title'] : null,
1098
-            'VNU_desc'            => ! empty($data['venue_description']) ? $data['venue_description'] : null,
1099
-            'VNU_identifier'      => ! empty($data['venue_identifier']) ? $data['venue_identifier'] : null,
1100
-            'VNU_short_desc'      => ! empty($data['venue_short_description']) ? $data['venue_short_description']
1101
-                : null,
1102
-            'VNU_address'         => ! empty($data['address']) ? $data['address'] : null,
1103
-            'VNU_address2'        => ! empty($data['address2']) ? $data['address2'] : null,
1104
-            'VNU_city'            => ! empty($data['city']) ? $data['city'] : null,
1105
-            'STA_ID'              => ! empty($data['state']) ? $data['state'] : null,
1106
-            'CNT_ISO'             => ! empty($data['countries']) ? $data['countries'] : null,
1107
-            'VNU_zip'             => ! empty($data['zip']) ? $data['zip'] : null,
1108
-            'VNU_phone'           => ! empty($data['venue_phone']) ? $data['venue_phone'] : null,
1109
-            'VNU_capacity'        => ! empty($data['venue_capacity']) ? $data['venue_capacity'] : null,
1110
-            'VNU_url'             => ! empty($data['venue_url']) ? $data['venue_url'] : null,
1111
-            'VNU_virtual_phone'   => ! empty($data['virtual_phone']) ? $data['virtual_phone'] : null,
1112
-            'VNU_virtual_url'     => ! empty($data['virtual_url']) ? $data['virtual_url'] : null,
1113
-            'VNU_enable_for_gmap' => isset($data['enable_for_gmap']) ? 1 : 0,
1114
-            'status'              => 'publish',
1115
-        );
1116
-        // if we've got the venue_id then we're just updating the existing venue so let's do that and then get out.
1117
-        if (! empty($venue_id)) {
1118
-            $update_where = array($venue_model->primary_key_name() => $venue_id);
1119
-            $rows_affected = $venue_model->update($venue_array, array($update_where));
1120
-            // we've gotta make sure that the venue is always attached to a revision.. add_relation_to should take care of making sure that the relation is already present.
1121
-            $evtobj->_add_relation_to($venue_id, 'Venue');
1122
-            return $rows_affected > 0 ? true : false;
1123
-        } else {
1124
-            // we insert the venue
1125
-            $venue_id = $venue_model->insert($venue_array);
1126
-            $evtobj->_add_relation_to($venue_id, 'Venue');
1127
-            return ! empty($venue_id) ? true : false;
1128
-        }
1129
-        // when we have the ancestor come in it's already been handled by the revision save.
1130
-    }
1131
-
1132
-
1133
-    /**
1134
-     * Handles saving everything related to Tickets (datetimes, tickets, prices)
1135
-     *
1136
-     * @param  EE_Event $evtobj The Event object we're attaching data to
1137
-     * @param  array    $data   The request data from the form
1138
-     * @return array
1139
-     */
1140
-    protected function _default_tickets_update(EE_Event $evtobj, $data)
1141
-    {
1142
-        $success = true;
1143
-        $saved_dtt = null;
1144
-        $saved_tickets = array();
1145
-        $incoming_date_formats = array('Y-m-d', 'h:i a');
1146
-        foreach ($data['edit_event_datetimes'] as $row => $dtt) {
1147
-            // trim all values to ensure any excess whitespace is removed.
1148
-            $dtt = array_map('trim', $dtt);
1149
-            $dtt['DTT_EVT_end'] = isset($dtt['DTT_EVT_end']) && ! empty($dtt['DTT_EVT_end']) ? $dtt['DTT_EVT_end']
1150
-                : $dtt['DTT_EVT_start'];
1151
-            $datetime_values = array(
1152
-                'DTT_ID'        => ! empty($dtt['DTT_ID']) ? $dtt['DTT_ID'] : null,
1153
-                'DTT_EVT_start' => $dtt['DTT_EVT_start'],
1154
-                'DTT_EVT_end'   => $dtt['DTT_EVT_end'],
1155
-                'DTT_reg_limit' => empty($dtt['DTT_reg_limit']) ? EE_INF : $dtt['DTT_reg_limit'],
1156
-                'DTT_order'     => $row,
1157
-            );
1158
-            // if we have an id then let's get existing object first and then set the new values.  Otherwise we instantiate a new object for save.
1159
-            if (! empty($dtt['DTT_ID'])) {
1160
-                $DTM = EE_Registry::instance()
1161
-                                  ->load_model('Datetime', array($evtobj->get_timezone()))
1162
-                                  ->get_one_by_ID($dtt['DTT_ID']);
1163
-                $DTM->set_date_format($incoming_date_formats[0]);
1164
-                $DTM->set_time_format($incoming_date_formats[1]);
1165
-                foreach ($datetime_values as $field => $value) {
1166
-                    $DTM->set($field, $value);
1167
-                }
1168
-                // make sure the $dtt_id here is saved just in case after the add_relation_to() the autosave replaces it.  We need to do this so we dont' TRASH the parent DTT.
1169
-                $saved_dtts[ $DTM->ID() ] = $DTM;
1170
-            } else {
1171
-                $DTM = EE_Registry::instance()->load_class(
1172
-                    'Datetime',
1173
-                    array($datetime_values, $evtobj->get_timezone(), $incoming_date_formats),
1174
-                    false,
1175
-                    false
1176
-                );
1177
-                foreach ($datetime_values as $field => $value) {
1178
-                    $DTM->set($field, $value);
1179
-                }
1180
-            }
1181
-            $DTM->save();
1182
-            $DTT = $evtobj->_add_relation_to($DTM, 'Datetime');
1183
-            // load DTT helper
1184
-            // before going any further make sure our dates are setup correctly so that the end date is always equal or greater than the start date.
1185
-            if ($DTT->get_raw('DTT_EVT_start') > $DTT->get_raw('DTT_EVT_end')) {
1186
-                $DTT->set('DTT_EVT_end', $DTT->get('DTT_EVT_start'));
1187
-                $DTT = EEH_DTT_Helper::date_time_add($DTT, 'DTT_EVT_end', 'days');
1188
-                $DTT->save();
1189
-            }
1190
-            // now we got to make sure we add the new DTT_ID to the $saved_dtts array  because it is possible there was a new one created for the autosave.
1191
-            $saved_dtt = $DTT;
1192
-            $success = ! $success ? $success : $DTT;
1193
-            // if ANY of these updates fail then we want the appropriate global error message.
1194
-            // //todo this is actually sucky we need a better error message but this is what it is for now.
1195
-        }
1196
-        // no dtts get deleted so we don't do any of that logic here.
1197
-        // update tickets next
1198
-        $old_tickets = isset($data['ticket_IDs']) ? explode(',', $data['ticket_IDs']) : array();
1199
-        foreach ($data['edit_tickets'] as $row => $tkt) {
1200
-            $incoming_date_formats = array('Y-m-d', 'h:i a');
1201
-            $update_prices = false;
1202
-            $ticket_price = isset($data['edit_prices'][ $row ][1]['PRC_amount'])
1203
-                ? $data['edit_prices'][ $row ][1]['PRC_amount'] : 0;
1204
-            // trim inputs to ensure any excess whitespace is removed.
1205
-            $tkt = array_map('trim', $tkt);
1206
-            if (empty($tkt['TKT_start_date'])) {
1207
-                // let's use now in the set timezone.
1208
-                $now = new DateTime('now', new DateTimeZone($evtobj->get_timezone()));
1209
-                $tkt['TKT_start_date'] = $now->format($incoming_date_formats[0] . ' ' . $incoming_date_formats[1]);
1210
-            }
1211
-            if (empty($tkt['TKT_end_date'])) {
1212
-                // use the start date of the first datetime
1213
-                $dtt = $evtobj->first_datetime();
1214
-                $tkt['TKT_end_date'] = $dtt->start_date_and_time(
1215
-                    $incoming_date_formats[0],
1216
-                    $incoming_date_formats[1]
1217
-                );
1218
-            }
1219
-            $TKT_values = array(
1220
-                'TKT_ID'          => ! empty($tkt['TKT_ID']) ? $tkt['TKT_ID'] : null,
1221
-                'TTM_ID'          => ! empty($tkt['TTM_ID']) ? $tkt['TTM_ID'] : 0,
1222
-                'TKT_name'        => ! empty($tkt['TKT_name']) ? $tkt['TKT_name'] : '',
1223
-                'TKT_description' => ! empty($tkt['TKT_description']) ? $tkt['TKT_description'] : '',
1224
-                'TKT_start_date'  => $tkt['TKT_start_date'],
1225
-                'TKT_end_date'    => $tkt['TKT_end_date'],
1226
-                'TKT_qty'         => ! isset($tkt['TKT_qty']) || $tkt['TKT_qty'] === '' ? EE_INF : $tkt['TKT_qty'],
1227
-                'TKT_uses'        => ! isset($tkt['TKT_uses']) || $tkt['TKT_uses'] === '' ? EE_INF : $tkt['TKT_uses'],
1228
-                'TKT_min'         => empty($tkt['TKT_min']) ? 0 : $tkt['TKT_min'],
1229
-                'TKT_max'         => empty($tkt['TKT_max']) ? EE_INF : $tkt['TKT_max'],
1230
-                'TKT_row'         => $row,
1231
-                'TKT_order'       => isset($tkt['TKT_order']) ? $tkt['TKT_order'] : $row,
1232
-                'TKT_price'       => $ticket_price,
1233
-            );
1234
-            // if this is a default TKT, then we need to set the TKT_ID to 0 and update accordingly, which means in turn that the prices will become new prices as well.
1235
-            if (isset($tkt['TKT_is_default']) && $tkt['TKT_is_default']) {
1236
-                $TKT_values['TKT_ID'] = 0;
1237
-                $TKT_values['TKT_is_default'] = 0;
1238
-                $TKT_values['TKT_price'] = $ticket_price;
1239
-                $update_prices = true;
1240
-            }
1241
-            // if we have a TKT_ID then we need to get that existing TKT_obj and update it
1242
-            // we actually do our saves a head of doing any add_relations to because its entirely possible that this ticket didn't removed or added to any datetime in the session but DID have it's items modified.
1243
-            // keep in mind that if the TKT has been sold (and we have changed pricing information), then we won't be updating the tkt but instead a new tkt will be created and the old one archived.
1244
-            if (! empty($tkt['TKT_ID'])) {
1245
-                $TKT = EE_Registry::instance()
1246
-                                  ->load_model('Ticket', array($evtobj->get_timezone()))
1247
-                                  ->get_one_by_ID($tkt['TKT_ID']);
1248
-                if ($TKT instanceof EE_Ticket) {
1249
-                    $ticket_sold = $TKT->count_related(
1250
-                        'Registration',
1251
-                        array(
1252
-                            array(
1253
-                                'STS_ID' => array(
1254
-                                    'NOT IN',
1255
-                                    array(EEM_Registration::status_id_incomplete),
1256
-                                ),
1257
-                            ),
1258
-                        )
1259
-                    ) > 0 ? true : false;
1260
-                    // let's just check the total price for the existing ticket and determine if it matches the new total price.  if they are different then we create a new ticket (if tkts sold) if they aren't different then we go ahead and modify existing ticket.
1261
-                    $create_new_TKT = $ticket_sold && $ticket_price != $TKT->get('TKT_price')
1262
-                                      && ! $TKT->get('TKT_deleted');
1263
-                    $TKT->set_date_format($incoming_date_formats[0]);
1264
-                    $TKT->set_time_format($incoming_date_formats[1]);
1265
-                    // set new values
1266
-                    foreach ($TKT_values as $field => $value) {
1267
-                        if ($field == 'TKT_qty') {
1268
-                            $TKT->set_qty($value);
1269
-                        } else {
1270
-                            $TKT->set($field, $value);
1271
-                        }
1272
-                    }
1273
-                    // if $create_new_TKT is false then we can safely update the existing ticket.  Otherwise we have to create a new ticket.
1274
-                    if ($create_new_TKT) {
1275
-                        // archive the old ticket first
1276
-                        $TKT->set('TKT_deleted', 1);
1277
-                        $TKT->save();
1278
-                        // make sure this ticket is still recorded in our saved_tkts so we don't run it through the regular trash routine.
1279
-                        $saved_tickets[ $TKT->ID() ] = $TKT;
1280
-                        // create new ticket that's a copy of the existing except a new id of course (and not archived) AND has the new TKT_price associated with it.
1281
-                        $TKT = clone $TKT;
1282
-                        $TKT->set('TKT_ID', 0);
1283
-                        $TKT->set('TKT_deleted', 0);
1284
-                        $TKT->set('TKT_price', $ticket_price);
1285
-                        $TKT->set('TKT_sold', 0);
1286
-                        // now we need to make sure that $new prices are created as well and attached to new ticket.
1287
-                        $update_prices = true;
1288
-                    }
1289
-                    // make sure price is set if it hasn't been already
1290
-                    $TKT->set('TKT_price', $ticket_price);
1291
-                }
1292
-            } else {
1293
-                // no TKT_id so a new TKT
1294
-                $TKT_values['TKT_price'] = $ticket_price;
1295
-                $TKT = EE_Registry::instance()->load_class('Ticket', array($TKT_values), false, false);
1296
-                if ($TKT instanceof EE_Ticket) {
1297
-                    // need to reset values to properly account for the date formats
1298
-                    $TKT->set_date_format($incoming_date_formats[0]);
1299
-                    $TKT->set_time_format($incoming_date_formats[1]);
1300
-                    $TKT->set_timezone($evtobj->get_timezone());
1301
-                    // set new values
1302
-                    foreach ($TKT_values as $field => $value) {
1303
-                        if ($field == 'TKT_qty') {
1304
-                            $TKT->set_qty($value);
1305
-                        } else {
1306
-                            $TKT->set($field, $value);
1307
-                        }
1308
-                    }
1309
-                    $update_prices = true;
1310
-                }
1311
-            }
1312
-            // cap ticket qty by datetime reg limits
1313
-            $TKT->set_qty(min($TKT->qty(), $TKT->qty('reg_limit')));
1314
-            // update ticket.
1315
-            $TKT->save();
1316
-            // before going any further make sure our dates are setup correctly so that the end date is always equal or greater than the start date.
1317
-            if ($TKT->get_raw('TKT_start_date') > $TKT->get_raw('TKT_end_date')) {
1318
-                $TKT->set('TKT_end_date', $TKT->get('TKT_start_date'));
1319
-                $TKT = EEH_DTT_Helper::date_time_add($TKT, 'TKT_end_date', 'days');
1320
-                $TKT->save();
1321
-            }
1322
-            // initially let's add the ticket to the dtt
1323
-            $saved_dtt->_add_relation_to($TKT, 'Ticket');
1324
-            $saved_tickets[ $TKT->ID() ] = $TKT;
1325
-            // add prices to ticket
1326
-            $this->_add_prices_to_ticket($data['edit_prices'][ $row ], $TKT, $update_prices);
1327
-        }
1328
-        // however now we need to handle permanently deleting tickets via the ui.  Keep in mind that the ui does not allow deleting/archiving tickets that have ticket sold.  However, it does allow for deleting tickets that have no tickets sold, in which case we want to get rid of permanently because there is no need to save in db.
1329
-        $old_tickets = isset($old_tickets[0]) && $old_tickets[0] == '' ? array() : $old_tickets;
1330
-        $tickets_removed = array_diff($old_tickets, array_keys($saved_tickets));
1331
-        foreach ($tickets_removed as $id) {
1332
-            $id = absint($id);
1333
-            // get the ticket for this id
1334
-            $tkt_to_remove = EE_Registry::instance()->load_model('Ticket')->get_one_by_ID($id);
1335
-            // need to get all the related datetimes on this ticket and remove from every single one of them (remember this process can ONLY kick off if there are NO tkts_sold)
1336
-            $dtts = $tkt_to_remove->get_many_related('Datetime');
1337
-            foreach ($dtts as $dtt) {
1338
-                $tkt_to_remove->_remove_relation_to($dtt, 'Datetime');
1339
-            }
1340
-            // need to do the same for prices (except these prices can also be deleted because again, tickets can only be trashed if they don't have any TKTs sold (otherwise they are just archived))
1341
-            $tkt_to_remove->delete_related_permanently('Price');
1342
-            // finally let's delete this ticket (which should not be blocked at this point b/c we've removed all our relationships)
1343
-            $tkt_to_remove->delete_permanently();
1344
-        }
1345
-        return array($saved_dtt, $saved_tickets);
1346
-    }
1347
-
1348
-
1349
-    /**
1350
-     * This attaches a list of given prices to a ticket.
1351
-     * Note we dont' have to worry about ever removing relationships (or archiving prices) because if there is a change
1352
-     * in price information on a ticket, a new ticket is created anyways so the archived ticket will retain the old
1353
-     * price info and prices are automatically "archived" via the ticket.
1354
-     *
1355
-     * @access  private
1356
-     * @param array     $prices     Array of prices from the form.
1357
-     * @param EE_Ticket $ticket     EE_Ticket object that prices are being attached to.
1358
-     * @param bool      $new_prices Whether attach existing incoming prices or create new ones.
1359
-     * @return  void
1360
-     */
1361
-    private function _add_prices_to_ticket($prices, EE_Ticket $ticket, $new_prices = false)
1362
-    {
1363
-        foreach ($prices as $row => $prc) {
1364
-            $PRC_values = array(
1365
-                'PRC_ID'         => ! empty($prc['PRC_ID']) ? $prc['PRC_ID'] : null,
1366
-                'PRT_ID'         => ! empty($prc['PRT_ID']) ? $prc['PRT_ID'] : null,
1367
-                'PRC_amount'     => ! empty($prc['PRC_amount']) ? $prc['PRC_amount'] : 0,
1368
-                'PRC_name'       => ! empty($prc['PRC_name']) ? $prc['PRC_name'] : '',
1369
-                'PRC_desc'       => ! empty($prc['PRC_desc']) ? $prc['PRC_desc'] : '',
1370
-                'PRC_is_default' => 0, // make sure prices are NOT set as default from this context
1371
-                'PRC_order'      => $row,
1372
-            );
1373
-            if ($new_prices || empty($PRC_values['PRC_ID'])) {
1374
-                $PRC_values['PRC_ID'] = 0;
1375
-                $PRC = EE_Registry::instance()->load_class('Price', array($PRC_values), false, false);
1376
-            } else {
1377
-                $PRC = EE_Registry::instance()->load_model('Price')->get_one_by_ID($prc['PRC_ID']);
1378
-                // update this price with new values
1379
-                foreach ($PRC_values as $field => $newprc) {
1380
-                    $PRC->set($field, $newprc);
1381
-                }
1382
-                $PRC->save();
1383
-            }
1384
-            $ticket->_add_relation_to($PRC, 'Price');
1385
-        }
1386
-    }
1387
-
1388
-
1389
-    /**
1390
-     * Add in our autosave ajax handlers
1391
-     *
1392
-     */
1393
-    protected function _ee_autosave_create_new()
1394
-    {
1395
-    }
1396
-
1397
-
1398
-    /**
1399
-     * More autosave handlers.
1400
-     */
1401
-    protected function _ee_autosave_edit()
1402
-    {
1403
-        return; // TEMPORARILY EXITING CAUSE THIS IS A TODO
1404
-    }
1405
-
1406
-
1407
-    /**
1408
-     *    _generate_publish_box_extra_content
1409
-     */
1410
-    private function _generate_publish_box_extra_content()
1411
-    {
1412
-        // load formatter helper
1413
-        // args for getting related registrations
1414
-        $approved_query_args = array(
1415
-            array(
1416
-                'REG_deleted' => 0,
1417
-                'STS_ID'      => EEM_Registration::status_id_approved,
1418
-            ),
1419
-        );
1420
-        $not_approved_query_args = array(
1421
-            array(
1422
-                'REG_deleted' => 0,
1423
-                'STS_ID'      => EEM_Registration::status_id_not_approved,
1424
-            ),
1425
-        );
1426
-        $pending_payment_query_args = array(
1427
-            array(
1428
-                'REG_deleted' => 0,
1429
-                'STS_ID'      => EEM_Registration::status_id_pending_payment,
1430
-            ),
1431
-        );
1432
-        // publish box
1433
-        $publish_box_extra_args = array(
1434
-            'view_approved_reg_url'        => add_query_arg(
1435
-                array(
1436
-                    'action'      => 'default',
1437
-                    'event_id'    => $this->_cpt_model_obj->ID(),
1438
-                    '_reg_status' => EEM_Registration::status_id_approved,
1439
-                ),
1440
-                REG_ADMIN_URL
1441
-            ),
1442
-            'view_not_approved_reg_url'    => add_query_arg(
1443
-                array(
1444
-                    'action'      => 'default',
1445
-                    'event_id'    => $this->_cpt_model_obj->ID(),
1446
-                    '_reg_status' => EEM_Registration::status_id_not_approved,
1447
-                ),
1448
-                REG_ADMIN_URL
1449
-            ),
1450
-            'view_pending_payment_reg_url' => add_query_arg(
1451
-                array(
1452
-                    'action'      => 'default',
1453
-                    'event_id'    => $this->_cpt_model_obj->ID(),
1454
-                    '_reg_status' => EEM_Registration::status_id_pending_payment,
1455
-                ),
1456
-                REG_ADMIN_URL
1457
-            ),
1458
-            'approved_regs'                => $this->_cpt_model_obj->count_related(
1459
-                'Registration',
1460
-                $approved_query_args
1461
-            ),
1462
-            'not_approved_regs'            => $this->_cpt_model_obj->count_related(
1463
-                'Registration',
1464
-                $not_approved_query_args
1465
-            ),
1466
-            'pending_payment_regs'         => $this->_cpt_model_obj->count_related(
1467
-                'Registration',
1468
-                $pending_payment_query_args
1469
-            ),
1470
-            'misc_pub_section_class'       => apply_filters(
1471
-                'FHEE_Events_Admin_Page___generate_publish_box_extra_content__misc_pub_section_class',
1472
-                'misc-pub-section'
1473
-            ),
1474
-        );
1475
-        ob_start();
1476
-        do_action(
1477
-            'AHEE__Events_Admin_Page___generate_publish_box_extra_content__event_editor_overview_add',
1478
-            $this->_cpt_model_obj
1479
-        );
1480
-        $publish_box_extra_args['event_editor_overview_add'] = ob_get_clean();
1481
-        // load template
1482
-        EEH_Template::display_template(
1483
-            EVENTS_TEMPLATE_PATH . 'event_publish_box_extras.template.php',
1484
-            $publish_box_extra_args
1485
-        );
1486
-    }
1487
-
1488
-
1489
-    /**
1490
-     * @return EE_Event
1491
-     */
1492
-    public function get_event_object()
1493
-    {
1494
-        return $this->_cpt_model_obj;
1495
-    }
1496
-
1497
-
1498
-
1499
-
1500
-    /** METABOXES * */
1501
-    /**
1502
-     * _register_event_editor_meta_boxes
1503
-     * add all metaboxes related to the event_editor
1504
-     *
1505
-     * @return void
1506
-     */
1507
-    protected function _register_event_editor_meta_boxes()
1508
-    {
1509
-        $this->verify_cpt_object();
1510
-        // add_meta_box(
1511
-        //     'espresso_event_editor_tickets',
1512
-        //     esc_html__('Event Datetime & Ticket', 'event_espresso'),
1513
-        //     array($this, 'ticket_metabox'),
1514
-        //     $this->page_slug,
1515
-        //     'normal',
1516
-        //     'high'
1517
-        // );
1518
-        add_meta_box(
1519
-            'espresso_event_editor_event_options',
1520
-            esc_html__('Event Registration Options', 'event_espresso'),
1521
-            array($this, 'registration_options_meta_box'),
1522
-            $this->page_slug,
1523
-            'side',
1524
-            'default'
1525
-        );
1526
-        // NOTE: if you're looking for other metaboxes in here,
1527
-        // where a metabox has a related management page in the admin
1528
-        // you will find it setup in the related management page's "_Hooks" file.
1529
-        // i.e. messages metabox is found in "espresso_events_Messages_Hooks.class.php".
1530
-    }
1531
-
1532
-
1533
-    /**
1534
-     * @throws DomainException
1535
-     * @throws EE_Error
1536
-     */
1537
-    public function ticket_metabox()
1538
-    {
1539
-        $existing_datetime_ids = $existing_ticket_ids = array();
1540
-        // defaults for template args
1541
-        $template_args = array(
1542
-            'existing_datetime_ids'    => '',
1543
-            'event_datetime_help_link' => '',
1544
-            'ticket_options_help_link' => '',
1545
-            'time'                     => null,
1546
-            'ticket_rows'              => '',
1547
-            'existing_ticket_ids'      => '',
1548
-            'total_ticket_rows'        => 1,
1549
-            'ticket_js_structure'      => '',
1550
-            'trash_icon'               => 'ee-lock-icon',
1551
-            'disabled'                 => '',
1552
-        );
1553
-        $event_id = is_object($this->_cpt_model_obj) ? $this->_cpt_model_obj->ID() : null;
1554
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
1555
-        /**
1556
-         * 1. Start with retrieving Datetimes
1557
-         * 2. Fore each datetime get related tickets
1558
-         * 3. For each ticket get related prices
1559
-         */
1560
-        $times = EE_Registry::instance()->load_model('Datetime')->get_all_event_dates($event_id);
1561
-        /** @type EE_Datetime $first_datetime */
1562
-        $first_datetime = reset($times);
1563
-        // do we get related tickets?
1564
-        if ($first_datetime instanceof EE_Datetime
1565
-            && $first_datetime->ID() !== 0
1566
-        ) {
1567
-            $existing_datetime_ids[] = $first_datetime->get('DTT_ID');
1568
-            $template_args['time'] = $first_datetime;
1569
-            $related_tickets = $first_datetime->tickets(
1570
-                array(
1571
-                    array('OR' => array('TKT_deleted' => 1, 'TKT_deleted*' => 0)),
1572
-                    'default_where_conditions' => 'none',
1573
-                )
1574
-            );
1575
-            if (! empty($related_tickets)) {
1576
-                $template_args['total_ticket_rows'] = count($related_tickets);
1577
-                $row = 0;
1578
-                foreach ($related_tickets as $ticket) {
1579
-                    $existing_ticket_ids[] = $ticket->get('TKT_ID');
1580
-                    $template_args['ticket_rows'] .= $this->_get_ticket_row($ticket, false, $row);
1581
-                    $row++;
1582
-                }
1583
-            } else {
1584
-                $template_args['total_ticket_rows'] = 1;
1585
-                /** @type EE_Ticket $ticket */
1586
-                $ticket = EE_Registry::instance()->load_model('Ticket')->create_default_object();
1587
-                $template_args['ticket_rows'] .= $this->_get_ticket_row($ticket);
1588
-            }
1589
-        } else {
1590
-            $template_args['time'] = $times[0];
1591
-            /** @type EE_Ticket $ticket */
1592
-            $ticket = EE_Registry::instance()->load_model('Ticket')->get_all_default_tickets();
1593
-            $template_args['ticket_rows'] .= $this->_get_ticket_row($ticket[1]);
1594
-            // NOTE: we're just sending the first default row
1595
-            // (decaf can't manage default tickets so this should be sufficient);
1596
-        }
1597
-        $template_args['event_datetime_help_link'] = $this->_get_help_tab_link(
1598
-            'event_editor_event_datetimes_help_tab'
1599
-        );
1600
-        $template_args['ticket_options_help_link'] = $this->_get_help_tab_link('ticket_options_info');
1601
-        $template_args['existing_datetime_ids'] = implode(',', $existing_datetime_ids);
1602
-        $template_args['existing_ticket_ids'] = implode(',', $existing_ticket_ids);
1603
-        $template_args['ticket_js_structure'] = $this->_get_ticket_row(
1604
-            EE_Registry::instance()->load_model('Ticket')->create_default_object(),
1605
-            true
1606
-        );
1607
-        $template = apply_filters(
1608
-            'FHEE__Events_Admin_Page__ticket_metabox__template',
1609
-            EVENTS_TEMPLATE_PATH . 'event_tickets_metabox_main.template.php'
1610
-        );
1611
-        EEH_Template::display_template($template, $template_args);
1612
-    }
1613
-
1614
-
1615
-    /**
1616
-     * Setup an individual ticket form for the decaf event editor page
1617
-     *
1618
-     * @access private
1619
-     * @param  EE_Ticket $ticket   the ticket object
1620
-     * @param  boolean   $skeleton whether we're generating a skeleton for js manipulation
1621
-     * @param int        $row
1622
-     * @return string generated html for the ticket row.
1623
-     */
1624
-    private function _get_ticket_row($ticket, $skeleton = false, $row = 0)
1625
-    {
1626
-        $template_args = array(
1627
-            'tkt_status_class'    => ' tkt-status-' . $ticket->ticket_status(),
1628
-            'tkt_archive_class'   => $ticket->ticket_status() === EE_Ticket::archived && ! $skeleton ? ' tkt-archived'
1629
-                : '',
1630
-            'ticketrow'           => $skeleton ? 'TICKETNUM' : $row,
1631
-            'TKT_ID'              => $ticket->get('TKT_ID'),
1632
-            'TKT_name'            => $ticket->get('TKT_name'),
1633
-            'TKT_start_date'      => $skeleton ? '' : $ticket->get_date('TKT_start_date', 'Y-m-d h:i a'),
1634
-            'TKT_end_date'        => $skeleton ? '' : $ticket->get_date('TKT_end_date', 'Y-m-d h:i a'),
1635
-            'TKT_is_default'      => $ticket->get('TKT_is_default'),
1636
-            'TKT_qty'             => $ticket->get_pretty('TKT_qty', 'input'),
1637
-            'edit_ticketrow_name' => $skeleton ? 'TICKETNAMEATTR' : 'edit_tickets',
1638
-            'TKT_sold'            => $skeleton ? 0 : $ticket->get('TKT_sold'),
1639
-            'trash_icon'          => ($skeleton || (! empty($ticket) && ! $ticket->get('TKT_deleted')))
1640
-                                     && (! empty($ticket) && $ticket->get('TKT_sold') === 0)
1641
-                ? 'trash-icon dashicons dashicons-post-trash clickable' : 'ee-lock-icon',
1642
-            'disabled'            => $skeleton || (! empty($ticket) && ! $ticket->get('TKT_deleted')) ? ''
1643
-                : ' disabled=disabled',
1644
-        );
1645
-        $price = $ticket->ID() !== 0
1646
-            ? $ticket->get_first_related('Price', array('default_where_conditions' => 'none'))
1647
-            : EE_Registry::instance()->load_model('Price')->create_default_object();
1648
-        $price_args = array(
1649
-            'price_currency_symbol' => EE_Registry::instance()->CFG->currency->sign,
1650
-            'PRC_amount'            => $price->get('PRC_amount'),
1651
-            'PRT_ID'                => $price->get('PRT_ID'),
1652
-            'PRC_ID'                => $price->get('PRC_ID'),
1653
-            'PRC_is_default'        => $price->get('PRC_is_default'),
1654
-        );
1655
-        // make sure we have default start and end dates if skeleton
1656
-        // handle rows that should NOT be empty
1657
-        if (empty($template_args['TKT_start_date'])) {
1658
-            // if empty then the start date will be now.
1659
-            $template_args['TKT_start_date'] = date('Y-m-d h:i a', current_time('timestamp'));
1660
-        }
1661
-        if (empty($template_args['TKT_end_date'])) {
1662
-            // get the earliest datetime (if present);
1663
-            $earliest_dtt = $this->_cpt_model_obj->ID() > 0
1664
-                ? $this->_cpt_model_obj->get_first_related(
1665
-                    'Datetime',
1666
-                    array('order_by' => array('DTT_EVT_start' => 'ASC'))
1667
-                )
1668
-                : null;
1669
-            if (! empty($earliest_dtt)) {
1670
-                $template_args['TKT_end_date'] = $earliest_dtt->get_datetime('DTT_EVT_start', 'Y-m-d', 'h:i a');
1671
-            } else {
1672
-                $template_args['TKT_end_date'] = date(
1673
-                    'Y-m-d h:i a',
1674
-                    mktime(0, 0, 0, date("m"), date("d") + 7, date("Y"))
1675
-                );
1676
-            }
1677
-        }
1678
-        $template_args = array_merge($template_args, $price_args);
1679
-        $template = apply_filters(
1680
-            'FHEE__Events_Admin_Page__get_ticket_row__template',
1681
-            EVENTS_TEMPLATE_PATH . 'event_tickets_metabox_ticket_row.template.php',
1682
-            $ticket
1683
-        );
1684
-        return EEH_Template::display_template($template, $template_args, true);
1685
-    }
1686
-
1687
-
1688
-    /**
1689
-     * @throws DomainException
1690
-     */
1691
-    public function registration_options_meta_box()
1692
-    {
1693
-        $yes_no_values = array(
1694
-            array('id' => true, 'text' => esc_html__('Yes', 'event_espresso')),
1695
-            array('id' => false, 'text' => esc_html__('No', 'event_espresso')),
1696
-        );
1697
-        $default_reg_status_values = EEM_Registration::reg_status_array(
1698
-            array(
1699
-                EEM_Registration::status_id_cancelled,
1700
-                EEM_Registration::status_id_declined,
1701
-                EEM_Registration::status_id_incomplete,
1702
-            ),
1703
-            true
1704
-        );
1705
-        // $template_args['is_active_select'] = EEH_Form_Fields::select_input('is_active', $yes_no_values, $this->_cpt_model_obj->is_active());
1706
-        $template_args['_event'] = $this->_cpt_model_obj;
1707
-        $template_args['active_status'] = $this->_cpt_model_obj->pretty_active_status(false);
1708
-        $template_args['additional_limit'] = $this->_cpt_model_obj->additional_limit();
1709
-        $template_args['default_registration_status'] = EEH_Form_Fields::select_input(
1710
-            'default_reg_status',
1711
-            $default_reg_status_values,
1712
-            $this->_cpt_model_obj->default_registration_status()
1713
-        );
1714
-        $template_args['display_description'] = EEH_Form_Fields::select_input(
1715
-            'display_desc',
1716
-            $yes_no_values,
1717
-            $this->_cpt_model_obj->display_description()
1718
-        );
1719
-        $template_args['display_ticket_selector'] = EEH_Form_Fields::select_input(
1720
-            'display_ticket_selector',
1721
-            $yes_no_values,
1722
-            $this->_cpt_model_obj->display_ticket_selector(),
1723
-            '',
1724
-            '',
1725
-            false
1726
-        );
1727
-        $template_args['additional_registration_options'] = apply_filters(
1728
-            'FHEE__Events_Admin_Page__registration_options_meta_box__additional_registration_options',
1729
-            '',
1730
-            $template_args,
1731
-            $yes_no_values,
1732
-            $default_reg_status_values
1733
-        );
1734
-        EEH_Template::display_template(
1735
-            EVENTS_TEMPLATE_PATH . 'event_registration_options.template.php',
1736
-            $template_args
1737
-        );
1738
-    }
1739
-
1740
-
1741
-    /**
1742
-     * _get_events()
1743
-     * This method simply returns all the events (for the given _view and paging)
1744
-     *
1745
-     * @access public
1746
-     * @param int  $per_page     count of items per page (20 default);
1747
-     * @param int  $current_page what is the current page being viewed.
1748
-     * @param bool $count        if TRUE then we just return a count of ALL events matching the given _view.
1749
-     *                           If FALSE then we return an array of event objects
1750
-     *                           that match the given _view and paging parameters.
1751
-     * @return array an array of event objects.
1752
-     */
1753
-    public function get_events($per_page = 10, $current_page = 1, $count = false)
1754
-    {
1755
-        $EEME = $this->_event_model();
1756
-        $offset = ($current_page - 1) * $per_page;
1757
-        $limit = $count ? null : $offset . ',' . $per_page;
1758
-        $orderby = isset($this->_req_data['orderby']) ? $this->_req_data['orderby'] : 'EVT_ID';
1759
-        $order = isset($this->_req_data['order']) ? $this->_req_data['order'] : "DESC";
1760
-        if (isset($this->_req_data['month_range'])) {
1761
-            $pieces = explode(' ', $this->_req_data['month_range'], 3);
1762
-            // simulate the FIRST day of the month, that fixes issues for months like February
1763
-            // where PHP doesn't know what to assume for date.
1764
-            // @see https://events.codebasehq.com/projects/event-espresso/tickets/10437
1765
-            $month_r = ! empty($pieces[0]) ? date('m', \EEH_DTT_Helper::first_of_month_timestamp($pieces[0])) : '';
1766
-            $year_r = ! empty($pieces[1]) ? $pieces[1] : '';
1767
-        }
1768
-        $where = array();
1769
-        $status = isset($this->_req_data['status']) ? $this->_req_data['status'] : null;
1770
-        // determine what post_status our condition will have for the query.
1771
-        switch ($status) {
1772
-            case 'month':
1773
-            case 'today':
1774
-            case null:
1775
-            case 'all':
1776
-                break;
1777
-            case 'draft':
1778
-                $where['status'] = array('IN', array('draft', 'auto-draft'));
1779
-                break;
1780
-            default:
1781
-                $where['status'] = $status;
1782
-        }
1783
-        // categories?
1784
-        $category = isset($this->_req_data['EVT_CAT']) && $this->_req_data['EVT_CAT'] > 0
1785
-            ? $this->_req_data['EVT_CAT'] : null;
1786
-        if (! empty($category)) {
1787
-            $where['Term_Taxonomy.taxonomy'] = EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY;
1788
-            $where['Term_Taxonomy.term_id'] = $category;
1789
-        }
1790
-        // date where conditions
1791
-        $start_formats = EEM_Datetime::instance()->get_formats_for('DTT_EVT_start');
1792
-        if (isset($this->_req_data['month_range']) && $this->_req_data['month_range'] != '') {
1793
-            $DateTime = new DateTime(
1794
-                $year_r . '-' . $month_r . '-01 00:00:00',
1795
-                new DateTimeZone(EEM_Datetime::instance()->get_timezone())
1796
-            );
1797
-            $start = $DateTime->format(implode(' ', $start_formats));
1798
-            $end = $DateTime->setDate(
1799
-                $year_r,
1800
-                $month_r,
1801
-                $DateTime
1802
-                    ->format('t')
1803
-            )->setTime(23, 59, 59)
1804
-                            ->format(implode(' ', $start_formats));
1805
-            $where['Datetime.DTT_EVT_start'] = array('BETWEEN', array($start, $end));
1806
-        } elseif (isset($this->_req_data['status']) && $this->_req_data['status'] == 'today') {
1807
-            $DateTime = new DateTime('now', new DateTimeZone(EEM_Event::instance()->get_timezone()));
1808
-            $start = $DateTime->setTime(0, 0, 0)->format(implode(' ', $start_formats));
1809
-            $end = $DateTime->setTime(23, 59, 59)->format(implode(' ', $start_formats));
1810
-            $where['Datetime.DTT_EVT_start'] = array('BETWEEN', array($start, $end));
1811
-        } elseif (isset($this->_req_data['status']) && $this->_req_data['status'] == 'month') {
1812
-            $now = date('Y-m-01');
1813
-            $DateTime = new DateTime($now, new DateTimeZone(EEM_Event::instance()->get_timezone()));
1814
-            $start = $DateTime->setTime(0, 0, 0)->format(implode(' ', $start_formats));
1815
-            $end = $DateTime->setDate(date('Y'), date('m'), $DateTime->format('t'))
1816
-                            ->setTime(23, 59, 59)
1817
-                            ->format(implode(' ', $start_formats));
1818
-            $where['Datetime.DTT_EVT_start'] = array('BETWEEN', array($start, $end));
1819
-        }
1820
-        if (! EE_Registry::instance()->CAP->current_user_can('ee_read_others_events', 'get_events')) {
1821
-            $where['EVT_wp_user'] = get_current_user_id();
1822
-        } else {
1823
-            if (! isset($where['status'])) {
1824
-                if (! EE_Registry::instance()->CAP->current_user_can('ee_read_private_events', 'get_events')) {
1825
-                    $where['OR'] = array(
1826
-                        'status*restrict_private' => array('!=', 'private'),
1827
-                        'AND'                     => array(
1828
-                            'status*inclusive' => array('=', 'private'),
1829
-                            'EVT_wp_user'      => get_current_user_id(),
1830
-                        ),
1831
-                    );
1832
-                }
1833
-            }
1834
-        }
1835
-        if (isset($this->_req_data['EVT_wp_user'])) {
1836
-            if ($this->_req_data['EVT_wp_user'] != get_current_user_id()
1837
-                && EE_Registry::instance()->CAP->current_user_can('ee_read_others_events', 'get_events')
1838
-            ) {
1839
-                $where['EVT_wp_user'] = $this->_req_data['EVT_wp_user'];
1840
-            }
1841
-        }
1842
-        // search query handling
1843
-        if (isset($this->_req_data['s'])) {
1844
-            $search_string = '%' . $this->_req_data['s'] . '%';
1845
-            $where['OR'] = array(
1846
-                'EVT_name'       => array('LIKE', $search_string),
1847
-                'EVT_desc'       => array('LIKE', $search_string),
1848
-                'EVT_short_desc' => array('LIKE', $search_string),
1849
-            );
1850
-        }
1851
-        $where = apply_filters('FHEE__Events_Admin_Page__get_events__where', $where, $this->_req_data);
1852
-        $query_params = apply_filters(
1853
-            'FHEE__Events_Admin_Page__get_events__query_params',
1854
-            array(
1855
-                $where,
1856
-                'limit'    => $limit,
1857
-                'order_by' => $orderby,
1858
-                'order'    => $order,
1859
-                'group_by' => 'EVT_ID',
1860
-            ),
1861
-            $this->_req_data
1862
-        );
1863
-        // let's first check if we have special requests coming in.
1864
-        if (isset($this->_req_data['active_status'])) {
1865
-            switch ($this->_req_data['active_status']) {
1866
-                case 'upcoming':
1867
-                    return $EEME->get_upcoming_events($query_params, $count);
1868
-                    break;
1869
-                case 'expired':
1870
-                    return $EEME->get_expired_events($query_params, $count);
1871
-                    break;
1872
-                case 'active':
1873
-                    return $EEME->get_active_events($query_params, $count);
1874
-                    break;
1875
-                case 'inactive':
1876
-                    return $EEME->get_inactive_events($query_params, $count);
1877
-                    break;
1878
-            }
1879
-        }
1880
-        $events = $count ? $EEME->count(array($where), 'EVT_ID', true) : $EEME->get_all($query_params);
1881
-        return $events;
1882
-    }
1883
-
1884
-
1885
-    /**
1886
-     * handling for WordPress CPT actions (trash, restore, delete)
1887
-     *
1888
-     * @param string $post_id
1889
-     */
1890
-    public function trash_cpt_item($post_id)
1891
-    {
1892
-        $this->_req_data['EVT_ID'] = $post_id;
1893
-        $this->_trash_or_restore_event('trash', false);
1894
-    }
1895
-
1896
-
1897
-    /**
1898
-     * @param string $post_id
1899
-     */
1900
-    public function restore_cpt_item($post_id)
1901
-    {
1902
-        $this->_req_data['EVT_ID'] = $post_id;
1903
-        $this->_trash_or_restore_event('draft', false);
1904
-    }
1905
-
1906
-
1907
-    /**
1908
-     * @param string $post_id
1909
-     */
1910
-    public function delete_cpt_item($post_id)
1911
-    {
1912
-        $this->_req_data['EVT_ID'] = $post_id;
1913
-        $this->_delete_event(false);
1914
-    }
1915
-
1916
-
1917
-    /**
1918
-     * _trash_or_restore_event
1919
-     *
1920
-     * @access protected
1921
-     * @param  string $event_status
1922
-     * @param bool    $redirect_after
1923
-     */
1924
-    protected function _trash_or_restore_event($event_status = 'trash', $redirect_after = true)
1925
-    {
1926
-        // determine the event id and set to array.
1927
-        $EVT_ID = isset($this->_req_data['EVT_ID']) ? absint($this->_req_data['EVT_ID']) : false;
1928
-        // loop thru events
1929
-        if ($EVT_ID) {
1930
-            // clean status
1931
-            $event_status = sanitize_key($event_status);
1932
-            // grab status
1933
-            if (! empty($event_status)) {
1934
-                $success = $this->_change_event_status($EVT_ID, $event_status);
1935
-            } else {
1936
-                $success = false;
1937
-                $msg = esc_html__(
1938
-                    'An error occurred. The event could not be moved to the trash because a valid event status was not not supplied.',
1939
-                    'event_espresso'
1940
-                );
1941
-                EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
1942
-            }
1943
-        } else {
1944
-            $success = false;
1945
-            $msg = esc_html__(
1946
-                'An error occurred. The event could not be moved to the trash because a valid event ID was not not supplied.',
1947
-                'event_espresso'
1948
-            );
1949
-            EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
1950
-        }
1951
-        $action = $event_status == 'trash' ? 'moved to the trash' : 'restored from the trash';
1952
-        if ($redirect_after) {
1953
-            $this->_redirect_after_action($success, 'Event', $action, array('action' => 'default'));
1954
-        }
1955
-    }
1956
-
1957
-
1958
-    /**
1959
-     * _trash_or_restore_events
1960
-     *
1961
-     * @access protected
1962
-     * @param  string $event_status
1963
-     * @return void
1964
-     */
1965
-    protected function _trash_or_restore_events($event_status = 'trash')
1966
-    {
1967
-        // clean status
1968
-        $event_status = sanitize_key($event_status);
1969
-        // grab status
1970
-        if (! empty($event_status)) {
1971
-            $success = true;
1972
-            // determine the event id and set to array.
1973
-            $EVT_IDs = isset($this->_req_data['EVT_IDs']) ? (array) $this->_req_data['EVT_IDs'] : array();
1974
-            // loop thru events
1975
-            foreach ($EVT_IDs as $EVT_ID) {
1976
-                if ($EVT_ID = absint($EVT_ID)) {
1977
-                    $results = $this->_change_event_status($EVT_ID, $event_status);
1978
-                    $success = $results !== false ? $success : false;
1979
-                } else {
1980
-                    $msg = sprintf(
1981
-                        esc_html__(
1982
-                            'An error occurred. Event #%d could not be moved to the trash because a valid event ID was not not supplied.',
1983
-                            'event_espresso'
1984
-                        ),
1985
-                        $EVT_ID
1986
-                    );
1987
-                    EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
1988
-                    $success = false;
1989
-                }
1990
-            }
1991
-        } else {
1992
-            $success = false;
1993
-            $msg = esc_html__(
1994
-                'An error occurred. The event could not be moved to the trash because a valid event status was not not supplied.',
1995
-                'event_espresso'
1996
-            );
1997
-            EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
1998
-        }
1999
-        // in order to force a pluralized result message we need to send back a success status greater than 1
2000
-        $success = $success ? 2 : false;
2001
-        $action = $event_status == 'trash' ? 'moved to the trash' : 'restored from the trash';
2002
-        $this->_redirect_after_action($success, 'Events', $action, array('action' => 'default'));
2003
-    }
2004
-
2005
-
2006
-    /**
2007
-     * _trash_or_restore_events
2008
-     *
2009
-     * @access  private
2010
-     * @param  int    $EVT_ID
2011
-     * @param  string $event_status
2012
-     * @return bool
2013
-     */
2014
-    private function _change_event_status($EVT_ID = 0, $event_status = '')
2015
-    {
2016
-        // grab event id
2017
-        if (! $EVT_ID) {
2018
-            $msg = esc_html__(
2019
-                'An error occurred. No Event ID or an invalid Event ID was received.',
2020
-                'event_espresso'
2021
-            );
2022
-            EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2023
-            return false;
2024
-        }
2025
-        $this->_cpt_model_obj = EEM_Event::instance()->get_one_by_ID($EVT_ID);
2026
-        // clean status
2027
-        $event_status = sanitize_key($event_status);
2028
-        // grab status
2029
-        if (empty($event_status)) {
2030
-            $msg = esc_html__(
2031
-                'An error occurred. No Event Status or an invalid Event Status was received.',
2032
-                'event_espresso'
2033
-            );
2034
-            EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2035
-            return false;
2036
-        }
2037
-        // was event trashed or restored ?
2038
-        switch ($event_status) {
2039
-            case 'draft':
2040
-                $action = 'restored from the trash';
2041
-                $hook = 'AHEE_event_restored_from_trash';
2042
-                break;
2043
-            case 'trash':
2044
-                $action = 'moved to the trash';
2045
-                $hook = 'AHEE_event_moved_to_trash';
2046
-                break;
2047
-            default:
2048
-                $action = 'updated';
2049
-                $hook = false;
2050
-        }
2051
-        // use class to change status
2052
-        $this->_cpt_model_obj->set_status($event_status);
2053
-        $success = $this->_cpt_model_obj->save();
2054
-        if ($success === false) {
2055
-            $msg = sprintf(esc_html__('An error occurred. The event could not be %s.', 'event_espresso'), $action);
2056
-            EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2057
-            return false;
2058
-        }
2059
-        if ($hook) {
2060
-            do_action($hook);
2061
-        }
2062
-        return true;
2063
-    }
2064
-
2065
-
2066
-    /**
2067
-     * _delete_event
2068
-     *
2069
-     * @access protected
2070
-     * @param bool $redirect_after
2071
-     */
2072
-    protected function _delete_event($redirect_after = true)
2073
-    {
2074
-        // determine the event id and set to array.
2075
-        $EVT_ID = isset($this->_req_data['EVT_ID']) ? absint($this->_req_data['EVT_ID']) : null;
2076
-        $EVT_ID = isset($this->_req_data['post']) ? absint($this->_req_data['post']) : $EVT_ID;
2077
-        // loop thru events
2078
-        if ($EVT_ID) {
2079
-            $success = $this->_permanently_delete_event($EVT_ID);
2080
-            // get list of events with no prices
2081
-            $espresso_no_ticket_prices = get_option('ee_no_ticket_prices', array());
2082
-            // remove this event from the list of events with no prices
2083
-            if (isset($espresso_no_ticket_prices[ $EVT_ID ])) {
2084
-                unset($espresso_no_ticket_prices[ $EVT_ID ]);
2085
-            }
2086
-            update_option('ee_no_ticket_prices', $espresso_no_ticket_prices);
2087
-        } else {
2088
-            $success = false;
2089
-            $msg = esc_html__(
2090
-                'An error occurred. An event could not be deleted because a valid event ID was not not supplied.',
2091
-                'event_espresso'
2092
-            );
2093
-            EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2094
-        }
2095
-        if ($redirect_after) {
2096
-            $this->_redirect_after_action(
2097
-                $success,
2098
-                'Event',
2099
-                'deleted',
2100
-                array('action' => 'default', 'status' => 'trash')
2101
-            );
2102
-        }
2103
-    }
2104
-
2105
-
2106
-    /**
2107
-     * _delete_events
2108
-     *
2109
-     * @access protected
2110
-     * @return void
2111
-     */
2112
-    protected function _delete_events()
2113
-    {
2114
-        $success = true;
2115
-        // get list of events with no prices
2116
-        $espresso_no_ticket_prices = get_option('ee_no_ticket_prices', array());
2117
-        // determine the event id and set to array.
2118
-        $EVT_IDs = isset($this->_req_data['EVT_IDs']) ? (array) $this->_req_data['EVT_IDs'] : array();
2119
-        // loop thru events
2120
-        foreach ($EVT_IDs as $EVT_ID) {
2121
-            $EVT_ID = absint($EVT_ID);
2122
-            if ($EVT_ID) {
2123
-                $results = $this->_permanently_delete_event($EVT_ID);
2124
-                $success = $results !== false ? $success : false;
2125
-                // remove this event from the list of events with no prices
2126
-                unset($espresso_no_ticket_prices[ $EVT_ID ]);
2127
-            } else {
2128
-                $success = false;
2129
-                $msg = esc_html__(
2130
-                    'An error occurred. An event could not be deleted because a valid event ID was not not supplied.',
2131
-                    'event_espresso'
2132
-                );
2133
-                EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2134
-            }
2135
-        }
2136
-        update_option('ee_no_ticket_prices', $espresso_no_ticket_prices);
2137
-        // in order to force a pluralized result message we need to send back a success status greater than 1
2138
-        $success = $success ? 2 : false;
2139
-        $this->_redirect_after_action($success, 'Events', 'deleted', array('action' => 'default'));
2140
-    }
2141
-
2142
-
2143
-    /**
2144
-     * _permanently_delete_event
2145
-     *
2146
-     * @access  private
2147
-     * @param  int $EVT_ID
2148
-     * @return bool
2149
-     */
2150
-    private function _permanently_delete_event($EVT_ID = 0)
2151
-    {
2152
-        // grab event id
2153
-        if (! $EVT_ID) {
2154
-            $msg = esc_html__(
2155
-                'An error occurred. No Event ID or an invalid Event ID was received.',
2156
-                'event_espresso'
2157
-            );
2158
-            EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2159
-            return false;
2160
-        }
2161
-        if (! $this->_cpt_model_obj instanceof EE_Event
2162
-            || $this->_cpt_model_obj->ID() !== $EVT_ID
2163
-        ) {
2164
-            $this->_cpt_model_obj = EEM_Event::instance()->get_one_by_ID($EVT_ID);
2165
-        }
2166
-        if (! $this->_cpt_model_obj instanceof EE_Event) {
2167
-            return false;
2168
-        }
2169
-        // need to delete related tickets and prices first.
2170
-        $datetimes = $this->_cpt_model_obj->get_many_related('Datetime');
2171
-        foreach ($datetimes as $datetime) {
2172
-            $this->_cpt_model_obj->_remove_relation_to($datetime, 'Datetime');
2173
-            $tickets = $datetime->get_many_related('Ticket');
2174
-            foreach ($tickets as $ticket) {
2175
-                $ticket->_remove_relation_to($datetime, 'Datetime');
2176
-                $ticket->delete_related_permanently('Price');
2177
-                $ticket->delete_permanently();
2178
-            }
2179
-            $datetime->delete();
2180
-        }
2181
-        // what about related venues or terms?
2182
-        $venues = $this->_cpt_model_obj->get_many_related('Venue');
2183
-        foreach ($venues as $venue) {
2184
-            $this->_cpt_model_obj->_remove_relation_to($venue, 'Venue');
2185
-        }
2186
-        // any attached question groups?
2187
-        $question_groups = $this->_cpt_model_obj->get_many_related('Question_Group');
2188
-        if (! empty($question_groups)) {
2189
-            foreach ($question_groups as $question_group) {
2190
-                $this->_cpt_model_obj->_remove_relation_to($question_group, 'Question_Group');
2191
-            }
2192
-        }
2193
-        // Message Template Groups
2194
-        $this->_cpt_model_obj->_remove_relations('Message_Template_Group');
2195
-        /** @type EE_Term_Taxonomy[] $term_taxonomies */
2196
-        $term_taxonomies = $this->_cpt_model_obj->term_taxonomies();
2197
-        foreach ($term_taxonomies as $term_taxonomy) {
2198
-            $this->_cpt_model_obj->remove_relation_to_term_taxonomy($term_taxonomy);
2199
-        }
2200
-        $success = $this->_cpt_model_obj->delete_permanently();
2201
-        // did it all go as planned ?
2202
-        if ($success) {
2203
-            $msg = sprintf(esc_html__('Event ID # %d has been deleted.', 'event_espresso'), $EVT_ID);
2204
-            EE_Error::add_success($msg);
2205
-        } else {
2206
-            $msg = sprintf(
2207
-                esc_html__('An error occurred. Event ID # %d could not be deleted.', 'event_espresso'),
2208
-                $EVT_ID
2209
-            );
2210
-            EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2211
-            return false;
2212
-        }
2213
-        do_action('AHEE__Events_Admin_Page___permanently_delete_event__after_event_deleted', $EVT_ID);
2214
-        return true;
2215
-    }
2216
-
2217
-
2218
-    /**
2219
-     * get total number of events
2220
-     *
2221
-     * @access public
2222
-     * @return int
2223
-     */
2224
-    public function total_events()
2225
-    {
2226
-        $count = EEM_Event::instance()->count(array('caps' => 'read_admin'), 'EVT_ID', true);
2227
-        return $count;
2228
-    }
2229
-
2230
-
2231
-    /**
2232
-     * get total number of draft events
2233
-     *
2234
-     * @access public
2235
-     * @return int
2236
-     */
2237
-    public function total_events_draft()
2238
-    {
2239
-        $where = array(
2240
-            'status' => array('IN', array('draft', 'auto-draft')),
2241
-        );
2242
-        $count = EEM_Event::instance()->count(array($where, 'caps' => 'read_admin'), 'EVT_ID', true);
2243
-        return $count;
2244
-    }
2245
-
2246
-
2247
-    /**
2248
-     * get total number of trashed events
2249
-     *
2250
-     * @access public
2251
-     * @return int
2252
-     */
2253
-    public function total_trashed_events()
2254
-    {
2255
-        $where = array(
2256
-            'status' => 'trash',
2257
-        );
2258
-        $count = EEM_Event::instance()->count(array($where, 'caps' => 'read_admin'), 'EVT_ID', true);
2259
-        return $count;
2260
-    }
2261
-
2262
-
2263
-    /**
2264
-     *    _default_event_settings
2265
-     *    This generates the Default Settings Tab
2266
-     *
2267
-     * @return void
2268
-     * @throws EE_Error
2269
-     */
2270
-    protected function _default_event_settings()
2271
-    {
2272
-        $this->_set_add_edit_form_tags('update_default_event_settings');
2273
-        $this->_set_publish_post_box_vars(null, false, false, null, false);
2274
-        $this->_template_args['admin_page_content'] = $this->_default_event_settings_form()->get_html();
2275
-        $this->display_admin_page_with_sidebar();
2276
-    }
2277
-
2278
-
2279
-    /**
2280
-     * Return the form for event settings.
2281
-     *
2282
-     * @return EE_Form_Section_Proper
2283
-     * @throws EE_Error
2284
-     */
2285
-    protected function _default_event_settings_form()
2286
-    {
2287
-        $registration_config = EE_Registry::instance()->CFG->registration;
2288
-        $registration_stati_for_selection = EEM_Registration::reg_status_array(
2289
-            // exclude
2290
-            array(
2291
-                EEM_Registration::status_id_cancelled,
2292
-                EEM_Registration::status_id_declined,
2293
-                EEM_Registration::status_id_incomplete,
2294
-                EEM_Registration::status_id_wait_list,
2295
-            ),
2296
-            true
2297
-        );
2298
-        return new EE_Form_Section_Proper(
2299
-            array(
2300
-                'name'            => 'update_default_event_settings',
2301
-                'html_id'         => 'update_default_event_settings',
2302
-                'html_class'      => 'form-table',
2303
-                'layout_strategy' => new EE_Admin_Two_Column_Layout(),
2304
-                'subsections'     => apply_filters(
2305
-                    'FHEE__Events_Admin_Page___default_event_settings_form__form_subsections',
2306
-                    array(
2307
-                        'default_reg_status'  => new EE_Select_Input(
2308
-                            $registration_stati_for_selection,
2309
-                            array(
2310
-                                'default'         => isset($registration_config->default_STS_ID)
2311
-                                                     && array_key_exists(
2312
-                                                         $registration_config->default_STS_ID,
2313
-                                                         $registration_stati_for_selection
2314
-                                                     )
2315
-                                    ? sanitize_text_field($registration_config->default_STS_ID)
2316
-                                    : EEM_Registration::status_id_pending_payment,
2317
-                                'html_label_text' => esc_html__('Default Registration Status', 'event_espresso')
2318
-                                                     . EEH_Template::get_help_tab_link(
2319
-                                                         'default_settings_status_help_tab'
2320
-                                                     ),
2321
-                                'html_help_text'  => esc_html__(
2322
-                                    'This setting allows you to preselect what the default registration status setting is when creating an event.  Note that changing this setting does NOT retroactively apply it to existing events.',
2323
-                                    'event_espresso'
2324
-                                ),
2325
-                            )
2326
-                        ),
2327
-                        'default_max_tickets' => new EE_Integer_Input(
2328
-                            array(
2329
-                                'default'         => isset($registration_config->default_maximum_number_of_tickets)
2330
-                                    ? $registration_config->default_maximum_number_of_tickets
2331
-                                    : EEM_Event::get_default_additional_limit(),
2332
-                                'html_label_text' => esc_html__(
2333
-                                    'Default Maximum Tickets Allowed Per Order:',
2334
-                                    'event_espresso'
2335
-                                )
2336
-                                                     . EEH_Template::get_help_tab_link(
2337
-                                                         'default_maximum_tickets_help_tab"'
2338
-                                                     ),
2339
-                                'html_help_text'  => esc_html__(
2340
-                                    'This setting allows you to indicate what will be the default for the maximum number of tickets per order when creating new events.',
2341
-                                    'event_espresso'
2342
-                                ),
2343
-                            )
2344
-                        ),
2345
-                    )
2346
-                ),
2347
-            )
2348
-        );
2349
-    }
2350
-
2351
-
2352
-    /**
2353
-     * _update_default_event_settings
2354
-     *
2355
-     * @access protected
2356
-     * @return void
2357
-     * @throws EE_Error
2358
-     */
2359
-    protected function _update_default_event_settings()
2360
-    {
2361
-        $registration_config = EE_Registry::instance()->CFG->registration;
2362
-        $form = $this->_default_event_settings_form();
2363
-        if ($form->was_submitted()) {
2364
-            $form->receive_form_submission();
2365
-            if ($form->is_valid()) {
2366
-                $valid_data = $form->valid_data();
2367
-                if (isset($valid_data['default_reg_status'])) {
2368
-                    $registration_config->default_STS_ID = $valid_data['default_reg_status'];
2369
-                }
2370
-                if (isset($valid_data['default_max_tickets'])) {
2371
-                    $registration_config->default_maximum_number_of_tickets = $valid_data['default_max_tickets'];
2372
-                }
2373
-                // update because data was valid!
2374
-                EE_Registry::instance()->CFG->update_espresso_config();
2375
-                EE_Error::overwrite_success();
2376
-                EE_Error::add_success(
2377
-                    __('Default Event Settings were updated', 'event_espresso')
2378
-                );
2379
-            }
2380
-        }
2381
-        $this->_redirect_after_action(0, '', '', array('action' => 'default_event_settings'), true);
2382
-    }
2383
-
2384
-
2385
-    /*************        Templates        *************/
2386
-    protected function _template_settings()
2387
-    {
2388
-        $this->_admin_page_title = esc_html__('Template Settings (Preview)', 'event_espresso');
2389
-        $this->_template_args['preview_img'] = '<img src="'
2390
-                                               . EVENTS_ASSETS_URL
2391
-                                               . DS
2392
-                                               . 'images'
2393
-                                               . DS
2394
-                                               . 'caffeinated_template_features.jpg" alt="'
2395
-                                               . esc_attr__('Template Settings Preview screenshot', 'event_espresso')
2396
-                                               . '" />';
2397
-        $this->_template_args['preview_text'] = '<strong>'
2398
-                                                . esc_html__(
2399
-                                                    'Template Settings is a feature that is only available in the premium version of Event Espresso 4 which is available with a support license purchase on EventEspresso.com. Template Settings allow you to configure some of the appearance options for both the Event List and Event Details pages.',
2400
-                                                    'event_espresso'
2401
-                                                ) . '</strong>';
2402
-        $this->display_admin_caf_preview_page('template_settings_tab');
2403
-    }
2404
-
2405
-
2406
-    /** Event Category Stuff **/
2407
-    /**
2408
-     * set the _category property with the category object for the loaded page.
2409
-     *
2410
-     * @access private
2411
-     * @return void
2412
-     */
2413
-    private function _set_category_object()
2414
-    {
2415
-        if (isset($this->_category->id) && ! empty($this->_category->id)) {
2416
-            return;
2417
-        } //already have the category object so get out.
2418
-        // set default category object
2419
-        $this->_set_empty_category_object();
2420
-        // only set if we've got an id
2421
-        if (! isset($this->_req_data['EVT_CAT_ID'])) {
2422
-            return;
2423
-        }
2424
-        $category_id = absint($this->_req_data['EVT_CAT_ID']);
2425
-        $term = get_term($category_id, EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY);
2426
-        if (! empty($term)) {
2427
-            $this->_category->category_name = $term->name;
2428
-            $this->_category->category_identifier = $term->slug;
2429
-            $this->_category->category_desc = $term->description;
2430
-            $this->_category->id = $term->term_id;
2431
-            $this->_category->parent = $term->parent;
2432
-        }
2433
-    }
2434
-
2435
-
2436
-    /**
2437
-     * Clears out category properties.
2438
-     */
2439
-    private function _set_empty_category_object()
2440
-    {
2441
-        $this->_category = new stdClass();
2442
-        $this->_category->category_name = $this->_category->category_identifier = $this->_category->category_desc = '';
2443
-        $this->_category->id = $this->_category->parent = 0;
2444
-    }
2445
-
2446
-
2447
-    /**
2448
-     * @throws EE_Error
2449
-     */
2450
-    protected function _category_list_table()
2451
-    {
2452
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
2453
-        $this->_search_btn_label = esc_html__('Categories', 'event_espresso');
2454
-        $this->_admin_page_title .= ' ' . $this->get_action_link_or_button(
2455
-            'add_category',
2456
-            'add_category',
2457
-            array(),
2458
-            'add-new-h2'
2459
-        );
2460
-        $this->display_admin_list_table_page_with_sidebar();
2461
-    }
2462
-
2463
-
2464
-    /**
2465
-     * Output category details view.
2466
-     */
2467
-    protected function _category_details($view)
2468
-    {
2469
-        // load formatter helper
2470
-        // load field generator helper
2471
-        $route = $view == 'edit' ? 'update_category' : 'insert_category';
2472
-        $this->_set_add_edit_form_tags($route);
2473
-        $this->_set_category_object();
2474
-        $id = ! empty($this->_category->id) ? $this->_category->id : '';
2475
-        $delete_action = 'delete_category';
2476
-        // custom redirect
2477
-        $redirect = EE_Admin_Page::add_query_args_and_nonce(
2478
-            array('action' => 'category_list'),
2479
-            $this->_admin_base_url
2480
-        );
2481
-        $this->_set_publish_post_box_vars('EVT_CAT_ID', $id, $delete_action, $redirect);
2482
-        // take care of contents
2483
-        $this->_template_args['admin_page_content'] = $this->_category_details_content();
2484
-        $this->display_admin_page_with_sidebar();
2485
-    }
2486
-
2487
-
2488
-    /**
2489
-     * Output category details content.
2490
-     */
2491
-    protected function _category_details_content()
2492
-    {
2493
-        $editor_args['category_desc'] = array(
2494
-            'type'          => 'wp_editor',
2495
-            'value'         => EEH_Formatter::admin_format_content($this->_category->category_desc),
2496
-            'class'         => 'my_editor_custom',
2497
-            'wpeditor_args' => array('media_buttons' => false),
2498
-        );
2499
-        $_wp_editor = $this->_generate_admin_form_fields($editor_args, 'array');
2500
-        $all_terms = get_terms(
2501
-            array(EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY),
2502
-            array('hide_empty' => 0, 'exclude' => array($this->_category->id))
2503
-        );
2504
-        // setup category select for term parents.
2505
-        $category_select_values[] = array(
2506
-            'text' => esc_html__('No Parent', 'event_espresso'),
2507
-            'id'   => 0,
2508
-        );
2509
-        foreach ($all_terms as $term) {
2510
-            $category_select_values[] = array(
2511
-                'text' => $term->name,
2512
-                'id'   => $term->term_id,
2513
-            );
2514
-        }
2515
-        $category_select = EEH_Form_Fields::select_input(
2516
-            'category_parent',
2517
-            $category_select_values,
2518
-            $this->_category->parent
2519
-        );
2520
-        $template_args = array(
2521
-            'category'                 => $this->_category,
2522
-            'category_select'          => $category_select,
2523
-            'unique_id_info_help_link' => $this->_get_help_tab_link('unique_id_info'),
2524
-            'category_desc_editor'     => $_wp_editor['category_desc']['field'],
2525
-            'disable'                  => '',
2526
-            'disabled_message'         => false,
2527
-        );
2528
-        $template = EVENTS_TEMPLATE_PATH . 'event_category_details.template.php';
2529
-        return EEH_Template::display_template($template, $template_args, true);
2530
-    }
2531
-
2532
-
2533
-    /**
2534
-     * Handles deleting categories.
2535
-     */
2536
-    protected function _delete_categories()
2537
-    {
2538
-        $cat_ids = isset($this->_req_data['EVT_CAT_ID']) ? (array) $this->_req_data['EVT_CAT_ID']
2539
-            : (array) $this->_req_data['category_id'];
2540
-        foreach ($cat_ids as $cat_id) {
2541
-            $this->_delete_category($cat_id);
2542
-        }
2543
-        // doesn't matter what page we're coming from... we're going to the same place after delete.
2544
-        $query_args = array(
2545
-            'action' => 'category_list',
2546
-        );
2547
-        $this->_redirect_after_action(0, '', '', $query_args);
2548
-    }
2549
-
2550
-
2551
-    /**
2552
-     * Handles deleting specific category.
2553
-     *
2554
-     * @param int $cat_id
2555
-     */
2556
-    protected function _delete_category($cat_id)
2557
-    {
2558
-        $cat_id = absint($cat_id);
2559
-        wp_delete_term($cat_id, EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY);
2560
-    }
2561
-
2562
-
2563
-    /**
2564
-     * Handles triggering the update or insertion of a new category.
2565
-     *
2566
-     * @param bool $new_category true means we're triggering the insert of a new category.
2567
-     */
2568
-    protected function _insert_or_update_category($new_category)
2569
-    {
2570
-        $cat_id = $new_category ? $this->_insert_category() : $this->_insert_category(true);
2571
-        $success = 0; // we already have a success message so lets not send another.
2572
-        if ($cat_id) {
2573
-            $query_args = array(
2574
-                'action'     => 'edit_category',
2575
-                'EVT_CAT_ID' => $cat_id,
2576
-            );
2577
-        } else {
2578
-            $query_args = array('action' => 'add_category');
2579
-        }
2580
-        $this->_redirect_after_action($success, '', '', $query_args, true);
2581
-    }
2582
-
2583
-
2584
-    /**
2585
-     * Inserts or updates category
2586
-     *
2587
-     * @param bool $update (true indicates we're updating a category).
2588
-     * @return bool|mixed|string
2589
-     */
2590
-    private function _insert_category($update = false)
2591
-    {
2592
-        $cat_id = $update ? $this->_req_data['EVT_CAT_ID'] : '';
2593
-        $category_name = isset($this->_req_data['category_name']) ? $this->_req_data['category_name'] : '';
2594
-        $category_desc = isset($this->_req_data['category_desc']) ? $this->_req_data['category_desc'] : '';
2595
-        $category_parent = isset($this->_req_data['category_parent']) ? $this->_req_data['category_parent'] : 0;
2596
-        if (empty($category_name)) {
2597
-            $msg = esc_html__('You must add a name for the category.', 'event_espresso');
2598
-            EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2599
-            return false;
2600
-        }
2601
-        $term_args = array(
2602
-            'name'        => $category_name,
2603
-            'description' => $category_desc,
2604
-            'parent'      => $category_parent,
2605
-        );
2606
-        // was the category_identifier input disabled?
2607
-        if (isset($this->_req_data['category_identifier'])) {
2608
-            $term_args['slug'] = $this->_req_data['category_identifier'];
2609
-        }
2610
-        $insert_ids = $update
2611
-            ? wp_update_term($cat_id, EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY, $term_args)
2612
-            : wp_insert_term($category_name, EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY, $term_args);
2613
-        if (! is_array($insert_ids)) {
2614
-            $msg = esc_html__(
2615
-                'An error occurred and the category has not been saved to the database.',
2616
-                'event_espresso'
2617
-            );
2618
-            EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2619
-        } else {
2620
-            $cat_id = $insert_ids['term_id'];
2621
-            $msg = sprintf(esc_html__('The category %s was successfully saved', 'event_espresso'), $category_name);
2622
-            EE_Error::add_success($msg);
2623
-        }
2624
-        return $cat_id;
2625
-    }
2626
-
2627
-
2628
-    /**
2629
-     * Gets categories or count of categories matching the arguments in the request.
2630
-     *
2631
-     * @param int  $per_page
2632
-     * @param int  $current_page
2633
-     * @param bool $count
2634
-     * @return EE_Base_Class[]|EE_Term_Taxonomy[]|int
2635
-     */
2636
-    public function get_categories($per_page = 10, $current_page = 1, $count = false)
2637
-    {
2638
-        // testing term stuff
2639
-        $orderby = isset($this->_req_data['orderby']) ? $this->_req_data['orderby'] : 'Term.term_id';
2640
-        $order = isset($this->_req_data['order']) ? $this->_req_data['order'] : 'DESC';
2641
-        $limit = ($current_page - 1) * $per_page;
2642
-        $where = array('taxonomy' => EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY);
2643
-        if (isset($this->_req_data['s'])) {
2644
-            $sstr = '%' . $this->_req_data['s'] . '%';
2645
-            $where['OR'] = array(
2646
-                'Term.name'   => array('LIKE', $sstr),
2647
-                'description' => array('LIKE', $sstr),
2648
-            );
2649
-        }
2650
-        $query_params = array(
2651
-            $where,
2652
-            'order_by'   => array($orderby => $order),
2653
-            'limit'      => $limit . ',' . $per_page,
2654
-            'force_join' => array('Term'),
2655
-        );
2656
-        $categories = $count
2657
-            ? EEM_Term_Taxonomy::instance()->count($query_params, 'term_id')
2658
-            : EEM_Term_Taxonomy::instance()->get_all($query_params);
2659
-        return $categories;
2660
-    }
2661
-
2662
-    /* end category stuff */
2663
-    /**************/
2664
-
2665
-
2666
-    /**
2667
-     * Callback for the `ee_save_timezone_setting` ajax action.
2668
-     *
2669
-     * @throws EE_Error
2670
-     */
2671
-    public function save_timezonestring_setting()
2672
-    {
2673
-        $timezone_string = isset($this->_req_data['timezone_selected'])
2674
-            ? $this->_req_data['timezone_selected']
2675
-            : '';
2676
-        if (empty($timezone_string) || ! EEH_DTT_Helper::validate_timezone($timezone_string, false)) {
2677
-            EE_Error::add_error(
2678
-                esc_html__('An invalid timezone string submitted.', 'event_espresso'),
2679
-                __FILE__,
2680
-                __FUNCTION__,
2681
-                __LINE__
2682
-            );
2683
-            $this->_template_args['error'] = true;
2684
-            $this->_return_json();
2685
-        }
2686
-
2687
-        update_option('timezone_string', $timezone_string);
2688
-        EE_Error::add_success(
2689
-            esc_html__('Your timezone string was updated.', 'event_espresso')
2690
-        );
2691
-        $this->_template_args['success'] = true;
2692
-        $this->_return_json(true, array('action' => 'create_new'));
2693
-    }
577
+				}
578
+			}
579
+		);
580
+	}
581
+
582
+
583
+	/**
584
+	 * Enqueuing scripts and styles specific to this view
585
+	 */
586
+	public function load_scripts_styles_create_new()
587
+	{
588
+		$this->load_scripts_styles_edit();
589
+	}
590
+
591
+
592
+	/**
593
+	 * Enqueuing scripts and styles specific to this view
594
+	 */
595
+	public function load_scripts_styles_edit()
596
+	{
597
+		// styles
598
+		wp_enqueue_style('espresso-ui-theme');
599
+		wp_register_style(
600
+			'event-editor-css',
601
+			EVENTS_ASSETS_URL . 'event-editor.css',
602
+			array('ee-admin-css'),
603
+			EVENT_ESPRESSO_VERSION
604
+		);
605
+		wp_enqueue_style('event-editor-css');
606
+		// scripts
607
+		wp_register_script(
608
+			'event-datetime-metabox',
609
+			EVENTS_ASSETS_URL . 'event-datetime-metabox.js',
610
+			array('event_editor_js', 'ee-datepicker'),
611
+			EVENT_ESPRESSO_VERSION
612
+		);
613
+		wp_enqueue_script('event-datetime-metabox');
614
+	}
615
+
616
+
617
+	/**
618
+	 * Populating the _views property for the category list table view.
619
+	 */
620
+	protected function _set_list_table_views_category_list()
621
+	{
622
+		$this->_views = array(
623
+			'all' => array(
624
+				'slug'        => 'all',
625
+				'label'       => esc_html__('All', 'event_espresso'),
626
+				'count'       => 0,
627
+				'bulk_action' => array(
628
+					'delete_categories' => esc_html__('Delete Permanently', 'event_espresso'),
629
+				),
630
+			),
631
+		);
632
+	}
633
+
634
+
635
+	/**
636
+	 * For adding anything that fires on the admin_init hook for any route within this admin page group.
637
+	 */
638
+	public function admin_init()
639
+	{
640
+		EE_Registry::$i18n_js_strings['image_confirm'] = esc_html__(
641
+			'Do you really want to delete this image? Please remember to update your event to complete the removal.',
642
+			'event_espresso'
643
+		);
644
+	}
645
+
646
+
647
+	/**
648
+	 * For adding anything that should be triggered on the admin_notices hook for any route within this admin page
649
+	 * group.
650
+	 */
651
+	public function admin_notices()
652
+	{
653
+	}
654
+
655
+
656
+	/**
657
+	 * For adding anything that should be triggered on the `admin_print_footer_scripts` hook for any route within
658
+	 * this admin page group.
659
+	 */
660
+	public function admin_footer_scripts()
661
+	{
662
+	}
663
+
664
+
665
+	/**
666
+	 * Call this function to verify if an event is public and has tickets for sale.  If it does, then we need to show a
667
+	 * warning (via EE_Error::add_error());
668
+	 *
669
+	 * @param  EE_Event $event Event object
670
+	 * @param string    $req_type
671
+	 * @return void
672
+	 * @throws EE_Error
673
+	 * @access public
674
+	 */
675
+	public function verify_event_edit($event = null, $req_type = '')
676
+	{
677
+		// don't need to do this when processing
678
+		if (! empty($req_type)) {
679
+			return;
680
+		}
681
+		// no event?
682
+		if (empty($event)) {
683
+			// set event
684
+			$event = $this->_cpt_model_obj;
685
+		}
686
+		// STILL no event?
687
+		if (! $event instanceof EE_Event) {
688
+			return;
689
+		}
690
+		$orig_status = $event->status();
691
+		// first check if event is active.
692
+		if ($orig_status === EEM_Event::cancelled
693
+			|| $orig_status === EEM_Event::postponed
694
+			|| $event->is_expired()
695
+			|| $event->is_inactive()
696
+		) {
697
+			return;
698
+		}
699
+		// made it here so it IS active... next check that any of the tickets are sold.
700
+		if ($event->is_sold_out(true)) {
701
+			if ($orig_status !== EEM_Event::sold_out && $event->status() !== $orig_status) {
702
+				EE_Error::add_attention(
703
+					sprintf(
704
+						esc_html__(
705
+							'Please note that the Event Status has automatically been changed to %s because there are no more spaces available for this event.  However, this change is not permanent until you update the event.  You can change the status back to something else before updating if you wish.',
706
+							'event_espresso'
707
+						),
708
+						EEH_Template::pretty_status(EEM_Event::sold_out, false, 'sentence')
709
+					)
710
+				);
711
+			}
712
+			return;
713
+		} elseif ($orig_status === EEM_Event::sold_out) {
714
+			EE_Error::add_attention(
715
+				sprintf(
716
+					esc_html__(
717
+						'Please note that the Event Status has automatically been changed to %s because more spaces have become available for this event, most likely due to abandoned transactions freeing up reserved tickets.  However, this change is not permanent until you update the event. If you wish, you can change the status back to something else before updating.',
718
+						'event_espresso'
719
+					),
720
+					EEH_Template::pretty_status($event->status(), false, 'sentence')
721
+				)
722
+			);
723
+		}
724
+		// now we need to determine if the event has any tickets on sale.  If not then we dont' show the error
725
+		if (! $event->tickets_on_sale()) {
726
+			return;
727
+		}
728
+		// made it here so show warning
729
+		$this->_edit_event_warning();
730
+	}
731
+
732
+
733
+	/**
734
+	 * This is the text used for when an event is being edited that is public and has tickets for sale.
735
+	 * When needed, hook this into a EE_Error::add_error() notice.
736
+	 *
737
+	 * @access protected
738
+	 * @return void
739
+	 */
740
+	protected function _edit_event_warning()
741
+	{
742
+		// we don't want to add warnings during these requests
743
+		if (isset($this->_req_data['action']) && $this->_req_data['action'] === 'editpost') {
744
+			return;
745
+		}
746
+		EE_Error::add_attention(
747
+			sprintf(
748
+				esc_html__(
749
+					'Your event is open for registration. Making changes may disrupt any transactions in progress. %sLearn more%s',
750
+					'event_espresso'
751
+				),
752
+				'<a class="espresso-help-tab-lnk">',
753
+				'</a>'
754
+			)
755
+		);
756
+	}
757
+
758
+
759
+	/**
760
+	 * When a user is creating a new event, notify them if they haven't set their timezone.
761
+	 * Otherwise, do the normal logic
762
+	 *
763
+	 * @return string
764
+	 * @throws \EE_Error
765
+	 */
766
+	protected function _create_new_cpt_item()
767
+	{
768
+		$has_timezone_string = get_option('timezone_string');
769
+		// only nag them about setting their timezone if it's their first event, and they haven't already done it
770
+		if (! $has_timezone_string && ! EEM_Event::instance()->exists(array())) {
771
+			EE_Error::add_attention(
772
+				sprintf(
773
+					__(
774
+						'Your website\'s timezone is currently set to a UTC offset. We recommend updating your timezone to a city or region near you before you create an event. Change your timezone now:%1$s%2$s%3$sChange Timezone%4$s',
775
+						'event_espresso'
776
+					),
777
+					'<br>',
778
+					'<select id="timezone_string" name="timezone_string" aria-describedby="timezone-description">'
779
+					. EEH_DTT_Helper::wp_timezone_choice('', EEH_DTT_Helper::get_user_locale())
780
+					. '</select>',
781
+					'<button class="button button-secondary timezone-submit">',
782
+					'</button><span class="spinner"></span>'
783
+				),
784
+				__FILE__,
785
+				__FUNCTION__,
786
+				__LINE__
787
+			);
788
+		}
789
+		return parent::_create_new_cpt_item();
790
+	}
791
+
792
+
793
+	/**
794
+	 * Sets the _views property for the default route in this admin page group.
795
+	 */
796
+	protected function _set_list_table_views_default()
797
+	{
798
+		$this->_views = array(
799
+			'all'   => array(
800
+				'slug'        => 'all',
801
+				'label'       => esc_html__('View All Events', 'event_espresso'),
802
+				'count'       => 0,
803
+				'bulk_action' => array(
804
+					'trash_events' => esc_html__('Move to Trash', 'event_espresso'),
805
+				),
806
+			),
807
+			'draft' => array(
808
+				'slug'        => 'draft',
809
+				'label'       => esc_html__('Draft', 'event_espresso'),
810
+				'count'       => 0,
811
+				'bulk_action' => array(
812
+					'trash_events' => esc_html__('Move to Trash', 'event_espresso'),
813
+				),
814
+			),
815
+		);
816
+		if (EE_Registry::instance()->CAP->current_user_can('ee_delete_events', 'espresso_events_trash_events')) {
817
+			$this->_views['trash'] = array(
818
+				'slug'        => 'trash',
819
+				'label'       => esc_html__('Trash', 'event_espresso'),
820
+				'count'       => 0,
821
+				'bulk_action' => array(
822
+					'restore_events' => esc_html__('Restore From Trash', 'event_espresso'),
823
+					'delete_events'  => esc_html__('Delete Permanently', 'event_espresso'),
824
+				),
825
+			);
826
+		}
827
+	}
828
+
829
+
830
+	/**
831
+	 * Provides the legend item array for the default list table view.
832
+	 *
833
+	 * @return array
834
+	 */
835
+	protected function _event_legend_items()
836
+	{
837
+		$items = array(
838
+			'view_details'   => array(
839
+				'class' => 'dashicons dashicons-search',
840
+				'desc'  => esc_html__('View Event', 'event_espresso'),
841
+			),
842
+			'edit_event'     => array(
843
+				'class' => 'ee-icon ee-icon-calendar-edit',
844
+				'desc'  => esc_html__('Edit Event Details', 'event_espresso'),
845
+			),
846
+			'view_attendees' => array(
847
+				'class' => 'dashicons dashicons-groups',
848
+				'desc'  => esc_html__('View Registrations for Event', 'event_espresso'),
849
+			),
850
+		);
851
+		$items = apply_filters('FHEE__Events_Admin_Page___event_legend_items__items', $items);
852
+		$statuses = array(
853
+			'sold_out_status'  => array(
854
+				'class' => 'ee-status-legend ee-status-legend-' . EE_Datetime::sold_out,
855
+				'desc'  => EEH_Template::pretty_status(EE_Datetime::sold_out, false, 'sentence'),
856
+			),
857
+			'active_status'    => array(
858
+				'class' => 'ee-status-legend ee-status-legend-' . EE_Datetime::active,
859
+				'desc'  => EEH_Template::pretty_status(EE_Datetime::active, false, 'sentence'),
860
+			),
861
+			'upcoming_status'  => array(
862
+				'class' => 'ee-status-legend ee-status-legend-' . EE_Datetime::upcoming,
863
+				'desc'  => EEH_Template::pretty_status(EE_Datetime::upcoming, false, 'sentence'),
864
+			),
865
+			'postponed_status' => array(
866
+				'class' => 'ee-status-legend ee-status-legend-' . EE_Datetime::postponed,
867
+				'desc'  => EEH_Template::pretty_status(EE_Datetime::postponed, false, 'sentence'),
868
+			),
869
+			'cancelled_status' => array(
870
+				'class' => 'ee-status-legend ee-status-legend-' . EE_Datetime::cancelled,
871
+				'desc'  => EEH_Template::pretty_status(EE_Datetime::cancelled, false, 'sentence'),
872
+			),
873
+			'expired_status'   => array(
874
+				'class' => 'ee-status-legend ee-status-legend-' . EE_Datetime::expired,
875
+				'desc'  => EEH_Template::pretty_status(EE_Datetime::expired, false, 'sentence'),
876
+			),
877
+			'inactive_status'  => array(
878
+				'class' => 'ee-status-legend ee-status-legend-' . EE_Datetime::inactive,
879
+				'desc'  => EEH_Template::pretty_status(EE_Datetime::inactive, false, 'sentence'),
880
+			),
881
+		);
882
+		$statuses = apply_filters('FHEE__Events_Admin_Page__event_legend_items__statuses', $statuses);
883
+		return array_merge($items, $statuses);
884
+	}
885
+
886
+
887
+	/**
888
+	 * @return EEM_Event
889
+	 */
890
+	private function _event_model()
891
+	{
892
+		if (! $this->_event_model instanceof EEM_Event) {
893
+			$this->_event_model = EE_Registry::instance()->load_model('Event');
894
+		}
895
+		return $this->_event_model;
896
+	}
897
+
898
+
899
+	/**
900
+	 * Adds extra buttons to the WP CPT permalink field row.
901
+	 * Method is called from parent and is hooked into the wp 'get_sample_permalink_html' filter.
902
+	 *
903
+	 * @param  string $return    the current html
904
+	 * @param  int    $id        the post id for the page
905
+	 * @param  string $new_title What the title is
906
+	 * @param  string $new_slug  what the slug is
907
+	 * @return string            The new html string for the permalink area
908
+	 */
909
+	public function extra_permalink_field_buttons($return, $id, $new_title, $new_slug)
910
+	{
911
+		// make sure this is only when editing
912
+		if (! empty($id)) {
913
+			$post = get_post($id);
914
+			$return .= '<a class="button button-small" onclick="prompt(\'Shortcode:\', jQuery(\'#shortcode\').val()); return false;" href="#"  tabindex="-1">'
915
+					   . esc_html__('Shortcode', 'event_espresso')
916
+					   . '</a> ';
917
+			$return .= '<input id="shortcode" type="hidden" value="[ESPRESSO_TICKET_SELECTOR event_id='
918
+					   . $post->ID
919
+					   . ']">';
920
+		}
921
+		return $return;
922
+	}
923
+
924
+
925
+	/**
926
+	 * _events_overview_list_table
927
+	 * This contains the logic for showing the events_overview list
928
+	 *
929
+	 * @access protected
930
+	 * @return void
931
+	 * @throws \EE_Error
932
+	 */
933
+	protected function _events_overview_list_table()
934
+	{
935
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
936
+		$this->_template_args['after_list_table'] = ! empty($this->_template_args['after_list_table'])
937
+			? (array) $this->_template_args['after_list_table']
938
+			: array();
939
+		$this->_template_args['after_list_table']['view_event_list_button'] = EEH_HTML::br()
940
+				. EEH_Template::get_button_or_link(
941
+					get_post_type_archive_link('espresso_events'),
942
+					esc_html__("View Event Archive Page", "event_espresso"),
943
+					'button'
944
+				);
945
+		$this->_template_args['after_list_table']['legend'] = $this->_display_legend($this->_event_legend_items());
946
+		$this->_admin_page_title .= ' ' . $this->get_action_link_or_button(
947
+			'create_new',
948
+			'add',
949
+			array(),
950
+			'add-new-h2'
951
+		);
952
+		$this->display_admin_list_table_page_with_no_sidebar();
953
+	}
954
+
955
+
956
+	/**
957
+	 * this allows for extra misc actions in the default WP publish box
958
+	 *
959
+	 * @return void
960
+	 */
961
+	public function extra_misc_actions_publish_box()
962
+	{
963
+		$this->_generate_publish_box_extra_content();
964
+	}
965
+
966
+
967
+	/**
968
+	 * This is hooked into the WordPress do_action('save_post') hook and runs after the custom post type has been
969
+	 * saved.
970
+	 * Typically you would use this to save any additional data.
971
+	 * Keep in mind also that "save_post" runs on EVERY post update to the database.
972
+	 * ALSO very important.  When a post transitions from scheduled to published,
973
+	 * the save_post action is fired but you will NOT have any _POST data containing any extra info you may have from
974
+	 * other meta saves. So MAKE sure that you handle this accordingly.
975
+	 *
976
+	 * @access protected
977
+	 * @abstract
978
+	 * @param  string $post_id The ID of the cpt that was saved (so you can link relationally)
979
+	 * @param  object $post    The post object of the cpt that was saved.
980
+	 * @return void
981
+	 * @throws \EE_Error
982
+	 */
983
+	protected function _insert_update_cpt_item($post_id, $post)
984
+	{
985
+		if ($post instanceof WP_Post && $post->post_type !== 'espresso_events') {
986
+			// get out we're not processing an event save.
987
+			return;
988
+		}
989
+		$event_values = array(
990
+			'EVT_display_desc'                => ! empty($this->_req_data['display_desc']) ? 1 : 0,
991
+			'EVT_display_ticket_selector'     => ! empty($this->_req_data['display_ticket_selector']) ? 1 : 0,
992
+			'EVT_additional_limit'            => min(
993
+				apply_filters('FHEE__EE_Events_Admin__insert_update_cpt_item__EVT_additional_limit_max', 255),
994
+				! empty($this->_req_data['additional_limit']) ? $this->_req_data['additional_limit'] : null
995
+			),
996
+			'EVT_default_registration_status' => ! empty($this->_req_data['EVT_default_registration_status'])
997
+				? $this->_req_data['EVT_default_registration_status']
998
+				: EE_Registry::instance()->CFG->registration->default_STS_ID,
999
+			'EVT_member_only'                 => ! empty($this->_req_data['member_only']) ? 1 : 0,
1000
+			'EVT_allow_overflow'              => ! empty($this->_req_data['EVT_allow_overflow']) ? 1 : 0,
1001
+			'EVT_timezone_string'             => ! empty($this->_req_data['timezone_string'])
1002
+				? $this->_req_data['timezone_string'] : null,
1003
+			'EVT_external_URL'                => ! empty($this->_req_data['externalURL'])
1004
+				? $this->_req_data['externalURL'] : null,
1005
+			'EVT_phone'                       => ! empty($this->_req_data['event_phone'])
1006
+				? $this->_req_data['event_phone'] : null,
1007
+		);
1008
+		// update event
1009
+		$success = $this->_event_model()->update_by_ID($event_values, $post_id);
1010
+		// get event_object for other metaboxes... though it would seem to make sense to just use $this->_event_model()->get_one_by_ID( $post_id ).. i have to setup where conditions to override the filters in the model that filter out autodraft and inherit statuses so we GET the inherit id!
1011
+		$get_one_where = array(
1012
+			$this->_event_model()->primary_key_name() => $post_id,
1013
+			'OR'                                      => array(
1014
+				'status'   => $post->post_status,
1015
+				// if trying to "Publish" a sold out event, it's status will get switched back to "sold_out" in the db,
1016
+				// but the returned object here has a status of "publish", so use the original post status as well
1017
+				'status*1' => $this->_req_data['original_post_status'],
1018
+			),
1019
+		);
1020
+		$event = $this->_event_model()->get_one(array($get_one_where));
1021
+		// the following are default callbacks for event attachment updates that can be overridden by caffeinated functionality and/or addons.
1022
+		$event_update_callbacks = apply_filters(
1023
+			'FHEE__Events_Admin_Page___insert_update_cpt_item__event_update_callbacks',
1024
+			array(
1025
+				array($this, '_default_venue_update'),
1026
+				array($this, '_default_tickets_update'),
1027
+			)
1028
+		);
1029
+		$att_success = true;
1030
+		foreach ($event_update_callbacks as $e_callback) {
1031
+			$_success = is_callable($e_callback)
1032
+				? call_user_func($e_callback, $event, $this->_req_data)
1033
+				: false;
1034
+			// if ANY of these updates fail then we want the appropriate global error message
1035
+			$att_success = ! $att_success ? $att_success : $_success;
1036
+		}
1037
+		// any errors?
1038
+		if ($success && false === $att_success) {
1039
+			EE_Error::add_error(
1040
+				esc_html__(
1041
+					'Event Details saved successfully but something went wrong with saving attachments.',
1042
+					'event_espresso'
1043
+				),
1044
+				__FILE__,
1045
+				__FUNCTION__,
1046
+				__LINE__
1047
+			);
1048
+		} elseif ($success === false) {
1049
+			EE_Error::add_error(
1050
+				esc_html__('Event Details did not save successfully.', 'event_espresso'),
1051
+				__FILE__,
1052
+				__FUNCTION__,
1053
+				__LINE__
1054
+			);
1055
+		}
1056
+	}
1057
+
1058
+
1059
+	/**
1060
+	 * @see parent::restore_item()
1061
+	 * @param int $post_id
1062
+	 * @param int $revision_id
1063
+	 */
1064
+	protected function _restore_cpt_item($post_id, $revision_id)
1065
+	{
1066
+		// copy existing event meta to new post
1067
+		$post_evt = $this->_event_model()->get_one_by_ID($post_id);
1068
+		if ($post_evt instanceof EE_Event) {
1069
+			// meta revision restore
1070
+			$post_evt->restore_revision($revision_id);
1071
+			// related objs restore
1072
+			$post_evt->restore_revision($revision_id, array('Venue', 'Datetime', 'Price'));
1073
+		}
1074
+	}
1075
+
1076
+
1077
+	/**
1078
+	 * Attach the venue to the Event
1079
+	 *
1080
+	 * @param  \EE_Event $evtobj Event Object to add the venue to
1081
+	 * @param  array     $data   The request data from the form
1082
+	 * @return bool           Success or fail.
1083
+	 */
1084
+	protected function _default_venue_update(\EE_Event $evtobj, $data)
1085
+	{
1086
+		require_once(EE_MODELS . 'EEM_Venue.model.php');
1087
+		$venue_model = EE_Registry::instance()->load_model('Venue');
1088
+		$rows_affected = null;
1089
+		$venue_id = ! empty($data['venue_id']) ? $data['venue_id'] : null;
1090
+		// very important.  If we don't have a venue name...
1091
+		// then we'll get out because not necessary to create empty venue
1092
+		if (empty($data['venue_title'])) {
1093
+			return false;
1094
+		}
1095
+		$venue_array = array(
1096
+			'VNU_wp_user'         => $evtobj->get('EVT_wp_user'),
1097
+			'VNU_name'            => ! empty($data['venue_title']) ? $data['venue_title'] : null,
1098
+			'VNU_desc'            => ! empty($data['venue_description']) ? $data['venue_description'] : null,
1099
+			'VNU_identifier'      => ! empty($data['venue_identifier']) ? $data['venue_identifier'] : null,
1100
+			'VNU_short_desc'      => ! empty($data['venue_short_description']) ? $data['venue_short_description']
1101
+				: null,
1102
+			'VNU_address'         => ! empty($data['address']) ? $data['address'] : null,
1103
+			'VNU_address2'        => ! empty($data['address2']) ? $data['address2'] : null,
1104
+			'VNU_city'            => ! empty($data['city']) ? $data['city'] : null,
1105
+			'STA_ID'              => ! empty($data['state']) ? $data['state'] : null,
1106
+			'CNT_ISO'             => ! empty($data['countries']) ? $data['countries'] : null,
1107
+			'VNU_zip'             => ! empty($data['zip']) ? $data['zip'] : null,
1108
+			'VNU_phone'           => ! empty($data['venue_phone']) ? $data['venue_phone'] : null,
1109
+			'VNU_capacity'        => ! empty($data['venue_capacity']) ? $data['venue_capacity'] : null,
1110
+			'VNU_url'             => ! empty($data['venue_url']) ? $data['venue_url'] : null,
1111
+			'VNU_virtual_phone'   => ! empty($data['virtual_phone']) ? $data['virtual_phone'] : null,
1112
+			'VNU_virtual_url'     => ! empty($data['virtual_url']) ? $data['virtual_url'] : null,
1113
+			'VNU_enable_for_gmap' => isset($data['enable_for_gmap']) ? 1 : 0,
1114
+			'status'              => 'publish',
1115
+		);
1116
+		// if we've got the venue_id then we're just updating the existing venue so let's do that and then get out.
1117
+		if (! empty($venue_id)) {
1118
+			$update_where = array($venue_model->primary_key_name() => $venue_id);
1119
+			$rows_affected = $venue_model->update($venue_array, array($update_where));
1120
+			// we've gotta make sure that the venue is always attached to a revision.. add_relation_to should take care of making sure that the relation is already present.
1121
+			$evtobj->_add_relation_to($venue_id, 'Venue');
1122
+			return $rows_affected > 0 ? true : false;
1123
+		} else {
1124
+			// we insert the venue
1125
+			$venue_id = $venue_model->insert($venue_array);
1126
+			$evtobj->_add_relation_to($venue_id, 'Venue');
1127
+			return ! empty($venue_id) ? true : false;
1128
+		}
1129
+		// when we have the ancestor come in it's already been handled by the revision save.
1130
+	}
1131
+
1132
+
1133
+	/**
1134
+	 * Handles saving everything related to Tickets (datetimes, tickets, prices)
1135
+	 *
1136
+	 * @param  EE_Event $evtobj The Event object we're attaching data to
1137
+	 * @param  array    $data   The request data from the form
1138
+	 * @return array
1139
+	 */
1140
+	protected function _default_tickets_update(EE_Event $evtobj, $data)
1141
+	{
1142
+		$success = true;
1143
+		$saved_dtt = null;
1144
+		$saved_tickets = array();
1145
+		$incoming_date_formats = array('Y-m-d', 'h:i a');
1146
+		foreach ($data['edit_event_datetimes'] as $row => $dtt) {
1147
+			// trim all values to ensure any excess whitespace is removed.
1148
+			$dtt = array_map('trim', $dtt);
1149
+			$dtt['DTT_EVT_end'] = isset($dtt['DTT_EVT_end']) && ! empty($dtt['DTT_EVT_end']) ? $dtt['DTT_EVT_end']
1150
+				: $dtt['DTT_EVT_start'];
1151
+			$datetime_values = array(
1152
+				'DTT_ID'        => ! empty($dtt['DTT_ID']) ? $dtt['DTT_ID'] : null,
1153
+				'DTT_EVT_start' => $dtt['DTT_EVT_start'],
1154
+				'DTT_EVT_end'   => $dtt['DTT_EVT_end'],
1155
+				'DTT_reg_limit' => empty($dtt['DTT_reg_limit']) ? EE_INF : $dtt['DTT_reg_limit'],
1156
+				'DTT_order'     => $row,
1157
+			);
1158
+			// if we have an id then let's get existing object first and then set the new values.  Otherwise we instantiate a new object for save.
1159
+			if (! empty($dtt['DTT_ID'])) {
1160
+				$DTM = EE_Registry::instance()
1161
+								  ->load_model('Datetime', array($evtobj->get_timezone()))
1162
+								  ->get_one_by_ID($dtt['DTT_ID']);
1163
+				$DTM->set_date_format($incoming_date_formats[0]);
1164
+				$DTM->set_time_format($incoming_date_formats[1]);
1165
+				foreach ($datetime_values as $field => $value) {
1166
+					$DTM->set($field, $value);
1167
+				}
1168
+				// make sure the $dtt_id here is saved just in case after the add_relation_to() the autosave replaces it.  We need to do this so we dont' TRASH the parent DTT.
1169
+				$saved_dtts[ $DTM->ID() ] = $DTM;
1170
+			} else {
1171
+				$DTM = EE_Registry::instance()->load_class(
1172
+					'Datetime',
1173
+					array($datetime_values, $evtobj->get_timezone(), $incoming_date_formats),
1174
+					false,
1175
+					false
1176
+				);
1177
+				foreach ($datetime_values as $field => $value) {
1178
+					$DTM->set($field, $value);
1179
+				}
1180
+			}
1181
+			$DTM->save();
1182
+			$DTT = $evtobj->_add_relation_to($DTM, 'Datetime');
1183
+			// load DTT helper
1184
+			// before going any further make sure our dates are setup correctly so that the end date is always equal or greater than the start date.
1185
+			if ($DTT->get_raw('DTT_EVT_start') > $DTT->get_raw('DTT_EVT_end')) {
1186
+				$DTT->set('DTT_EVT_end', $DTT->get('DTT_EVT_start'));
1187
+				$DTT = EEH_DTT_Helper::date_time_add($DTT, 'DTT_EVT_end', 'days');
1188
+				$DTT->save();
1189
+			}
1190
+			// now we got to make sure we add the new DTT_ID to the $saved_dtts array  because it is possible there was a new one created for the autosave.
1191
+			$saved_dtt = $DTT;
1192
+			$success = ! $success ? $success : $DTT;
1193
+			// if ANY of these updates fail then we want the appropriate global error message.
1194
+			// //todo this is actually sucky we need a better error message but this is what it is for now.
1195
+		}
1196
+		// no dtts get deleted so we don't do any of that logic here.
1197
+		// update tickets next
1198
+		$old_tickets = isset($data['ticket_IDs']) ? explode(',', $data['ticket_IDs']) : array();
1199
+		foreach ($data['edit_tickets'] as $row => $tkt) {
1200
+			$incoming_date_formats = array('Y-m-d', 'h:i a');
1201
+			$update_prices = false;
1202
+			$ticket_price = isset($data['edit_prices'][ $row ][1]['PRC_amount'])
1203
+				? $data['edit_prices'][ $row ][1]['PRC_amount'] : 0;
1204
+			// trim inputs to ensure any excess whitespace is removed.
1205
+			$tkt = array_map('trim', $tkt);
1206
+			if (empty($tkt['TKT_start_date'])) {
1207
+				// let's use now in the set timezone.
1208
+				$now = new DateTime('now', new DateTimeZone($evtobj->get_timezone()));
1209
+				$tkt['TKT_start_date'] = $now->format($incoming_date_formats[0] . ' ' . $incoming_date_formats[1]);
1210
+			}
1211
+			if (empty($tkt['TKT_end_date'])) {
1212
+				// use the start date of the first datetime
1213
+				$dtt = $evtobj->first_datetime();
1214
+				$tkt['TKT_end_date'] = $dtt->start_date_and_time(
1215
+					$incoming_date_formats[0],
1216
+					$incoming_date_formats[1]
1217
+				);
1218
+			}
1219
+			$TKT_values = array(
1220
+				'TKT_ID'          => ! empty($tkt['TKT_ID']) ? $tkt['TKT_ID'] : null,
1221
+				'TTM_ID'          => ! empty($tkt['TTM_ID']) ? $tkt['TTM_ID'] : 0,
1222
+				'TKT_name'        => ! empty($tkt['TKT_name']) ? $tkt['TKT_name'] : '',
1223
+				'TKT_description' => ! empty($tkt['TKT_description']) ? $tkt['TKT_description'] : '',
1224
+				'TKT_start_date'  => $tkt['TKT_start_date'],
1225
+				'TKT_end_date'    => $tkt['TKT_end_date'],
1226
+				'TKT_qty'         => ! isset($tkt['TKT_qty']) || $tkt['TKT_qty'] === '' ? EE_INF : $tkt['TKT_qty'],
1227
+				'TKT_uses'        => ! isset($tkt['TKT_uses']) || $tkt['TKT_uses'] === '' ? EE_INF : $tkt['TKT_uses'],
1228
+				'TKT_min'         => empty($tkt['TKT_min']) ? 0 : $tkt['TKT_min'],
1229
+				'TKT_max'         => empty($tkt['TKT_max']) ? EE_INF : $tkt['TKT_max'],
1230
+				'TKT_row'         => $row,
1231
+				'TKT_order'       => isset($tkt['TKT_order']) ? $tkt['TKT_order'] : $row,
1232
+				'TKT_price'       => $ticket_price,
1233
+			);
1234
+			// if this is a default TKT, then we need to set the TKT_ID to 0 and update accordingly, which means in turn that the prices will become new prices as well.
1235
+			if (isset($tkt['TKT_is_default']) && $tkt['TKT_is_default']) {
1236
+				$TKT_values['TKT_ID'] = 0;
1237
+				$TKT_values['TKT_is_default'] = 0;
1238
+				$TKT_values['TKT_price'] = $ticket_price;
1239
+				$update_prices = true;
1240
+			}
1241
+			// if we have a TKT_ID then we need to get that existing TKT_obj and update it
1242
+			// we actually do our saves a head of doing any add_relations to because its entirely possible that this ticket didn't removed or added to any datetime in the session but DID have it's items modified.
1243
+			// keep in mind that if the TKT has been sold (and we have changed pricing information), then we won't be updating the tkt but instead a new tkt will be created and the old one archived.
1244
+			if (! empty($tkt['TKT_ID'])) {
1245
+				$TKT = EE_Registry::instance()
1246
+								  ->load_model('Ticket', array($evtobj->get_timezone()))
1247
+								  ->get_one_by_ID($tkt['TKT_ID']);
1248
+				if ($TKT instanceof EE_Ticket) {
1249
+					$ticket_sold = $TKT->count_related(
1250
+						'Registration',
1251
+						array(
1252
+							array(
1253
+								'STS_ID' => array(
1254
+									'NOT IN',
1255
+									array(EEM_Registration::status_id_incomplete),
1256
+								),
1257
+							),
1258
+						)
1259
+					) > 0 ? true : false;
1260
+					// let's just check the total price for the existing ticket and determine if it matches the new total price.  if they are different then we create a new ticket (if tkts sold) if they aren't different then we go ahead and modify existing ticket.
1261
+					$create_new_TKT = $ticket_sold && $ticket_price != $TKT->get('TKT_price')
1262
+									  && ! $TKT->get('TKT_deleted');
1263
+					$TKT->set_date_format($incoming_date_formats[0]);
1264
+					$TKT->set_time_format($incoming_date_formats[1]);
1265
+					// set new values
1266
+					foreach ($TKT_values as $field => $value) {
1267
+						if ($field == 'TKT_qty') {
1268
+							$TKT->set_qty($value);
1269
+						} else {
1270
+							$TKT->set($field, $value);
1271
+						}
1272
+					}
1273
+					// if $create_new_TKT is false then we can safely update the existing ticket.  Otherwise we have to create a new ticket.
1274
+					if ($create_new_TKT) {
1275
+						// archive the old ticket first
1276
+						$TKT->set('TKT_deleted', 1);
1277
+						$TKT->save();
1278
+						// make sure this ticket is still recorded in our saved_tkts so we don't run it through the regular trash routine.
1279
+						$saved_tickets[ $TKT->ID() ] = $TKT;
1280
+						// create new ticket that's a copy of the existing except a new id of course (and not archived) AND has the new TKT_price associated with it.
1281
+						$TKT = clone $TKT;
1282
+						$TKT->set('TKT_ID', 0);
1283
+						$TKT->set('TKT_deleted', 0);
1284
+						$TKT->set('TKT_price', $ticket_price);
1285
+						$TKT->set('TKT_sold', 0);
1286
+						// now we need to make sure that $new prices are created as well and attached to new ticket.
1287
+						$update_prices = true;
1288
+					}
1289
+					// make sure price is set if it hasn't been already
1290
+					$TKT->set('TKT_price', $ticket_price);
1291
+				}
1292
+			} else {
1293
+				// no TKT_id so a new TKT
1294
+				$TKT_values['TKT_price'] = $ticket_price;
1295
+				$TKT = EE_Registry::instance()->load_class('Ticket', array($TKT_values), false, false);
1296
+				if ($TKT instanceof EE_Ticket) {
1297
+					// need to reset values to properly account for the date formats
1298
+					$TKT->set_date_format($incoming_date_formats[0]);
1299
+					$TKT->set_time_format($incoming_date_formats[1]);
1300
+					$TKT->set_timezone($evtobj->get_timezone());
1301
+					// set new values
1302
+					foreach ($TKT_values as $field => $value) {
1303
+						if ($field == 'TKT_qty') {
1304
+							$TKT->set_qty($value);
1305
+						} else {
1306
+							$TKT->set($field, $value);
1307
+						}
1308
+					}
1309
+					$update_prices = true;
1310
+				}
1311
+			}
1312
+			// cap ticket qty by datetime reg limits
1313
+			$TKT->set_qty(min($TKT->qty(), $TKT->qty('reg_limit')));
1314
+			// update ticket.
1315
+			$TKT->save();
1316
+			// before going any further make sure our dates are setup correctly so that the end date is always equal or greater than the start date.
1317
+			if ($TKT->get_raw('TKT_start_date') > $TKT->get_raw('TKT_end_date')) {
1318
+				$TKT->set('TKT_end_date', $TKT->get('TKT_start_date'));
1319
+				$TKT = EEH_DTT_Helper::date_time_add($TKT, 'TKT_end_date', 'days');
1320
+				$TKT->save();
1321
+			}
1322
+			// initially let's add the ticket to the dtt
1323
+			$saved_dtt->_add_relation_to($TKT, 'Ticket');
1324
+			$saved_tickets[ $TKT->ID() ] = $TKT;
1325
+			// add prices to ticket
1326
+			$this->_add_prices_to_ticket($data['edit_prices'][ $row ], $TKT, $update_prices);
1327
+		}
1328
+		// however now we need to handle permanently deleting tickets via the ui.  Keep in mind that the ui does not allow deleting/archiving tickets that have ticket sold.  However, it does allow for deleting tickets that have no tickets sold, in which case we want to get rid of permanently because there is no need to save in db.
1329
+		$old_tickets = isset($old_tickets[0]) && $old_tickets[0] == '' ? array() : $old_tickets;
1330
+		$tickets_removed = array_diff($old_tickets, array_keys($saved_tickets));
1331
+		foreach ($tickets_removed as $id) {
1332
+			$id = absint($id);
1333
+			// get the ticket for this id
1334
+			$tkt_to_remove = EE_Registry::instance()->load_model('Ticket')->get_one_by_ID($id);
1335
+			// need to get all the related datetimes on this ticket and remove from every single one of them (remember this process can ONLY kick off if there are NO tkts_sold)
1336
+			$dtts = $tkt_to_remove->get_many_related('Datetime');
1337
+			foreach ($dtts as $dtt) {
1338
+				$tkt_to_remove->_remove_relation_to($dtt, 'Datetime');
1339
+			}
1340
+			// need to do the same for prices (except these prices can also be deleted because again, tickets can only be trashed if they don't have any TKTs sold (otherwise they are just archived))
1341
+			$tkt_to_remove->delete_related_permanently('Price');
1342
+			// finally let's delete this ticket (which should not be blocked at this point b/c we've removed all our relationships)
1343
+			$tkt_to_remove->delete_permanently();
1344
+		}
1345
+		return array($saved_dtt, $saved_tickets);
1346
+	}
1347
+
1348
+
1349
+	/**
1350
+	 * This attaches a list of given prices to a ticket.
1351
+	 * Note we dont' have to worry about ever removing relationships (or archiving prices) because if there is a change
1352
+	 * in price information on a ticket, a new ticket is created anyways so the archived ticket will retain the old
1353
+	 * price info and prices are automatically "archived" via the ticket.
1354
+	 *
1355
+	 * @access  private
1356
+	 * @param array     $prices     Array of prices from the form.
1357
+	 * @param EE_Ticket $ticket     EE_Ticket object that prices are being attached to.
1358
+	 * @param bool      $new_prices Whether attach existing incoming prices or create new ones.
1359
+	 * @return  void
1360
+	 */
1361
+	private function _add_prices_to_ticket($prices, EE_Ticket $ticket, $new_prices = false)
1362
+	{
1363
+		foreach ($prices as $row => $prc) {
1364
+			$PRC_values = array(
1365
+				'PRC_ID'         => ! empty($prc['PRC_ID']) ? $prc['PRC_ID'] : null,
1366
+				'PRT_ID'         => ! empty($prc['PRT_ID']) ? $prc['PRT_ID'] : null,
1367
+				'PRC_amount'     => ! empty($prc['PRC_amount']) ? $prc['PRC_amount'] : 0,
1368
+				'PRC_name'       => ! empty($prc['PRC_name']) ? $prc['PRC_name'] : '',
1369
+				'PRC_desc'       => ! empty($prc['PRC_desc']) ? $prc['PRC_desc'] : '',
1370
+				'PRC_is_default' => 0, // make sure prices are NOT set as default from this context
1371
+				'PRC_order'      => $row,
1372
+			);
1373
+			if ($new_prices || empty($PRC_values['PRC_ID'])) {
1374
+				$PRC_values['PRC_ID'] = 0;
1375
+				$PRC = EE_Registry::instance()->load_class('Price', array($PRC_values), false, false);
1376
+			} else {
1377
+				$PRC = EE_Registry::instance()->load_model('Price')->get_one_by_ID($prc['PRC_ID']);
1378
+				// update this price with new values
1379
+				foreach ($PRC_values as $field => $newprc) {
1380
+					$PRC->set($field, $newprc);
1381
+				}
1382
+				$PRC->save();
1383
+			}
1384
+			$ticket->_add_relation_to($PRC, 'Price');
1385
+		}
1386
+	}
1387
+
1388
+
1389
+	/**
1390
+	 * Add in our autosave ajax handlers
1391
+	 *
1392
+	 */
1393
+	protected function _ee_autosave_create_new()
1394
+	{
1395
+	}
1396
+
1397
+
1398
+	/**
1399
+	 * More autosave handlers.
1400
+	 */
1401
+	protected function _ee_autosave_edit()
1402
+	{
1403
+		return; // TEMPORARILY EXITING CAUSE THIS IS A TODO
1404
+	}
1405
+
1406
+
1407
+	/**
1408
+	 *    _generate_publish_box_extra_content
1409
+	 */
1410
+	private function _generate_publish_box_extra_content()
1411
+	{
1412
+		// load formatter helper
1413
+		// args for getting related registrations
1414
+		$approved_query_args = array(
1415
+			array(
1416
+				'REG_deleted' => 0,
1417
+				'STS_ID'      => EEM_Registration::status_id_approved,
1418
+			),
1419
+		);
1420
+		$not_approved_query_args = array(
1421
+			array(
1422
+				'REG_deleted' => 0,
1423
+				'STS_ID'      => EEM_Registration::status_id_not_approved,
1424
+			),
1425
+		);
1426
+		$pending_payment_query_args = array(
1427
+			array(
1428
+				'REG_deleted' => 0,
1429
+				'STS_ID'      => EEM_Registration::status_id_pending_payment,
1430
+			),
1431
+		);
1432
+		// publish box
1433
+		$publish_box_extra_args = array(
1434
+			'view_approved_reg_url'        => add_query_arg(
1435
+				array(
1436
+					'action'      => 'default',
1437
+					'event_id'    => $this->_cpt_model_obj->ID(),
1438
+					'_reg_status' => EEM_Registration::status_id_approved,
1439
+				),
1440
+				REG_ADMIN_URL
1441
+			),
1442
+			'view_not_approved_reg_url'    => add_query_arg(
1443
+				array(
1444
+					'action'      => 'default',
1445
+					'event_id'    => $this->_cpt_model_obj->ID(),
1446
+					'_reg_status' => EEM_Registration::status_id_not_approved,
1447
+				),
1448
+				REG_ADMIN_URL
1449
+			),
1450
+			'view_pending_payment_reg_url' => add_query_arg(
1451
+				array(
1452
+					'action'      => 'default',
1453
+					'event_id'    => $this->_cpt_model_obj->ID(),
1454
+					'_reg_status' => EEM_Registration::status_id_pending_payment,
1455
+				),
1456
+				REG_ADMIN_URL
1457
+			),
1458
+			'approved_regs'                => $this->_cpt_model_obj->count_related(
1459
+				'Registration',
1460
+				$approved_query_args
1461
+			),
1462
+			'not_approved_regs'            => $this->_cpt_model_obj->count_related(
1463
+				'Registration',
1464
+				$not_approved_query_args
1465
+			),
1466
+			'pending_payment_regs'         => $this->_cpt_model_obj->count_related(
1467
+				'Registration',
1468
+				$pending_payment_query_args
1469
+			),
1470
+			'misc_pub_section_class'       => apply_filters(
1471
+				'FHEE_Events_Admin_Page___generate_publish_box_extra_content__misc_pub_section_class',
1472
+				'misc-pub-section'
1473
+			),
1474
+		);
1475
+		ob_start();
1476
+		do_action(
1477
+			'AHEE__Events_Admin_Page___generate_publish_box_extra_content__event_editor_overview_add',
1478
+			$this->_cpt_model_obj
1479
+		);
1480
+		$publish_box_extra_args['event_editor_overview_add'] = ob_get_clean();
1481
+		// load template
1482
+		EEH_Template::display_template(
1483
+			EVENTS_TEMPLATE_PATH . 'event_publish_box_extras.template.php',
1484
+			$publish_box_extra_args
1485
+		);
1486
+	}
1487
+
1488
+
1489
+	/**
1490
+	 * @return EE_Event
1491
+	 */
1492
+	public function get_event_object()
1493
+	{
1494
+		return $this->_cpt_model_obj;
1495
+	}
1496
+
1497
+
1498
+
1499
+
1500
+	/** METABOXES * */
1501
+	/**
1502
+	 * _register_event_editor_meta_boxes
1503
+	 * add all metaboxes related to the event_editor
1504
+	 *
1505
+	 * @return void
1506
+	 */
1507
+	protected function _register_event_editor_meta_boxes()
1508
+	{
1509
+		$this->verify_cpt_object();
1510
+		// add_meta_box(
1511
+		//     'espresso_event_editor_tickets',
1512
+		//     esc_html__('Event Datetime & Ticket', 'event_espresso'),
1513
+		//     array($this, 'ticket_metabox'),
1514
+		//     $this->page_slug,
1515
+		//     'normal',
1516
+		//     'high'
1517
+		// );
1518
+		add_meta_box(
1519
+			'espresso_event_editor_event_options',
1520
+			esc_html__('Event Registration Options', 'event_espresso'),
1521
+			array($this, 'registration_options_meta_box'),
1522
+			$this->page_slug,
1523
+			'side',
1524
+			'default'
1525
+		);
1526
+		// NOTE: if you're looking for other metaboxes in here,
1527
+		// where a metabox has a related management page in the admin
1528
+		// you will find it setup in the related management page's "_Hooks" file.
1529
+		// i.e. messages metabox is found in "espresso_events_Messages_Hooks.class.php".
1530
+	}
1531
+
1532
+
1533
+	/**
1534
+	 * @throws DomainException
1535
+	 * @throws EE_Error
1536
+	 */
1537
+	public function ticket_metabox()
1538
+	{
1539
+		$existing_datetime_ids = $existing_ticket_ids = array();
1540
+		// defaults for template args
1541
+		$template_args = array(
1542
+			'existing_datetime_ids'    => '',
1543
+			'event_datetime_help_link' => '',
1544
+			'ticket_options_help_link' => '',
1545
+			'time'                     => null,
1546
+			'ticket_rows'              => '',
1547
+			'existing_ticket_ids'      => '',
1548
+			'total_ticket_rows'        => 1,
1549
+			'ticket_js_structure'      => '',
1550
+			'trash_icon'               => 'ee-lock-icon',
1551
+			'disabled'                 => '',
1552
+		);
1553
+		$event_id = is_object($this->_cpt_model_obj) ? $this->_cpt_model_obj->ID() : null;
1554
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
1555
+		/**
1556
+		 * 1. Start with retrieving Datetimes
1557
+		 * 2. Fore each datetime get related tickets
1558
+		 * 3. For each ticket get related prices
1559
+		 */
1560
+		$times = EE_Registry::instance()->load_model('Datetime')->get_all_event_dates($event_id);
1561
+		/** @type EE_Datetime $first_datetime */
1562
+		$first_datetime = reset($times);
1563
+		// do we get related tickets?
1564
+		if ($first_datetime instanceof EE_Datetime
1565
+			&& $first_datetime->ID() !== 0
1566
+		) {
1567
+			$existing_datetime_ids[] = $first_datetime->get('DTT_ID');
1568
+			$template_args['time'] = $first_datetime;
1569
+			$related_tickets = $first_datetime->tickets(
1570
+				array(
1571
+					array('OR' => array('TKT_deleted' => 1, 'TKT_deleted*' => 0)),
1572
+					'default_where_conditions' => 'none',
1573
+				)
1574
+			);
1575
+			if (! empty($related_tickets)) {
1576
+				$template_args['total_ticket_rows'] = count($related_tickets);
1577
+				$row = 0;
1578
+				foreach ($related_tickets as $ticket) {
1579
+					$existing_ticket_ids[] = $ticket->get('TKT_ID');
1580
+					$template_args['ticket_rows'] .= $this->_get_ticket_row($ticket, false, $row);
1581
+					$row++;
1582
+				}
1583
+			} else {
1584
+				$template_args['total_ticket_rows'] = 1;
1585
+				/** @type EE_Ticket $ticket */
1586
+				$ticket = EE_Registry::instance()->load_model('Ticket')->create_default_object();
1587
+				$template_args['ticket_rows'] .= $this->_get_ticket_row($ticket);
1588
+			}
1589
+		} else {
1590
+			$template_args['time'] = $times[0];
1591
+			/** @type EE_Ticket $ticket */
1592
+			$ticket = EE_Registry::instance()->load_model('Ticket')->get_all_default_tickets();
1593
+			$template_args['ticket_rows'] .= $this->_get_ticket_row($ticket[1]);
1594
+			// NOTE: we're just sending the first default row
1595
+			// (decaf can't manage default tickets so this should be sufficient);
1596
+		}
1597
+		$template_args['event_datetime_help_link'] = $this->_get_help_tab_link(
1598
+			'event_editor_event_datetimes_help_tab'
1599
+		);
1600
+		$template_args['ticket_options_help_link'] = $this->_get_help_tab_link('ticket_options_info');
1601
+		$template_args['existing_datetime_ids'] = implode(',', $existing_datetime_ids);
1602
+		$template_args['existing_ticket_ids'] = implode(',', $existing_ticket_ids);
1603
+		$template_args['ticket_js_structure'] = $this->_get_ticket_row(
1604
+			EE_Registry::instance()->load_model('Ticket')->create_default_object(),
1605
+			true
1606
+		);
1607
+		$template = apply_filters(
1608
+			'FHEE__Events_Admin_Page__ticket_metabox__template',
1609
+			EVENTS_TEMPLATE_PATH . 'event_tickets_metabox_main.template.php'
1610
+		);
1611
+		EEH_Template::display_template($template, $template_args);
1612
+	}
1613
+
1614
+
1615
+	/**
1616
+	 * Setup an individual ticket form for the decaf event editor page
1617
+	 *
1618
+	 * @access private
1619
+	 * @param  EE_Ticket $ticket   the ticket object
1620
+	 * @param  boolean   $skeleton whether we're generating a skeleton for js manipulation
1621
+	 * @param int        $row
1622
+	 * @return string generated html for the ticket row.
1623
+	 */
1624
+	private function _get_ticket_row($ticket, $skeleton = false, $row = 0)
1625
+	{
1626
+		$template_args = array(
1627
+			'tkt_status_class'    => ' tkt-status-' . $ticket->ticket_status(),
1628
+			'tkt_archive_class'   => $ticket->ticket_status() === EE_Ticket::archived && ! $skeleton ? ' tkt-archived'
1629
+				: '',
1630
+			'ticketrow'           => $skeleton ? 'TICKETNUM' : $row,
1631
+			'TKT_ID'              => $ticket->get('TKT_ID'),
1632
+			'TKT_name'            => $ticket->get('TKT_name'),
1633
+			'TKT_start_date'      => $skeleton ? '' : $ticket->get_date('TKT_start_date', 'Y-m-d h:i a'),
1634
+			'TKT_end_date'        => $skeleton ? '' : $ticket->get_date('TKT_end_date', 'Y-m-d h:i a'),
1635
+			'TKT_is_default'      => $ticket->get('TKT_is_default'),
1636
+			'TKT_qty'             => $ticket->get_pretty('TKT_qty', 'input'),
1637
+			'edit_ticketrow_name' => $skeleton ? 'TICKETNAMEATTR' : 'edit_tickets',
1638
+			'TKT_sold'            => $skeleton ? 0 : $ticket->get('TKT_sold'),
1639
+			'trash_icon'          => ($skeleton || (! empty($ticket) && ! $ticket->get('TKT_deleted')))
1640
+									 && (! empty($ticket) && $ticket->get('TKT_sold') === 0)
1641
+				? 'trash-icon dashicons dashicons-post-trash clickable' : 'ee-lock-icon',
1642
+			'disabled'            => $skeleton || (! empty($ticket) && ! $ticket->get('TKT_deleted')) ? ''
1643
+				: ' disabled=disabled',
1644
+		);
1645
+		$price = $ticket->ID() !== 0
1646
+			? $ticket->get_first_related('Price', array('default_where_conditions' => 'none'))
1647
+			: EE_Registry::instance()->load_model('Price')->create_default_object();
1648
+		$price_args = array(
1649
+			'price_currency_symbol' => EE_Registry::instance()->CFG->currency->sign,
1650
+			'PRC_amount'            => $price->get('PRC_amount'),
1651
+			'PRT_ID'                => $price->get('PRT_ID'),
1652
+			'PRC_ID'                => $price->get('PRC_ID'),
1653
+			'PRC_is_default'        => $price->get('PRC_is_default'),
1654
+		);
1655
+		// make sure we have default start and end dates if skeleton
1656
+		// handle rows that should NOT be empty
1657
+		if (empty($template_args['TKT_start_date'])) {
1658
+			// if empty then the start date will be now.
1659
+			$template_args['TKT_start_date'] = date('Y-m-d h:i a', current_time('timestamp'));
1660
+		}
1661
+		if (empty($template_args['TKT_end_date'])) {
1662
+			// get the earliest datetime (if present);
1663
+			$earliest_dtt = $this->_cpt_model_obj->ID() > 0
1664
+				? $this->_cpt_model_obj->get_first_related(
1665
+					'Datetime',
1666
+					array('order_by' => array('DTT_EVT_start' => 'ASC'))
1667
+				)
1668
+				: null;
1669
+			if (! empty($earliest_dtt)) {
1670
+				$template_args['TKT_end_date'] = $earliest_dtt->get_datetime('DTT_EVT_start', 'Y-m-d', 'h:i a');
1671
+			} else {
1672
+				$template_args['TKT_end_date'] = date(
1673
+					'Y-m-d h:i a',
1674
+					mktime(0, 0, 0, date("m"), date("d") + 7, date("Y"))
1675
+				);
1676
+			}
1677
+		}
1678
+		$template_args = array_merge($template_args, $price_args);
1679
+		$template = apply_filters(
1680
+			'FHEE__Events_Admin_Page__get_ticket_row__template',
1681
+			EVENTS_TEMPLATE_PATH . 'event_tickets_metabox_ticket_row.template.php',
1682
+			$ticket
1683
+		);
1684
+		return EEH_Template::display_template($template, $template_args, true);
1685
+	}
1686
+
1687
+
1688
+	/**
1689
+	 * @throws DomainException
1690
+	 */
1691
+	public function registration_options_meta_box()
1692
+	{
1693
+		$yes_no_values = array(
1694
+			array('id' => true, 'text' => esc_html__('Yes', 'event_espresso')),
1695
+			array('id' => false, 'text' => esc_html__('No', 'event_espresso')),
1696
+		);
1697
+		$default_reg_status_values = EEM_Registration::reg_status_array(
1698
+			array(
1699
+				EEM_Registration::status_id_cancelled,
1700
+				EEM_Registration::status_id_declined,
1701
+				EEM_Registration::status_id_incomplete,
1702
+			),
1703
+			true
1704
+		);
1705
+		// $template_args['is_active_select'] = EEH_Form_Fields::select_input('is_active', $yes_no_values, $this->_cpt_model_obj->is_active());
1706
+		$template_args['_event'] = $this->_cpt_model_obj;
1707
+		$template_args['active_status'] = $this->_cpt_model_obj->pretty_active_status(false);
1708
+		$template_args['additional_limit'] = $this->_cpt_model_obj->additional_limit();
1709
+		$template_args['default_registration_status'] = EEH_Form_Fields::select_input(
1710
+			'default_reg_status',
1711
+			$default_reg_status_values,
1712
+			$this->_cpt_model_obj->default_registration_status()
1713
+		);
1714
+		$template_args['display_description'] = EEH_Form_Fields::select_input(
1715
+			'display_desc',
1716
+			$yes_no_values,
1717
+			$this->_cpt_model_obj->display_description()
1718
+		);
1719
+		$template_args['display_ticket_selector'] = EEH_Form_Fields::select_input(
1720
+			'display_ticket_selector',
1721
+			$yes_no_values,
1722
+			$this->_cpt_model_obj->display_ticket_selector(),
1723
+			'',
1724
+			'',
1725
+			false
1726
+		);
1727
+		$template_args['additional_registration_options'] = apply_filters(
1728
+			'FHEE__Events_Admin_Page__registration_options_meta_box__additional_registration_options',
1729
+			'',
1730
+			$template_args,
1731
+			$yes_no_values,
1732
+			$default_reg_status_values
1733
+		);
1734
+		EEH_Template::display_template(
1735
+			EVENTS_TEMPLATE_PATH . 'event_registration_options.template.php',
1736
+			$template_args
1737
+		);
1738
+	}
1739
+
1740
+
1741
+	/**
1742
+	 * _get_events()
1743
+	 * This method simply returns all the events (for the given _view and paging)
1744
+	 *
1745
+	 * @access public
1746
+	 * @param int  $per_page     count of items per page (20 default);
1747
+	 * @param int  $current_page what is the current page being viewed.
1748
+	 * @param bool $count        if TRUE then we just return a count of ALL events matching the given _view.
1749
+	 *                           If FALSE then we return an array of event objects
1750
+	 *                           that match the given _view and paging parameters.
1751
+	 * @return array an array of event objects.
1752
+	 */
1753
+	public function get_events($per_page = 10, $current_page = 1, $count = false)
1754
+	{
1755
+		$EEME = $this->_event_model();
1756
+		$offset = ($current_page - 1) * $per_page;
1757
+		$limit = $count ? null : $offset . ',' . $per_page;
1758
+		$orderby = isset($this->_req_data['orderby']) ? $this->_req_data['orderby'] : 'EVT_ID';
1759
+		$order = isset($this->_req_data['order']) ? $this->_req_data['order'] : "DESC";
1760
+		if (isset($this->_req_data['month_range'])) {
1761
+			$pieces = explode(' ', $this->_req_data['month_range'], 3);
1762
+			// simulate the FIRST day of the month, that fixes issues for months like February
1763
+			// where PHP doesn't know what to assume for date.
1764
+			// @see https://events.codebasehq.com/projects/event-espresso/tickets/10437
1765
+			$month_r = ! empty($pieces[0]) ? date('m', \EEH_DTT_Helper::first_of_month_timestamp($pieces[0])) : '';
1766
+			$year_r = ! empty($pieces[1]) ? $pieces[1] : '';
1767
+		}
1768
+		$where = array();
1769
+		$status = isset($this->_req_data['status']) ? $this->_req_data['status'] : null;
1770
+		// determine what post_status our condition will have for the query.
1771
+		switch ($status) {
1772
+			case 'month':
1773
+			case 'today':
1774
+			case null:
1775
+			case 'all':
1776
+				break;
1777
+			case 'draft':
1778
+				$where['status'] = array('IN', array('draft', 'auto-draft'));
1779
+				break;
1780
+			default:
1781
+				$where['status'] = $status;
1782
+		}
1783
+		// categories?
1784
+		$category = isset($this->_req_data['EVT_CAT']) && $this->_req_data['EVT_CAT'] > 0
1785
+			? $this->_req_data['EVT_CAT'] : null;
1786
+		if (! empty($category)) {
1787
+			$where['Term_Taxonomy.taxonomy'] = EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY;
1788
+			$where['Term_Taxonomy.term_id'] = $category;
1789
+		}
1790
+		// date where conditions
1791
+		$start_formats = EEM_Datetime::instance()->get_formats_for('DTT_EVT_start');
1792
+		if (isset($this->_req_data['month_range']) && $this->_req_data['month_range'] != '') {
1793
+			$DateTime = new DateTime(
1794
+				$year_r . '-' . $month_r . '-01 00:00:00',
1795
+				new DateTimeZone(EEM_Datetime::instance()->get_timezone())
1796
+			);
1797
+			$start = $DateTime->format(implode(' ', $start_formats));
1798
+			$end = $DateTime->setDate(
1799
+				$year_r,
1800
+				$month_r,
1801
+				$DateTime
1802
+					->format('t')
1803
+			)->setTime(23, 59, 59)
1804
+							->format(implode(' ', $start_formats));
1805
+			$where['Datetime.DTT_EVT_start'] = array('BETWEEN', array($start, $end));
1806
+		} elseif (isset($this->_req_data['status']) && $this->_req_data['status'] == 'today') {
1807
+			$DateTime = new DateTime('now', new DateTimeZone(EEM_Event::instance()->get_timezone()));
1808
+			$start = $DateTime->setTime(0, 0, 0)->format(implode(' ', $start_formats));
1809
+			$end = $DateTime->setTime(23, 59, 59)->format(implode(' ', $start_formats));
1810
+			$where['Datetime.DTT_EVT_start'] = array('BETWEEN', array($start, $end));
1811
+		} elseif (isset($this->_req_data['status']) && $this->_req_data['status'] == 'month') {
1812
+			$now = date('Y-m-01');
1813
+			$DateTime = new DateTime($now, new DateTimeZone(EEM_Event::instance()->get_timezone()));
1814
+			$start = $DateTime->setTime(0, 0, 0)->format(implode(' ', $start_formats));
1815
+			$end = $DateTime->setDate(date('Y'), date('m'), $DateTime->format('t'))
1816
+							->setTime(23, 59, 59)
1817
+							->format(implode(' ', $start_formats));
1818
+			$where['Datetime.DTT_EVT_start'] = array('BETWEEN', array($start, $end));
1819
+		}
1820
+		if (! EE_Registry::instance()->CAP->current_user_can('ee_read_others_events', 'get_events')) {
1821
+			$where['EVT_wp_user'] = get_current_user_id();
1822
+		} else {
1823
+			if (! isset($where['status'])) {
1824
+				if (! EE_Registry::instance()->CAP->current_user_can('ee_read_private_events', 'get_events')) {
1825
+					$where['OR'] = array(
1826
+						'status*restrict_private' => array('!=', 'private'),
1827
+						'AND'                     => array(
1828
+							'status*inclusive' => array('=', 'private'),
1829
+							'EVT_wp_user'      => get_current_user_id(),
1830
+						),
1831
+					);
1832
+				}
1833
+			}
1834
+		}
1835
+		if (isset($this->_req_data['EVT_wp_user'])) {
1836
+			if ($this->_req_data['EVT_wp_user'] != get_current_user_id()
1837
+				&& EE_Registry::instance()->CAP->current_user_can('ee_read_others_events', 'get_events')
1838
+			) {
1839
+				$where['EVT_wp_user'] = $this->_req_data['EVT_wp_user'];
1840
+			}
1841
+		}
1842
+		// search query handling
1843
+		if (isset($this->_req_data['s'])) {
1844
+			$search_string = '%' . $this->_req_data['s'] . '%';
1845
+			$where['OR'] = array(
1846
+				'EVT_name'       => array('LIKE', $search_string),
1847
+				'EVT_desc'       => array('LIKE', $search_string),
1848
+				'EVT_short_desc' => array('LIKE', $search_string),
1849
+			);
1850
+		}
1851
+		$where = apply_filters('FHEE__Events_Admin_Page__get_events__where', $where, $this->_req_data);
1852
+		$query_params = apply_filters(
1853
+			'FHEE__Events_Admin_Page__get_events__query_params',
1854
+			array(
1855
+				$where,
1856
+				'limit'    => $limit,
1857
+				'order_by' => $orderby,
1858
+				'order'    => $order,
1859
+				'group_by' => 'EVT_ID',
1860
+			),
1861
+			$this->_req_data
1862
+		);
1863
+		// let's first check if we have special requests coming in.
1864
+		if (isset($this->_req_data['active_status'])) {
1865
+			switch ($this->_req_data['active_status']) {
1866
+				case 'upcoming':
1867
+					return $EEME->get_upcoming_events($query_params, $count);
1868
+					break;
1869
+				case 'expired':
1870
+					return $EEME->get_expired_events($query_params, $count);
1871
+					break;
1872
+				case 'active':
1873
+					return $EEME->get_active_events($query_params, $count);
1874
+					break;
1875
+				case 'inactive':
1876
+					return $EEME->get_inactive_events($query_params, $count);
1877
+					break;
1878
+			}
1879
+		}
1880
+		$events = $count ? $EEME->count(array($where), 'EVT_ID', true) : $EEME->get_all($query_params);
1881
+		return $events;
1882
+	}
1883
+
1884
+
1885
+	/**
1886
+	 * handling for WordPress CPT actions (trash, restore, delete)
1887
+	 *
1888
+	 * @param string $post_id
1889
+	 */
1890
+	public function trash_cpt_item($post_id)
1891
+	{
1892
+		$this->_req_data['EVT_ID'] = $post_id;
1893
+		$this->_trash_or_restore_event('trash', false);
1894
+	}
1895
+
1896
+
1897
+	/**
1898
+	 * @param string $post_id
1899
+	 */
1900
+	public function restore_cpt_item($post_id)
1901
+	{
1902
+		$this->_req_data['EVT_ID'] = $post_id;
1903
+		$this->_trash_or_restore_event('draft', false);
1904
+	}
1905
+
1906
+
1907
+	/**
1908
+	 * @param string $post_id
1909
+	 */
1910
+	public function delete_cpt_item($post_id)
1911
+	{
1912
+		$this->_req_data['EVT_ID'] = $post_id;
1913
+		$this->_delete_event(false);
1914
+	}
1915
+
1916
+
1917
+	/**
1918
+	 * _trash_or_restore_event
1919
+	 *
1920
+	 * @access protected
1921
+	 * @param  string $event_status
1922
+	 * @param bool    $redirect_after
1923
+	 */
1924
+	protected function _trash_or_restore_event($event_status = 'trash', $redirect_after = true)
1925
+	{
1926
+		// determine the event id and set to array.
1927
+		$EVT_ID = isset($this->_req_data['EVT_ID']) ? absint($this->_req_data['EVT_ID']) : false;
1928
+		// loop thru events
1929
+		if ($EVT_ID) {
1930
+			// clean status
1931
+			$event_status = sanitize_key($event_status);
1932
+			// grab status
1933
+			if (! empty($event_status)) {
1934
+				$success = $this->_change_event_status($EVT_ID, $event_status);
1935
+			} else {
1936
+				$success = false;
1937
+				$msg = esc_html__(
1938
+					'An error occurred. The event could not be moved to the trash because a valid event status was not not supplied.',
1939
+					'event_espresso'
1940
+				);
1941
+				EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
1942
+			}
1943
+		} else {
1944
+			$success = false;
1945
+			$msg = esc_html__(
1946
+				'An error occurred. The event could not be moved to the trash because a valid event ID was not not supplied.',
1947
+				'event_espresso'
1948
+			);
1949
+			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
1950
+		}
1951
+		$action = $event_status == 'trash' ? 'moved to the trash' : 'restored from the trash';
1952
+		if ($redirect_after) {
1953
+			$this->_redirect_after_action($success, 'Event', $action, array('action' => 'default'));
1954
+		}
1955
+	}
1956
+
1957
+
1958
+	/**
1959
+	 * _trash_or_restore_events
1960
+	 *
1961
+	 * @access protected
1962
+	 * @param  string $event_status
1963
+	 * @return void
1964
+	 */
1965
+	protected function _trash_or_restore_events($event_status = 'trash')
1966
+	{
1967
+		// clean status
1968
+		$event_status = sanitize_key($event_status);
1969
+		// grab status
1970
+		if (! empty($event_status)) {
1971
+			$success = true;
1972
+			// determine the event id and set to array.
1973
+			$EVT_IDs = isset($this->_req_data['EVT_IDs']) ? (array) $this->_req_data['EVT_IDs'] : array();
1974
+			// loop thru events
1975
+			foreach ($EVT_IDs as $EVT_ID) {
1976
+				if ($EVT_ID = absint($EVT_ID)) {
1977
+					$results = $this->_change_event_status($EVT_ID, $event_status);
1978
+					$success = $results !== false ? $success : false;
1979
+				} else {
1980
+					$msg = sprintf(
1981
+						esc_html__(
1982
+							'An error occurred. Event #%d could not be moved to the trash because a valid event ID was not not supplied.',
1983
+							'event_espresso'
1984
+						),
1985
+						$EVT_ID
1986
+					);
1987
+					EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
1988
+					$success = false;
1989
+				}
1990
+			}
1991
+		} else {
1992
+			$success = false;
1993
+			$msg = esc_html__(
1994
+				'An error occurred. The event could not be moved to the trash because a valid event status was not not supplied.',
1995
+				'event_espresso'
1996
+			);
1997
+			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
1998
+		}
1999
+		// in order to force a pluralized result message we need to send back a success status greater than 1
2000
+		$success = $success ? 2 : false;
2001
+		$action = $event_status == 'trash' ? 'moved to the trash' : 'restored from the trash';
2002
+		$this->_redirect_after_action($success, 'Events', $action, array('action' => 'default'));
2003
+	}
2004
+
2005
+
2006
+	/**
2007
+	 * _trash_or_restore_events
2008
+	 *
2009
+	 * @access  private
2010
+	 * @param  int    $EVT_ID
2011
+	 * @param  string $event_status
2012
+	 * @return bool
2013
+	 */
2014
+	private function _change_event_status($EVT_ID = 0, $event_status = '')
2015
+	{
2016
+		// grab event id
2017
+		if (! $EVT_ID) {
2018
+			$msg = esc_html__(
2019
+				'An error occurred. No Event ID or an invalid Event ID was received.',
2020
+				'event_espresso'
2021
+			);
2022
+			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2023
+			return false;
2024
+		}
2025
+		$this->_cpt_model_obj = EEM_Event::instance()->get_one_by_ID($EVT_ID);
2026
+		// clean status
2027
+		$event_status = sanitize_key($event_status);
2028
+		// grab status
2029
+		if (empty($event_status)) {
2030
+			$msg = esc_html__(
2031
+				'An error occurred. No Event Status or an invalid Event Status was received.',
2032
+				'event_espresso'
2033
+			);
2034
+			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2035
+			return false;
2036
+		}
2037
+		// was event trashed or restored ?
2038
+		switch ($event_status) {
2039
+			case 'draft':
2040
+				$action = 'restored from the trash';
2041
+				$hook = 'AHEE_event_restored_from_trash';
2042
+				break;
2043
+			case 'trash':
2044
+				$action = 'moved to the trash';
2045
+				$hook = 'AHEE_event_moved_to_trash';
2046
+				break;
2047
+			default:
2048
+				$action = 'updated';
2049
+				$hook = false;
2050
+		}
2051
+		// use class to change status
2052
+		$this->_cpt_model_obj->set_status($event_status);
2053
+		$success = $this->_cpt_model_obj->save();
2054
+		if ($success === false) {
2055
+			$msg = sprintf(esc_html__('An error occurred. The event could not be %s.', 'event_espresso'), $action);
2056
+			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2057
+			return false;
2058
+		}
2059
+		if ($hook) {
2060
+			do_action($hook);
2061
+		}
2062
+		return true;
2063
+	}
2064
+
2065
+
2066
+	/**
2067
+	 * _delete_event
2068
+	 *
2069
+	 * @access protected
2070
+	 * @param bool $redirect_after
2071
+	 */
2072
+	protected function _delete_event($redirect_after = true)
2073
+	{
2074
+		// determine the event id and set to array.
2075
+		$EVT_ID = isset($this->_req_data['EVT_ID']) ? absint($this->_req_data['EVT_ID']) : null;
2076
+		$EVT_ID = isset($this->_req_data['post']) ? absint($this->_req_data['post']) : $EVT_ID;
2077
+		// loop thru events
2078
+		if ($EVT_ID) {
2079
+			$success = $this->_permanently_delete_event($EVT_ID);
2080
+			// get list of events with no prices
2081
+			$espresso_no_ticket_prices = get_option('ee_no_ticket_prices', array());
2082
+			// remove this event from the list of events with no prices
2083
+			if (isset($espresso_no_ticket_prices[ $EVT_ID ])) {
2084
+				unset($espresso_no_ticket_prices[ $EVT_ID ]);
2085
+			}
2086
+			update_option('ee_no_ticket_prices', $espresso_no_ticket_prices);
2087
+		} else {
2088
+			$success = false;
2089
+			$msg = esc_html__(
2090
+				'An error occurred. An event could not be deleted because a valid event ID was not not supplied.',
2091
+				'event_espresso'
2092
+			);
2093
+			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2094
+		}
2095
+		if ($redirect_after) {
2096
+			$this->_redirect_after_action(
2097
+				$success,
2098
+				'Event',
2099
+				'deleted',
2100
+				array('action' => 'default', 'status' => 'trash')
2101
+			);
2102
+		}
2103
+	}
2104
+
2105
+
2106
+	/**
2107
+	 * _delete_events
2108
+	 *
2109
+	 * @access protected
2110
+	 * @return void
2111
+	 */
2112
+	protected function _delete_events()
2113
+	{
2114
+		$success = true;
2115
+		// get list of events with no prices
2116
+		$espresso_no_ticket_prices = get_option('ee_no_ticket_prices', array());
2117
+		// determine the event id and set to array.
2118
+		$EVT_IDs = isset($this->_req_data['EVT_IDs']) ? (array) $this->_req_data['EVT_IDs'] : array();
2119
+		// loop thru events
2120
+		foreach ($EVT_IDs as $EVT_ID) {
2121
+			$EVT_ID = absint($EVT_ID);
2122
+			if ($EVT_ID) {
2123
+				$results = $this->_permanently_delete_event($EVT_ID);
2124
+				$success = $results !== false ? $success : false;
2125
+				// remove this event from the list of events with no prices
2126
+				unset($espresso_no_ticket_prices[ $EVT_ID ]);
2127
+			} else {
2128
+				$success = false;
2129
+				$msg = esc_html__(
2130
+					'An error occurred. An event could not be deleted because a valid event ID was not not supplied.',
2131
+					'event_espresso'
2132
+				);
2133
+				EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2134
+			}
2135
+		}
2136
+		update_option('ee_no_ticket_prices', $espresso_no_ticket_prices);
2137
+		// in order to force a pluralized result message we need to send back a success status greater than 1
2138
+		$success = $success ? 2 : false;
2139
+		$this->_redirect_after_action($success, 'Events', 'deleted', array('action' => 'default'));
2140
+	}
2141
+
2142
+
2143
+	/**
2144
+	 * _permanently_delete_event
2145
+	 *
2146
+	 * @access  private
2147
+	 * @param  int $EVT_ID
2148
+	 * @return bool
2149
+	 */
2150
+	private function _permanently_delete_event($EVT_ID = 0)
2151
+	{
2152
+		// grab event id
2153
+		if (! $EVT_ID) {
2154
+			$msg = esc_html__(
2155
+				'An error occurred. No Event ID or an invalid Event ID was received.',
2156
+				'event_espresso'
2157
+			);
2158
+			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2159
+			return false;
2160
+		}
2161
+		if (! $this->_cpt_model_obj instanceof EE_Event
2162
+			|| $this->_cpt_model_obj->ID() !== $EVT_ID
2163
+		) {
2164
+			$this->_cpt_model_obj = EEM_Event::instance()->get_one_by_ID($EVT_ID);
2165
+		}
2166
+		if (! $this->_cpt_model_obj instanceof EE_Event) {
2167
+			return false;
2168
+		}
2169
+		// need to delete related tickets and prices first.
2170
+		$datetimes = $this->_cpt_model_obj->get_many_related('Datetime');
2171
+		foreach ($datetimes as $datetime) {
2172
+			$this->_cpt_model_obj->_remove_relation_to($datetime, 'Datetime');
2173
+			$tickets = $datetime->get_many_related('Ticket');
2174
+			foreach ($tickets as $ticket) {
2175
+				$ticket->_remove_relation_to($datetime, 'Datetime');
2176
+				$ticket->delete_related_permanently('Price');
2177
+				$ticket->delete_permanently();
2178
+			}
2179
+			$datetime->delete();
2180
+		}
2181
+		// what about related venues or terms?
2182
+		$venues = $this->_cpt_model_obj->get_many_related('Venue');
2183
+		foreach ($venues as $venue) {
2184
+			$this->_cpt_model_obj->_remove_relation_to($venue, 'Venue');
2185
+		}
2186
+		// any attached question groups?
2187
+		$question_groups = $this->_cpt_model_obj->get_many_related('Question_Group');
2188
+		if (! empty($question_groups)) {
2189
+			foreach ($question_groups as $question_group) {
2190
+				$this->_cpt_model_obj->_remove_relation_to($question_group, 'Question_Group');
2191
+			}
2192
+		}
2193
+		// Message Template Groups
2194
+		$this->_cpt_model_obj->_remove_relations('Message_Template_Group');
2195
+		/** @type EE_Term_Taxonomy[] $term_taxonomies */
2196
+		$term_taxonomies = $this->_cpt_model_obj->term_taxonomies();
2197
+		foreach ($term_taxonomies as $term_taxonomy) {
2198
+			$this->_cpt_model_obj->remove_relation_to_term_taxonomy($term_taxonomy);
2199
+		}
2200
+		$success = $this->_cpt_model_obj->delete_permanently();
2201
+		// did it all go as planned ?
2202
+		if ($success) {
2203
+			$msg = sprintf(esc_html__('Event ID # %d has been deleted.', 'event_espresso'), $EVT_ID);
2204
+			EE_Error::add_success($msg);
2205
+		} else {
2206
+			$msg = sprintf(
2207
+				esc_html__('An error occurred. Event ID # %d could not be deleted.', 'event_espresso'),
2208
+				$EVT_ID
2209
+			);
2210
+			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2211
+			return false;
2212
+		}
2213
+		do_action('AHEE__Events_Admin_Page___permanently_delete_event__after_event_deleted', $EVT_ID);
2214
+		return true;
2215
+	}
2216
+
2217
+
2218
+	/**
2219
+	 * get total number of events
2220
+	 *
2221
+	 * @access public
2222
+	 * @return int
2223
+	 */
2224
+	public function total_events()
2225
+	{
2226
+		$count = EEM_Event::instance()->count(array('caps' => 'read_admin'), 'EVT_ID', true);
2227
+		return $count;
2228
+	}
2229
+
2230
+
2231
+	/**
2232
+	 * get total number of draft events
2233
+	 *
2234
+	 * @access public
2235
+	 * @return int
2236
+	 */
2237
+	public function total_events_draft()
2238
+	{
2239
+		$where = array(
2240
+			'status' => array('IN', array('draft', 'auto-draft')),
2241
+		);
2242
+		$count = EEM_Event::instance()->count(array($where, 'caps' => 'read_admin'), 'EVT_ID', true);
2243
+		return $count;
2244
+	}
2245
+
2246
+
2247
+	/**
2248
+	 * get total number of trashed events
2249
+	 *
2250
+	 * @access public
2251
+	 * @return int
2252
+	 */
2253
+	public function total_trashed_events()
2254
+	{
2255
+		$where = array(
2256
+			'status' => 'trash',
2257
+		);
2258
+		$count = EEM_Event::instance()->count(array($where, 'caps' => 'read_admin'), 'EVT_ID', true);
2259
+		return $count;
2260
+	}
2261
+
2262
+
2263
+	/**
2264
+	 *    _default_event_settings
2265
+	 *    This generates the Default Settings Tab
2266
+	 *
2267
+	 * @return void
2268
+	 * @throws EE_Error
2269
+	 */
2270
+	protected function _default_event_settings()
2271
+	{
2272
+		$this->_set_add_edit_form_tags('update_default_event_settings');
2273
+		$this->_set_publish_post_box_vars(null, false, false, null, false);
2274
+		$this->_template_args['admin_page_content'] = $this->_default_event_settings_form()->get_html();
2275
+		$this->display_admin_page_with_sidebar();
2276
+	}
2277
+
2278
+
2279
+	/**
2280
+	 * Return the form for event settings.
2281
+	 *
2282
+	 * @return EE_Form_Section_Proper
2283
+	 * @throws EE_Error
2284
+	 */
2285
+	protected function _default_event_settings_form()
2286
+	{
2287
+		$registration_config = EE_Registry::instance()->CFG->registration;
2288
+		$registration_stati_for_selection = EEM_Registration::reg_status_array(
2289
+			// exclude
2290
+			array(
2291
+				EEM_Registration::status_id_cancelled,
2292
+				EEM_Registration::status_id_declined,
2293
+				EEM_Registration::status_id_incomplete,
2294
+				EEM_Registration::status_id_wait_list,
2295
+			),
2296
+			true
2297
+		);
2298
+		return new EE_Form_Section_Proper(
2299
+			array(
2300
+				'name'            => 'update_default_event_settings',
2301
+				'html_id'         => 'update_default_event_settings',
2302
+				'html_class'      => 'form-table',
2303
+				'layout_strategy' => new EE_Admin_Two_Column_Layout(),
2304
+				'subsections'     => apply_filters(
2305
+					'FHEE__Events_Admin_Page___default_event_settings_form__form_subsections',
2306
+					array(
2307
+						'default_reg_status'  => new EE_Select_Input(
2308
+							$registration_stati_for_selection,
2309
+							array(
2310
+								'default'         => isset($registration_config->default_STS_ID)
2311
+													 && array_key_exists(
2312
+														 $registration_config->default_STS_ID,
2313
+														 $registration_stati_for_selection
2314
+													 )
2315
+									? sanitize_text_field($registration_config->default_STS_ID)
2316
+									: EEM_Registration::status_id_pending_payment,
2317
+								'html_label_text' => esc_html__('Default Registration Status', 'event_espresso')
2318
+													 . EEH_Template::get_help_tab_link(
2319
+														 'default_settings_status_help_tab'
2320
+													 ),
2321
+								'html_help_text'  => esc_html__(
2322
+									'This setting allows you to preselect what the default registration status setting is when creating an event.  Note that changing this setting does NOT retroactively apply it to existing events.',
2323
+									'event_espresso'
2324
+								),
2325
+							)
2326
+						),
2327
+						'default_max_tickets' => new EE_Integer_Input(
2328
+							array(
2329
+								'default'         => isset($registration_config->default_maximum_number_of_tickets)
2330
+									? $registration_config->default_maximum_number_of_tickets
2331
+									: EEM_Event::get_default_additional_limit(),
2332
+								'html_label_text' => esc_html__(
2333
+									'Default Maximum Tickets Allowed Per Order:',
2334
+									'event_espresso'
2335
+								)
2336
+													 . EEH_Template::get_help_tab_link(
2337
+														 'default_maximum_tickets_help_tab"'
2338
+													 ),
2339
+								'html_help_text'  => esc_html__(
2340
+									'This setting allows you to indicate what will be the default for the maximum number of tickets per order when creating new events.',
2341
+									'event_espresso'
2342
+								),
2343
+							)
2344
+						),
2345
+					)
2346
+				),
2347
+			)
2348
+		);
2349
+	}
2350
+
2351
+
2352
+	/**
2353
+	 * _update_default_event_settings
2354
+	 *
2355
+	 * @access protected
2356
+	 * @return void
2357
+	 * @throws EE_Error
2358
+	 */
2359
+	protected function _update_default_event_settings()
2360
+	{
2361
+		$registration_config = EE_Registry::instance()->CFG->registration;
2362
+		$form = $this->_default_event_settings_form();
2363
+		if ($form->was_submitted()) {
2364
+			$form->receive_form_submission();
2365
+			if ($form->is_valid()) {
2366
+				$valid_data = $form->valid_data();
2367
+				if (isset($valid_data['default_reg_status'])) {
2368
+					$registration_config->default_STS_ID = $valid_data['default_reg_status'];
2369
+				}
2370
+				if (isset($valid_data['default_max_tickets'])) {
2371
+					$registration_config->default_maximum_number_of_tickets = $valid_data['default_max_tickets'];
2372
+				}
2373
+				// update because data was valid!
2374
+				EE_Registry::instance()->CFG->update_espresso_config();
2375
+				EE_Error::overwrite_success();
2376
+				EE_Error::add_success(
2377
+					__('Default Event Settings were updated', 'event_espresso')
2378
+				);
2379
+			}
2380
+		}
2381
+		$this->_redirect_after_action(0, '', '', array('action' => 'default_event_settings'), true);
2382
+	}
2383
+
2384
+
2385
+	/*************        Templates        *************/
2386
+	protected function _template_settings()
2387
+	{
2388
+		$this->_admin_page_title = esc_html__('Template Settings (Preview)', 'event_espresso');
2389
+		$this->_template_args['preview_img'] = '<img src="'
2390
+											   . EVENTS_ASSETS_URL
2391
+											   . DS
2392
+											   . 'images'
2393
+											   . DS
2394
+											   . 'caffeinated_template_features.jpg" alt="'
2395
+											   . esc_attr__('Template Settings Preview screenshot', 'event_espresso')
2396
+											   . '" />';
2397
+		$this->_template_args['preview_text'] = '<strong>'
2398
+												. esc_html__(
2399
+													'Template Settings is a feature that is only available in the premium version of Event Espresso 4 which is available with a support license purchase on EventEspresso.com. Template Settings allow you to configure some of the appearance options for both the Event List and Event Details pages.',
2400
+													'event_espresso'
2401
+												) . '</strong>';
2402
+		$this->display_admin_caf_preview_page('template_settings_tab');
2403
+	}
2404
+
2405
+
2406
+	/** Event Category Stuff **/
2407
+	/**
2408
+	 * set the _category property with the category object for the loaded page.
2409
+	 *
2410
+	 * @access private
2411
+	 * @return void
2412
+	 */
2413
+	private function _set_category_object()
2414
+	{
2415
+		if (isset($this->_category->id) && ! empty($this->_category->id)) {
2416
+			return;
2417
+		} //already have the category object so get out.
2418
+		// set default category object
2419
+		$this->_set_empty_category_object();
2420
+		// only set if we've got an id
2421
+		if (! isset($this->_req_data['EVT_CAT_ID'])) {
2422
+			return;
2423
+		}
2424
+		$category_id = absint($this->_req_data['EVT_CAT_ID']);
2425
+		$term = get_term($category_id, EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY);
2426
+		if (! empty($term)) {
2427
+			$this->_category->category_name = $term->name;
2428
+			$this->_category->category_identifier = $term->slug;
2429
+			$this->_category->category_desc = $term->description;
2430
+			$this->_category->id = $term->term_id;
2431
+			$this->_category->parent = $term->parent;
2432
+		}
2433
+	}
2434
+
2435
+
2436
+	/**
2437
+	 * Clears out category properties.
2438
+	 */
2439
+	private function _set_empty_category_object()
2440
+	{
2441
+		$this->_category = new stdClass();
2442
+		$this->_category->category_name = $this->_category->category_identifier = $this->_category->category_desc = '';
2443
+		$this->_category->id = $this->_category->parent = 0;
2444
+	}
2445
+
2446
+
2447
+	/**
2448
+	 * @throws EE_Error
2449
+	 */
2450
+	protected function _category_list_table()
2451
+	{
2452
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
2453
+		$this->_search_btn_label = esc_html__('Categories', 'event_espresso');
2454
+		$this->_admin_page_title .= ' ' . $this->get_action_link_or_button(
2455
+			'add_category',
2456
+			'add_category',
2457
+			array(),
2458
+			'add-new-h2'
2459
+		);
2460
+		$this->display_admin_list_table_page_with_sidebar();
2461
+	}
2462
+
2463
+
2464
+	/**
2465
+	 * Output category details view.
2466
+	 */
2467
+	protected function _category_details($view)
2468
+	{
2469
+		// load formatter helper
2470
+		// load field generator helper
2471
+		$route = $view == 'edit' ? 'update_category' : 'insert_category';
2472
+		$this->_set_add_edit_form_tags($route);
2473
+		$this->_set_category_object();
2474
+		$id = ! empty($this->_category->id) ? $this->_category->id : '';
2475
+		$delete_action = 'delete_category';
2476
+		// custom redirect
2477
+		$redirect = EE_Admin_Page::add_query_args_and_nonce(
2478
+			array('action' => 'category_list'),
2479
+			$this->_admin_base_url
2480
+		);
2481
+		$this->_set_publish_post_box_vars('EVT_CAT_ID', $id, $delete_action, $redirect);
2482
+		// take care of contents
2483
+		$this->_template_args['admin_page_content'] = $this->_category_details_content();
2484
+		$this->display_admin_page_with_sidebar();
2485
+	}
2486
+
2487
+
2488
+	/**
2489
+	 * Output category details content.
2490
+	 */
2491
+	protected function _category_details_content()
2492
+	{
2493
+		$editor_args['category_desc'] = array(
2494
+			'type'          => 'wp_editor',
2495
+			'value'         => EEH_Formatter::admin_format_content($this->_category->category_desc),
2496
+			'class'         => 'my_editor_custom',
2497
+			'wpeditor_args' => array('media_buttons' => false),
2498
+		);
2499
+		$_wp_editor = $this->_generate_admin_form_fields($editor_args, 'array');
2500
+		$all_terms = get_terms(
2501
+			array(EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY),
2502
+			array('hide_empty' => 0, 'exclude' => array($this->_category->id))
2503
+		);
2504
+		// setup category select for term parents.
2505
+		$category_select_values[] = array(
2506
+			'text' => esc_html__('No Parent', 'event_espresso'),
2507
+			'id'   => 0,
2508
+		);
2509
+		foreach ($all_terms as $term) {
2510
+			$category_select_values[] = array(
2511
+				'text' => $term->name,
2512
+				'id'   => $term->term_id,
2513
+			);
2514
+		}
2515
+		$category_select = EEH_Form_Fields::select_input(
2516
+			'category_parent',
2517
+			$category_select_values,
2518
+			$this->_category->parent
2519
+		);
2520
+		$template_args = array(
2521
+			'category'                 => $this->_category,
2522
+			'category_select'          => $category_select,
2523
+			'unique_id_info_help_link' => $this->_get_help_tab_link('unique_id_info'),
2524
+			'category_desc_editor'     => $_wp_editor['category_desc']['field'],
2525
+			'disable'                  => '',
2526
+			'disabled_message'         => false,
2527
+		);
2528
+		$template = EVENTS_TEMPLATE_PATH . 'event_category_details.template.php';
2529
+		return EEH_Template::display_template($template, $template_args, true);
2530
+	}
2531
+
2532
+
2533
+	/**
2534
+	 * Handles deleting categories.
2535
+	 */
2536
+	protected function _delete_categories()
2537
+	{
2538
+		$cat_ids = isset($this->_req_data['EVT_CAT_ID']) ? (array) $this->_req_data['EVT_CAT_ID']
2539
+			: (array) $this->_req_data['category_id'];
2540
+		foreach ($cat_ids as $cat_id) {
2541
+			$this->_delete_category($cat_id);
2542
+		}
2543
+		// doesn't matter what page we're coming from... we're going to the same place after delete.
2544
+		$query_args = array(
2545
+			'action' => 'category_list',
2546
+		);
2547
+		$this->_redirect_after_action(0, '', '', $query_args);
2548
+	}
2549
+
2550
+
2551
+	/**
2552
+	 * Handles deleting specific category.
2553
+	 *
2554
+	 * @param int $cat_id
2555
+	 */
2556
+	protected function _delete_category($cat_id)
2557
+	{
2558
+		$cat_id = absint($cat_id);
2559
+		wp_delete_term($cat_id, EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY);
2560
+	}
2561
+
2562
+
2563
+	/**
2564
+	 * Handles triggering the update or insertion of a new category.
2565
+	 *
2566
+	 * @param bool $new_category true means we're triggering the insert of a new category.
2567
+	 */
2568
+	protected function _insert_or_update_category($new_category)
2569
+	{
2570
+		$cat_id = $new_category ? $this->_insert_category() : $this->_insert_category(true);
2571
+		$success = 0; // we already have a success message so lets not send another.
2572
+		if ($cat_id) {
2573
+			$query_args = array(
2574
+				'action'     => 'edit_category',
2575
+				'EVT_CAT_ID' => $cat_id,
2576
+			);
2577
+		} else {
2578
+			$query_args = array('action' => 'add_category');
2579
+		}
2580
+		$this->_redirect_after_action($success, '', '', $query_args, true);
2581
+	}
2582
+
2583
+
2584
+	/**
2585
+	 * Inserts or updates category
2586
+	 *
2587
+	 * @param bool $update (true indicates we're updating a category).
2588
+	 * @return bool|mixed|string
2589
+	 */
2590
+	private function _insert_category($update = false)
2591
+	{
2592
+		$cat_id = $update ? $this->_req_data['EVT_CAT_ID'] : '';
2593
+		$category_name = isset($this->_req_data['category_name']) ? $this->_req_data['category_name'] : '';
2594
+		$category_desc = isset($this->_req_data['category_desc']) ? $this->_req_data['category_desc'] : '';
2595
+		$category_parent = isset($this->_req_data['category_parent']) ? $this->_req_data['category_parent'] : 0;
2596
+		if (empty($category_name)) {
2597
+			$msg = esc_html__('You must add a name for the category.', 'event_espresso');
2598
+			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2599
+			return false;
2600
+		}
2601
+		$term_args = array(
2602
+			'name'        => $category_name,
2603
+			'description' => $category_desc,
2604
+			'parent'      => $category_parent,
2605
+		);
2606
+		// was the category_identifier input disabled?
2607
+		if (isset($this->_req_data['category_identifier'])) {
2608
+			$term_args['slug'] = $this->_req_data['category_identifier'];
2609
+		}
2610
+		$insert_ids = $update
2611
+			? wp_update_term($cat_id, EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY, $term_args)
2612
+			: wp_insert_term($category_name, EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY, $term_args);
2613
+		if (! is_array($insert_ids)) {
2614
+			$msg = esc_html__(
2615
+				'An error occurred and the category has not been saved to the database.',
2616
+				'event_espresso'
2617
+			);
2618
+			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2619
+		} else {
2620
+			$cat_id = $insert_ids['term_id'];
2621
+			$msg = sprintf(esc_html__('The category %s was successfully saved', 'event_espresso'), $category_name);
2622
+			EE_Error::add_success($msg);
2623
+		}
2624
+		return $cat_id;
2625
+	}
2626
+
2627
+
2628
+	/**
2629
+	 * Gets categories or count of categories matching the arguments in the request.
2630
+	 *
2631
+	 * @param int  $per_page
2632
+	 * @param int  $current_page
2633
+	 * @param bool $count
2634
+	 * @return EE_Base_Class[]|EE_Term_Taxonomy[]|int
2635
+	 */
2636
+	public function get_categories($per_page = 10, $current_page = 1, $count = false)
2637
+	{
2638
+		// testing term stuff
2639
+		$orderby = isset($this->_req_data['orderby']) ? $this->_req_data['orderby'] : 'Term.term_id';
2640
+		$order = isset($this->_req_data['order']) ? $this->_req_data['order'] : 'DESC';
2641
+		$limit = ($current_page - 1) * $per_page;
2642
+		$where = array('taxonomy' => EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY);
2643
+		if (isset($this->_req_data['s'])) {
2644
+			$sstr = '%' . $this->_req_data['s'] . '%';
2645
+			$where['OR'] = array(
2646
+				'Term.name'   => array('LIKE', $sstr),
2647
+				'description' => array('LIKE', $sstr),
2648
+			);
2649
+		}
2650
+		$query_params = array(
2651
+			$where,
2652
+			'order_by'   => array($orderby => $order),
2653
+			'limit'      => $limit . ',' . $per_page,
2654
+			'force_join' => array('Term'),
2655
+		);
2656
+		$categories = $count
2657
+			? EEM_Term_Taxonomy::instance()->count($query_params, 'term_id')
2658
+			: EEM_Term_Taxonomy::instance()->get_all($query_params);
2659
+		return $categories;
2660
+	}
2661
+
2662
+	/* end category stuff */
2663
+	/**************/
2664
+
2665
+
2666
+	/**
2667
+	 * Callback for the `ee_save_timezone_setting` ajax action.
2668
+	 *
2669
+	 * @throws EE_Error
2670
+	 */
2671
+	public function save_timezonestring_setting()
2672
+	{
2673
+		$timezone_string = isset($this->_req_data['timezone_selected'])
2674
+			? $this->_req_data['timezone_selected']
2675
+			: '';
2676
+		if (empty($timezone_string) || ! EEH_DTT_Helper::validate_timezone($timezone_string, false)) {
2677
+			EE_Error::add_error(
2678
+				esc_html__('An invalid timezone string submitted.', 'event_espresso'),
2679
+				__FILE__,
2680
+				__FUNCTION__,
2681
+				__LINE__
2682
+			);
2683
+			$this->_template_args['error'] = true;
2684
+			$this->_return_json();
2685
+		}
2686
+
2687
+		update_option('timezone_string', $timezone_string);
2688
+		EE_Error::add_success(
2689
+			esc_html__('Your timezone string was updated.', 'event_espresso')
2690
+		);
2691
+		$this->_template_args['success'] = true;
2692
+		$this->_return_json(true, array('action' => 'create_new'));
2693
+	}
2694 2694
 }
Please login to merge, or discard this patch.
Spacing   +67 added lines, -67 removed lines patch added patch discarded remove patch
@@ -548,11 +548,11 @@  discard block
 block discarded – undo
548 548
     {
549 549
         wp_register_style(
550 550
             'events-admin-css',
551
-            EVENTS_ASSETS_URL . 'events-admin-page.css',
551
+            EVENTS_ASSETS_URL.'events-admin-page.css',
552 552
             array(),
553 553
             EVENT_ESPRESSO_VERSION
554 554
         );
555
-        wp_register_style('ee-cat-admin', EVENTS_ASSETS_URL . 'ee-cat-admin.css', array(), EVENT_ESPRESSO_VERSION);
555
+        wp_register_style('ee-cat-admin', EVENTS_ASSETS_URL.'ee-cat-admin.css', array(), EVENT_ESPRESSO_VERSION);
556 556
         wp_enqueue_style('events-admin-css');
557 557
         wp_enqueue_style('ee-cat-admin');
558 558
         // todo note: we also need to load_scripts_styles per view (i.e. default/view_report/event_details
@@ -560,19 +560,19 @@  discard block
 block discarded – undo
560 560
         // scripts
561 561
         wp_register_script(
562 562
             'event_editor_js',
563
-            EVENTS_ASSETS_URL . 'event_editor.js',
563
+            EVENTS_ASSETS_URL.'event_editor.js',
564 564
             array('ee_admin_js', 'jquery-ui-slider', 'jquery-ui-timepicker-addon'),
565 565
             EVENT_ESPRESSO_VERSION,
566 566
             true
567 567
         );
568 568
         add_action(
569 569
             'admin_footer',
570
-            function () {
570
+            function() {
571 571
                 $eventId = isset($_REQUEST['post']) ? absint($_REQUEST['post']) : 0;
572 572
                 if ($eventId) {
573 573
                     echo '
574 574
         <script type="text/javascript">
575
-            /* <![CDATA[ */ var eeEditorEventId = ' . $eventId . ' /* ]]> */
575
+            /* <![CDATA[ */ var eeEditorEventId = ' . $eventId.' /* ]]> */
576 576
         </script>';
577 577
                 }
578 578
             }
@@ -598,7 +598,7 @@  discard block
 block discarded – undo
598 598
         wp_enqueue_style('espresso-ui-theme');
599 599
         wp_register_style(
600 600
             'event-editor-css',
601
-            EVENTS_ASSETS_URL . 'event-editor.css',
601
+            EVENTS_ASSETS_URL.'event-editor.css',
602 602
             array('ee-admin-css'),
603 603
             EVENT_ESPRESSO_VERSION
604 604
         );
@@ -606,7 +606,7 @@  discard block
 block discarded – undo
606 606
         // scripts
607 607
         wp_register_script(
608 608
             'event-datetime-metabox',
609
-            EVENTS_ASSETS_URL . 'event-datetime-metabox.js',
609
+            EVENTS_ASSETS_URL.'event-datetime-metabox.js',
610 610
             array('event_editor_js', 'ee-datepicker'),
611 611
             EVENT_ESPRESSO_VERSION
612 612
         );
@@ -675,7 +675,7 @@  discard block
 block discarded – undo
675 675
     public function verify_event_edit($event = null, $req_type = '')
676 676
     {
677 677
         // don't need to do this when processing
678
-        if (! empty($req_type)) {
678
+        if ( ! empty($req_type)) {
679 679
             return;
680 680
         }
681 681
         // no event?
@@ -684,7 +684,7 @@  discard block
 block discarded – undo
684 684
             $event = $this->_cpt_model_obj;
685 685
         }
686 686
         // STILL no event?
687
-        if (! $event instanceof EE_Event) {
687
+        if ( ! $event instanceof EE_Event) {
688 688
             return;
689 689
         }
690 690
         $orig_status = $event->status();
@@ -722,7 +722,7 @@  discard block
 block discarded – undo
722 722
             );
723 723
         }
724 724
         // now we need to determine if the event has any tickets on sale.  If not then we dont' show the error
725
-        if (! $event->tickets_on_sale()) {
725
+        if ( ! $event->tickets_on_sale()) {
726 726
             return;
727 727
         }
728 728
         // made it here so show warning
@@ -767,7 +767,7 @@  discard block
 block discarded – undo
767 767
     {
768 768
         $has_timezone_string = get_option('timezone_string');
769 769
         // only nag them about setting their timezone if it's their first event, and they haven't already done it
770
-        if (! $has_timezone_string && ! EEM_Event::instance()->exists(array())) {
770
+        if ( ! $has_timezone_string && ! EEM_Event::instance()->exists(array())) {
771 771
             EE_Error::add_attention(
772 772
                 sprintf(
773 773
                     __(
@@ -851,31 +851,31 @@  discard block
 block discarded – undo
851 851
         $items = apply_filters('FHEE__Events_Admin_Page___event_legend_items__items', $items);
852 852
         $statuses = array(
853 853
             'sold_out_status'  => array(
854
-                'class' => 'ee-status-legend ee-status-legend-' . EE_Datetime::sold_out,
854
+                'class' => 'ee-status-legend ee-status-legend-'.EE_Datetime::sold_out,
855 855
                 'desc'  => EEH_Template::pretty_status(EE_Datetime::sold_out, false, 'sentence'),
856 856
             ),
857 857
             'active_status'    => array(
858
-                'class' => 'ee-status-legend ee-status-legend-' . EE_Datetime::active,
858
+                'class' => 'ee-status-legend ee-status-legend-'.EE_Datetime::active,
859 859
                 'desc'  => EEH_Template::pretty_status(EE_Datetime::active, false, 'sentence'),
860 860
             ),
861 861
             'upcoming_status'  => array(
862
-                'class' => 'ee-status-legend ee-status-legend-' . EE_Datetime::upcoming,
862
+                'class' => 'ee-status-legend ee-status-legend-'.EE_Datetime::upcoming,
863 863
                 'desc'  => EEH_Template::pretty_status(EE_Datetime::upcoming, false, 'sentence'),
864 864
             ),
865 865
             'postponed_status' => array(
866
-                'class' => 'ee-status-legend ee-status-legend-' . EE_Datetime::postponed,
866
+                'class' => 'ee-status-legend ee-status-legend-'.EE_Datetime::postponed,
867 867
                 'desc'  => EEH_Template::pretty_status(EE_Datetime::postponed, false, 'sentence'),
868 868
             ),
869 869
             'cancelled_status' => array(
870
-                'class' => 'ee-status-legend ee-status-legend-' . EE_Datetime::cancelled,
870
+                'class' => 'ee-status-legend ee-status-legend-'.EE_Datetime::cancelled,
871 871
                 'desc'  => EEH_Template::pretty_status(EE_Datetime::cancelled, false, 'sentence'),
872 872
             ),
873 873
             'expired_status'   => array(
874
-                'class' => 'ee-status-legend ee-status-legend-' . EE_Datetime::expired,
874
+                'class' => 'ee-status-legend ee-status-legend-'.EE_Datetime::expired,
875 875
                 'desc'  => EEH_Template::pretty_status(EE_Datetime::expired, false, 'sentence'),
876 876
             ),
877 877
             'inactive_status'  => array(
878
-                'class' => 'ee-status-legend ee-status-legend-' . EE_Datetime::inactive,
878
+                'class' => 'ee-status-legend ee-status-legend-'.EE_Datetime::inactive,
879 879
                 'desc'  => EEH_Template::pretty_status(EE_Datetime::inactive, false, 'sentence'),
880 880
             ),
881 881
         );
@@ -889,7 +889,7 @@  discard block
 block discarded – undo
889 889
      */
890 890
     private function _event_model()
891 891
     {
892
-        if (! $this->_event_model instanceof EEM_Event) {
892
+        if ( ! $this->_event_model instanceof EEM_Event) {
893 893
             $this->_event_model = EE_Registry::instance()->load_model('Event');
894 894
         }
895 895
         return $this->_event_model;
@@ -909,7 +909,7 @@  discard block
 block discarded – undo
909 909
     public function extra_permalink_field_buttons($return, $id, $new_title, $new_slug)
910 910
     {
911 911
         // make sure this is only when editing
912
-        if (! empty($id)) {
912
+        if ( ! empty($id)) {
913 913
             $post = get_post($id);
914 914
             $return .= '<a class="button button-small" onclick="prompt(\'Shortcode:\', jQuery(\'#shortcode\').val()); return false;" href="#"  tabindex="-1">'
915 915
                        . esc_html__('Shortcode', 'event_espresso')
@@ -943,7 +943,7 @@  discard block
 block discarded – undo
943 943
                     'button'
944 944
                 );
945 945
         $this->_template_args['after_list_table']['legend'] = $this->_display_legend($this->_event_legend_items());
946
-        $this->_admin_page_title .= ' ' . $this->get_action_link_or_button(
946
+        $this->_admin_page_title .= ' '.$this->get_action_link_or_button(
947 947
             'create_new',
948 948
             'add',
949 949
             array(),
@@ -1083,7 +1083,7 @@  discard block
 block discarded – undo
1083 1083
      */
1084 1084
     protected function _default_venue_update(\EE_Event $evtobj, $data)
1085 1085
     {
1086
-        require_once(EE_MODELS . 'EEM_Venue.model.php');
1086
+        require_once(EE_MODELS.'EEM_Venue.model.php');
1087 1087
         $venue_model = EE_Registry::instance()->load_model('Venue');
1088 1088
         $rows_affected = null;
1089 1089
         $venue_id = ! empty($data['venue_id']) ? $data['venue_id'] : null;
@@ -1114,7 +1114,7 @@  discard block
 block discarded – undo
1114 1114
             'status'              => 'publish',
1115 1115
         );
1116 1116
         // if we've got the venue_id then we're just updating the existing venue so let's do that and then get out.
1117
-        if (! empty($venue_id)) {
1117
+        if ( ! empty($venue_id)) {
1118 1118
             $update_where = array($venue_model->primary_key_name() => $venue_id);
1119 1119
             $rows_affected = $venue_model->update($venue_array, array($update_where));
1120 1120
             // we've gotta make sure that the venue is always attached to a revision.. add_relation_to should take care of making sure that the relation is already present.
@@ -1156,7 +1156,7 @@  discard block
 block discarded – undo
1156 1156
                 'DTT_order'     => $row,
1157 1157
             );
1158 1158
             // if we have an id then let's get existing object first and then set the new values.  Otherwise we instantiate a new object for save.
1159
-            if (! empty($dtt['DTT_ID'])) {
1159
+            if ( ! empty($dtt['DTT_ID'])) {
1160 1160
                 $DTM = EE_Registry::instance()
1161 1161
                                   ->load_model('Datetime', array($evtobj->get_timezone()))
1162 1162
                                   ->get_one_by_ID($dtt['DTT_ID']);
@@ -1166,7 +1166,7 @@  discard block
 block discarded – undo
1166 1166
                     $DTM->set($field, $value);
1167 1167
                 }
1168 1168
                 // make sure the $dtt_id here is saved just in case after the add_relation_to() the autosave replaces it.  We need to do this so we dont' TRASH the parent DTT.
1169
-                $saved_dtts[ $DTM->ID() ] = $DTM;
1169
+                $saved_dtts[$DTM->ID()] = $DTM;
1170 1170
             } else {
1171 1171
                 $DTM = EE_Registry::instance()->load_class(
1172 1172
                     'Datetime',
@@ -1199,14 +1199,14 @@  discard block
 block discarded – undo
1199 1199
         foreach ($data['edit_tickets'] as $row => $tkt) {
1200 1200
             $incoming_date_formats = array('Y-m-d', 'h:i a');
1201 1201
             $update_prices = false;
1202
-            $ticket_price = isset($data['edit_prices'][ $row ][1]['PRC_amount'])
1203
-                ? $data['edit_prices'][ $row ][1]['PRC_amount'] : 0;
1202
+            $ticket_price = isset($data['edit_prices'][$row][1]['PRC_amount'])
1203
+                ? $data['edit_prices'][$row][1]['PRC_amount'] : 0;
1204 1204
             // trim inputs to ensure any excess whitespace is removed.
1205 1205
             $tkt = array_map('trim', $tkt);
1206 1206
             if (empty($tkt['TKT_start_date'])) {
1207 1207
                 // let's use now in the set timezone.
1208 1208
                 $now = new DateTime('now', new DateTimeZone($evtobj->get_timezone()));
1209
-                $tkt['TKT_start_date'] = $now->format($incoming_date_formats[0] . ' ' . $incoming_date_formats[1]);
1209
+                $tkt['TKT_start_date'] = $now->format($incoming_date_formats[0].' '.$incoming_date_formats[1]);
1210 1210
             }
1211 1211
             if (empty($tkt['TKT_end_date'])) {
1212 1212
                 // use the start date of the first datetime
@@ -1241,7 +1241,7 @@  discard block
 block discarded – undo
1241 1241
             // if we have a TKT_ID then we need to get that existing TKT_obj and update it
1242 1242
             // we actually do our saves a head of doing any add_relations to because its entirely possible that this ticket didn't removed or added to any datetime in the session but DID have it's items modified.
1243 1243
             // keep in mind that if the TKT has been sold (and we have changed pricing information), then we won't be updating the tkt but instead a new tkt will be created and the old one archived.
1244
-            if (! empty($tkt['TKT_ID'])) {
1244
+            if ( ! empty($tkt['TKT_ID'])) {
1245 1245
                 $TKT = EE_Registry::instance()
1246 1246
                                   ->load_model('Ticket', array($evtobj->get_timezone()))
1247 1247
                                   ->get_one_by_ID($tkt['TKT_ID']);
@@ -1276,7 +1276,7 @@  discard block
 block discarded – undo
1276 1276
                         $TKT->set('TKT_deleted', 1);
1277 1277
                         $TKT->save();
1278 1278
                         // make sure this ticket is still recorded in our saved_tkts so we don't run it through the regular trash routine.
1279
-                        $saved_tickets[ $TKT->ID() ] = $TKT;
1279
+                        $saved_tickets[$TKT->ID()] = $TKT;
1280 1280
                         // create new ticket that's a copy of the existing except a new id of course (and not archived) AND has the new TKT_price associated with it.
1281 1281
                         $TKT = clone $TKT;
1282 1282
                         $TKT->set('TKT_ID', 0);
@@ -1321,9 +1321,9 @@  discard block
 block discarded – undo
1321 1321
             }
1322 1322
             // initially let's add the ticket to the dtt
1323 1323
             $saved_dtt->_add_relation_to($TKT, 'Ticket');
1324
-            $saved_tickets[ $TKT->ID() ] = $TKT;
1324
+            $saved_tickets[$TKT->ID()] = $TKT;
1325 1325
             // add prices to ticket
1326
-            $this->_add_prices_to_ticket($data['edit_prices'][ $row ], $TKT, $update_prices);
1326
+            $this->_add_prices_to_ticket($data['edit_prices'][$row], $TKT, $update_prices);
1327 1327
         }
1328 1328
         // however now we need to handle permanently deleting tickets via the ui.  Keep in mind that the ui does not allow deleting/archiving tickets that have ticket sold.  However, it does allow for deleting tickets that have no tickets sold, in which case we want to get rid of permanently because there is no need to save in db.
1329 1329
         $old_tickets = isset($old_tickets[0]) && $old_tickets[0] == '' ? array() : $old_tickets;
@@ -1480,7 +1480,7 @@  discard block
 block discarded – undo
1480 1480
         $publish_box_extra_args['event_editor_overview_add'] = ob_get_clean();
1481 1481
         // load template
1482 1482
         EEH_Template::display_template(
1483
-            EVENTS_TEMPLATE_PATH . 'event_publish_box_extras.template.php',
1483
+            EVENTS_TEMPLATE_PATH.'event_publish_box_extras.template.php',
1484 1484
             $publish_box_extra_args
1485 1485
         );
1486 1486
     }
@@ -1572,7 +1572,7 @@  discard block
 block discarded – undo
1572 1572
                     'default_where_conditions' => 'none',
1573 1573
                 )
1574 1574
             );
1575
-            if (! empty($related_tickets)) {
1575
+            if ( ! empty($related_tickets)) {
1576 1576
                 $template_args['total_ticket_rows'] = count($related_tickets);
1577 1577
                 $row = 0;
1578 1578
                 foreach ($related_tickets as $ticket) {
@@ -1606,7 +1606,7 @@  discard block
 block discarded – undo
1606 1606
         );
1607 1607
         $template = apply_filters(
1608 1608
             'FHEE__Events_Admin_Page__ticket_metabox__template',
1609
-            EVENTS_TEMPLATE_PATH . 'event_tickets_metabox_main.template.php'
1609
+            EVENTS_TEMPLATE_PATH.'event_tickets_metabox_main.template.php'
1610 1610
         );
1611 1611
         EEH_Template::display_template($template, $template_args);
1612 1612
     }
@@ -1624,7 +1624,7 @@  discard block
 block discarded – undo
1624 1624
     private function _get_ticket_row($ticket, $skeleton = false, $row = 0)
1625 1625
     {
1626 1626
         $template_args = array(
1627
-            'tkt_status_class'    => ' tkt-status-' . $ticket->ticket_status(),
1627
+            'tkt_status_class'    => ' tkt-status-'.$ticket->ticket_status(),
1628 1628
             'tkt_archive_class'   => $ticket->ticket_status() === EE_Ticket::archived && ! $skeleton ? ' tkt-archived'
1629 1629
                 : '',
1630 1630
             'ticketrow'           => $skeleton ? 'TICKETNUM' : $row,
@@ -1636,10 +1636,10 @@  discard block
 block discarded – undo
1636 1636
             'TKT_qty'             => $ticket->get_pretty('TKT_qty', 'input'),
1637 1637
             'edit_ticketrow_name' => $skeleton ? 'TICKETNAMEATTR' : 'edit_tickets',
1638 1638
             'TKT_sold'            => $skeleton ? 0 : $ticket->get('TKT_sold'),
1639
-            'trash_icon'          => ($skeleton || (! empty($ticket) && ! $ticket->get('TKT_deleted')))
1640
-                                     && (! empty($ticket) && $ticket->get('TKT_sold') === 0)
1639
+            'trash_icon'          => ($skeleton || ( ! empty($ticket) && ! $ticket->get('TKT_deleted')))
1640
+                                     && ( ! empty($ticket) && $ticket->get('TKT_sold') === 0)
1641 1641
                 ? 'trash-icon dashicons dashicons-post-trash clickable' : 'ee-lock-icon',
1642
-            'disabled'            => $skeleton || (! empty($ticket) && ! $ticket->get('TKT_deleted')) ? ''
1642
+            'disabled'            => $skeleton || ( ! empty($ticket) && ! $ticket->get('TKT_deleted')) ? ''
1643 1643
                 : ' disabled=disabled',
1644 1644
         );
1645 1645
         $price = $ticket->ID() !== 0
@@ -1666,7 +1666,7 @@  discard block
 block discarded – undo
1666 1666
                     array('order_by' => array('DTT_EVT_start' => 'ASC'))
1667 1667
                 )
1668 1668
                 : null;
1669
-            if (! empty($earliest_dtt)) {
1669
+            if ( ! empty($earliest_dtt)) {
1670 1670
                 $template_args['TKT_end_date'] = $earliest_dtt->get_datetime('DTT_EVT_start', 'Y-m-d', 'h:i a');
1671 1671
             } else {
1672 1672
                 $template_args['TKT_end_date'] = date(
@@ -1678,7 +1678,7 @@  discard block
 block discarded – undo
1678 1678
         $template_args = array_merge($template_args, $price_args);
1679 1679
         $template = apply_filters(
1680 1680
             'FHEE__Events_Admin_Page__get_ticket_row__template',
1681
-            EVENTS_TEMPLATE_PATH . 'event_tickets_metabox_ticket_row.template.php',
1681
+            EVENTS_TEMPLATE_PATH.'event_tickets_metabox_ticket_row.template.php',
1682 1682
             $ticket
1683 1683
         );
1684 1684
         return EEH_Template::display_template($template, $template_args, true);
@@ -1732,7 +1732,7 @@  discard block
 block discarded – undo
1732 1732
             $default_reg_status_values
1733 1733
         );
1734 1734
         EEH_Template::display_template(
1735
-            EVENTS_TEMPLATE_PATH . 'event_registration_options.template.php',
1735
+            EVENTS_TEMPLATE_PATH.'event_registration_options.template.php',
1736 1736
             $template_args
1737 1737
         );
1738 1738
     }
@@ -1754,7 +1754,7 @@  discard block
 block discarded – undo
1754 1754
     {
1755 1755
         $EEME = $this->_event_model();
1756 1756
         $offset = ($current_page - 1) * $per_page;
1757
-        $limit = $count ? null : $offset . ',' . $per_page;
1757
+        $limit = $count ? null : $offset.','.$per_page;
1758 1758
         $orderby = isset($this->_req_data['orderby']) ? $this->_req_data['orderby'] : 'EVT_ID';
1759 1759
         $order = isset($this->_req_data['order']) ? $this->_req_data['order'] : "DESC";
1760 1760
         if (isset($this->_req_data['month_range'])) {
@@ -1783,7 +1783,7 @@  discard block
 block discarded – undo
1783 1783
         // categories?
1784 1784
         $category = isset($this->_req_data['EVT_CAT']) && $this->_req_data['EVT_CAT'] > 0
1785 1785
             ? $this->_req_data['EVT_CAT'] : null;
1786
-        if (! empty($category)) {
1786
+        if ( ! empty($category)) {
1787 1787
             $where['Term_Taxonomy.taxonomy'] = EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY;
1788 1788
             $where['Term_Taxonomy.term_id'] = $category;
1789 1789
         }
@@ -1791,7 +1791,7 @@  discard block
 block discarded – undo
1791 1791
         $start_formats = EEM_Datetime::instance()->get_formats_for('DTT_EVT_start');
1792 1792
         if (isset($this->_req_data['month_range']) && $this->_req_data['month_range'] != '') {
1793 1793
             $DateTime = new DateTime(
1794
-                $year_r . '-' . $month_r . '-01 00:00:00',
1794
+                $year_r.'-'.$month_r.'-01 00:00:00',
1795 1795
                 new DateTimeZone(EEM_Datetime::instance()->get_timezone())
1796 1796
             );
1797 1797
             $start = $DateTime->format(implode(' ', $start_formats));
@@ -1817,11 +1817,11 @@  discard block
 block discarded – undo
1817 1817
                             ->format(implode(' ', $start_formats));
1818 1818
             $where['Datetime.DTT_EVT_start'] = array('BETWEEN', array($start, $end));
1819 1819
         }
1820
-        if (! EE_Registry::instance()->CAP->current_user_can('ee_read_others_events', 'get_events')) {
1820
+        if ( ! EE_Registry::instance()->CAP->current_user_can('ee_read_others_events', 'get_events')) {
1821 1821
             $where['EVT_wp_user'] = get_current_user_id();
1822 1822
         } else {
1823
-            if (! isset($where['status'])) {
1824
-                if (! EE_Registry::instance()->CAP->current_user_can('ee_read_private_events', 'get_events')) {
1823
+            if ( ! isset($where['status'])) {
1824
+                if ( ! EE_Registry::instance()->CAP->current_user_can('ee_read_private_events', 'get_events')) {
1825 1825
                     $where['OR'] = array(
1826 1826
                         'status*restrict_private' => array('!=', 'private'),
1827 1827
                         'AND'                     => array(
@@ -1841,7 +1841,7 @@  discard block
 block discarded – undo
1841 1841
         }
1842 1842
         // search query handling
1843 1843
         if (isset($this->_req_data['s'])) {
1844
-            $search_string = '%' . $this->_req_data['s'] . '%';
1844
+            $search_string = '%'.$this->_req_data['s'].'%';
1845 1845
             $where['OR'] = array(
1846 1846
                 'EVT_name'       => array('LIKE', $search_string),
1847 1847
                 'EVT_desc'       => array('LIKE', $search_string),
@@ -1930,7 +1930,7 @@  discard block
 block discarded – undo
1930 1930
             // clean status
1931 1931
             $event_status = sanitize_key($event_status);
1932 1932
             // grab status
1933
-            if (! empty($event_status)) {
1933
+            if ( ! empty($event_status)) {
1934 1934
                 $success = $this->_change_event_status($EVT_ID, $event_status);
1935 1935
             } else {
1936 1936
                 $success = false;
@@ -1967,7 +1967,7 @@  discard block
 block discarded – undo
1967 1967
         // clean status
1968 1968
         $event_status = sanitize_key($event_status);
1969 1969
         // grab status
1970
-        if (! empty($event_status)) {
1970
+        if ( ! empty($event_status)) {
1971 1971
             $success = true;
1972 1972
             // determine the event id and set to array.
1973 1973
             $EVT_IDs = isset($this->_req_data['EVT_IDs']) ? (array) $this->_req_data['EVT_IDs'] : array();
@@ -2014,7 +2014,7 @@  discard block
 block discarded – undo
2014 2014
     private function _change_event_status($EVT_ID = 0, $event_status = '')
2015 2015
     {
2016 2016
         // grab event id
2017
-        if (! $EVT_ID) {
2017
+        if ( ! $EVT_ID) {
2018 2018
             $msg = esc_html__(
2019 2019
                 'An error occurred. No Event ID or an invalid Event ID was received.',
2020 2020
                 'event_espresso'
@@ -2080,8 +2080,8 @@  discard block
 block discarded – undo
2080 2080
             // get list of events with no prices
2081 2081
             $espresso_no_ticket_prices = get_option('ee_no_ticket_prices', array());
2082 2082
             // remove this event from the list of events with no prices
2083
-            if (isset($espresso_no_ticket_prices[ $EVT_ID ])) {
2084
-                unset($espresso_no_ticket_prices[ $EVT_ID ]);
2083
+            if (isset($espresso_no_ticket_prices[$EVT_ID])) {
2084
+                unset($espresso_no_ticket_prices[$EVT_ID]);
2085 2085
             }
2086 2086
             update_option('ee_no_ticket_prices', $espresso_no_ticket_prices);
2087 2087
         } else {
@@ -2123,7 +2123,7 @@  discard block
 block discarded – undo
2123 2123
                 $results = $this->_permanently_delete_event($EVT_ID);
2124 2124
                 $success = $results !== false ? $success : false;
2125 2125
                 // remove this event from the list of events with no prices
2126
-                unset($espresso_no_ticket_prices[ $EVT_ID ]);
2126
+                unset($espresso_no_ticket_prices[$EVT_ID]);
2127 2127
             } else {
2128 2128
                 $success = false;
2129 2129
                 $msg = esc_html__(
@@ -2150,7 +2150,7 @@  discard block
 block discarded – undo
2150 2150
     private function _permanently_delete_event($EVT_ID = 0)
2151 2151
     {
2152 2152
         // grab event id
2153
-        if (! $EVT_ID) {
2153
+        if ( ! $EVT_ID) {
2154 2154
             $msg = esc_html__(
2155 2155
                 'An error occurred. No Event ID or an invalid Event ID was received.',
2156 2156
                 'event_espresso'
@@ -2158,12 +2158,12 @@  discard block
 block discarded – undo
2158 2158
             EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2159 2159
             return false;
2160 2160
         }
2161
-        if (! $this->_cpt_model_obj instanceof EE_Event
2161
+        if ( ! $this->_cpt_model_obj instanceof EE_Event
2162 2162
             || $this->_cpt_model_obj->ID() !== $EVT_ID
2163 2163
         ) {
2164 2164
             $this->_cpt_model_obj = EEM_Event::instance()->get_one_by_ID($EVT_ID);
2165 2165
         }
2166
-        if (! $this->_cpt_model_obj instanceof EE_Event) {
2166
+        if ( ! $this->_cpt_model_obj instanceof EE_Event) {
2167 2167
             return false;
2168 2168
         }
2169 2169
         // need to delete related tickets and prices first.
@@ -2185,7 +2185,7 @@  discard block
 block discarded – undo
2185 2185
         }
2186 2186
         // any attached question groups?
2187 2187
         $question_groups = $this->_cpt_model_obj->get_many_related('Question_Group');
2188
-        if (! empty($question_groups)) {
2188
+        if ( ! empty($question_groups)) {
2189 2189
             foreach ($question_groups as $question_group) {
2190 2190
                 $this->_cpt_model_obj->_remove_relation_to($question_group, 'Question_Group');
2191 2191
             }
@@ -2398,7 +2398,7 @@  discard block
 block discarded – undo
2398 2398
                                                 . esc_html__(
2399 2399
                                                     'Template Settings is a feature that is only available in the premium version of Event Espresso 4 which is available with a support license purchase on EventEspresso.com. Template Settings allow you to configure some of the appearance options for both the Event List and Event Details pages.',
2400 2400
                                                     'event_espresso'
2401
-                                                ) . '</strong>';
2401
+                                                ).'</strong>';
2402 2402
         $this->display_admin_caf_preview_page('template_settings_tab');
2403 2403
     }
2404 2404
 
@@ -2418,12 +2418,12 @@  discard block
 block discarded – undo
2418 2418
         // set default category object
2419 2419
         $this->_set_empty_category_object();
2420 2420
         // only set if we've got an id
2421
-        if (! isset($this->_req_data['EVT_CAT_ID'])) {
2421
+        if ( ! isset($this->_req_data['EVT_CAT_ID'])) {
2422 2422
             return;
2423 2423
         }
2424 2424
         $category_id = absint($this->_req_data['EVT_CAT_ID']);
2425 2425
         $term = get_term($category_id, EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY);
2426
-        if (! empty($term)) {
2426
+        if ( ! empty($term)) {
2427 2427
             $this->_category->category_name = $term->name;
2428 2428
             $this->_category->category_identifier = $term->slug;
2429 2429
             $this->_category->category_desc = $term->description;
@@ -2451,7 +2451,7 @@  discard block
 block discarded – undo
2451 2451
     {
2452 2452
         do_action('AHEE_log', __FILE__, __FUNCTION__, '');
2453 2453
         $this->_search_btn_label = esc_html__('Categories', 'event_espresso');
2454
-        $this->_admin_page_title .= ' ' . $this->get_action_link_or_button(
2454
+        $this->_admin_page_title .= ' '.$this->get_action_link_or_button(
2455 2455
             'add_category',
2456 2456
             'add_category',
2457 2457
             array(),
@@ -2525,7 +2525,7 @@  discard block
 block discarded – undo
2525 2525
             'disable'                  => '',
2526 2526
             'disabled_message'         => false,
2527 2527
         );
2528
-        $template = EVENTS_TEMPLATE_PATH . 'event_category_details.template.php';
2528
+        $template = EVENTS_TEMPLATE_PATH.'event_category_details.template.php';
2529 2529
         return EEH_Template::display_template($template, $template_args, true);
2530 2530
     }
2531 2531
 
@@ -2610,7 +2610,7 @@  discard block
 block discarded – undo
2610 2610
         $insert_ids = $update
2611 2611
             ? wp_update_term($cat_id, EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY, $term_args)
2612 2612
             : wp_insert_term($category_name, EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY, $term_args);
2613
-        if (! is_array($insert_ids)) {
2613
+        if ( ! is_array($insert_ids)) {
2614 2614
             $msg = esc_html__(
2615 2615
                 'An error occurred and the category has not been saved to the database.',
2616 2616
                 'event_espresso'
@@ -2641,7 +2641,7 @@  discard block
 block discarded – undo
2641 2641
         $limit = ($current_page - 1) * $per_page;
2642 2642
         $where = array('taxonomy' => EEM_CPT_Base::EVENT_CATEGORY_TAXONOMY);
2643 2643
         if (isset($this->_req_data['s'])) {
2644
-            $sstr = '%' . $this->_req_data['s'] . '%';
2644
+            $sstr = '%'.$this->_req_data['s'].'%';
2645 2645
             $where['OR'] = array(
2646 2646
                 'Term.name'   => array('LIKE', $sstr),
2647 2647
                 'description' => array('LIKE', $sstr),
@@ -2650,7 +2650,7 @@  discard block
 block discarded – undo
2650 2650
         $query_params = array(
2651 2651
             $where,
2652 2652
             'order_by'   => array($orderby => $order),
2653
-            'limit'      => $limit . ',' . $per_page,
2653
+            'limit'      => $limit.','.$per_page,
2654 2654
             'force_join' => array('Term'),
2655 2655
         );
2656 2656
         $categories = $count
Please login to merge, or discard this patch.
core/db_classes/EE_Ticket.class.php 1 patch
Indentation   +1734 added lines, -1734 removed lines patch added patch discarded remove patch
@@ -14,1742 +14,1742 @@
 block discarded – undo
14 14
 class EE_Ticket extends EE_Soft_Delete_Base_Class implements EEI_Line_Item_Object, EEI_Event_Relation, EEI_Has_Icon
15 15
 {
16 16
 
17
-    /**
18
-     * TicKet Sold out:
19
-     * constant used by ticket_status() to indicate that a ticket is sold out
20
-     * and no longer available for purchase
21
-     */
22
-    const sold_out = 'TKS';
23
-
24
-    /**
25
-     * TicKet Expired:
26
-     * constant used by ticket_status() to indicate that a ticket is expired
27
-     * and no longer available for purchase
28
-     */
29
-    const expired = 'TKE';
30
-
31
-    /**
32
-     * TicKet Archived:
33
-     * constant used by ticket_status() to indicate that a ticket is archived
34
-     * and no longer available for purchase
35
-     */
36
-    const archived = 'TKA';
37
-
38
-    /**
39
-     * TicKet Pending:
40
-     * constant used by ticket_status() to indicate that a ticket is pending
41
-     * and is NOT YET available for purchase
42
-     */
43
-    const pending = 'TKP';
44
-
45
-    /**
46
-     * TicKet On sale:
47
-     * constant used by ticket_status() to indicate that a ticket is On Sale
48
-     * and IS available for purchase
49
-     */
50
-    const onsale = 'TKO';
51
-
52
-    /**
53
-     * extra meta key for tracking ticket reservations
54
-     *
55
-     * @type string
56
-     */
57
-    const META_KEY_TICKET_RESERVATIONS = 'ticket_reservations';
58
-
59
-    /**
60
-     * cached result from method of the same name
61
-     *
62
-     * @var float $_ticket_total_with_taxes
63
-     */
64
-    private $_ticket_total_with_taxes;
65
-
66
-
67
-    /**
68
-     * @param array  $props_n_values          incoming values
69
-     * @param string $timezone                incoming timezone (if not set the timezone set for the website will be
70
-     *                                        used.)
71
-     * @param array  $date_formats            incoming date_formats in an array where the first value is the
72
-     *                                        date_format and the second value is the time format
73
-     * @return EE_Ticket
74
-     * @throws EE_Error
75
-     */
76
-    public static function new_instance($props_n_values = array(), $timezone = null, $date_formats = array())
77
-    {
78
-        $has_object = parent::_check_for_object($props_n_values, __CLASS__, $timezone, $date_formats);
79
-        return $has_object ? $has_object : new self($props_n_values, false, $timezone, $date_formats);
80
-    }
81
-
82
-
83
-    /**
84
-     * @param array  $props_n_values  incoming values from the database
85
-     * @param string $timezone        incoming timezone as set by the model.  If not set the timezone for
86
-     *                                the website will be used.
87
-     * @return EE_Ticket
88
-     * @throws EE_Error
89
-     */
90
-    public static function new_instance_from_db($props_n_values = array(), $timezone = null)
91
-    {
92
-        return new self($props_n_values, true, $timezone);
93
-    }
94
-
95
-
96
-    /**
97
-     * @return bool
98
-     * @throws EE_Error
99
-     */
100
-    public function parent()
101
-    {
102
-        return $this->get('TKT_parent');
103
-    }
104
-
105
-
106
-    /**
107
-     * return if a ticket has quantities available for purchase
108
-     *
109
-     * @param  int $DTT_ID the primary key for a particular datetime
110
-     * @return boolean
111
-     * @throws EE_Error
112
-     */
113
-    public function available($DTT_ID = 0)
114
-    {
115
-        // are we checking availability for a particular datetime ?
116
-        if ($DTT_ID) {
117
-            // get that datetime object
118
-            $datetime = $this->get_first_related('Datetime', array(array('DTT_ID' => $DTT_ID)));
119
-            // if  ticket sales for this datetime have exceeded the reg limit...
120
-            if ($datetime instanceof EE_Datetime && $datetime->sold_out()) {
121
-                return false;
122
-            }
123
-        }
124
-        // datetime is still open for registration, but is this ticket sold out ?
125
-        return $this->qty() < 1 || $this->qty() > $this->sold() ? true : false;
126
-    }
127
-
128
-
129
-    /**
130
-     * Using the start date and end date this method calculates whether the ticket is On Sale, Pending, or Expired
131
-     *
132
-     * @param bool        $display   true = we'll return a localized string, otherwise we just return the value of the
133
-     *                               relevant status const
134
-     * @param bool | null $remaining if it is already known that tickets are available, then simply pass a bool to save
135
-     *               further processing
136
-     * @return mixed status int if the display string isn't requested
137
-     * @throws EE_Error
138
-     */
139
-    public function ticket_status($display = false, $remaining = null)
140
-    {
141
-        $remaining = is_bool($remaining) ? $remaining : $this->is_remaining();
142
-        if (! $remaining) {
143
-            return $display ? EEH_Template::pretty_status(EE_Ticket::sold_out, false, 'sentence') : EE_Ticket::sold_out;
144
-        }
145
-        if ($this->get('TKT_deleted')) {
146
-            return $display ? EEH_Template::pretty_status(EE_Ticket::archived, false, 'sentence') : EE_Ticket::archived;
147
-        }
148
-        if ($this->is_expired()) {
149
-            return $display ? EEH_Template::pretty_status(EE_Ticket::expired, false, 'sentence') : EE_Ticket::expired;
150
-        }
151
-        if ($this->is_pending()) {
152
-            return $display ? EEH_Template::pretty_status(EE_Ticket::pending, false, 'sentence') : EE_Ticket::pending;
153
-        }
154
-        if ($this->is_on_sale()) {
155
-            return $display ? EEH_Template::pretty_status(EE_Ticket::onsale, false, 'sentence') : EE_Ticket::onsale;
156
-        }
157
-        return '';
158
-    }
159
-
160
-
161
-    /**
162
-     * The purpose of this method is to simply return a boolean for whether there are any tickets remaining for sale
163
-     * considering ALL the factors used for figuring that out.
164
-     *
165
-     * @access public
166
-     * @param  int $DTT_ID if an int above 0 is included here then we get a specific dtt.
167
-     * @return boolean         true = tickets remaining, false not.
168
-     * @throws EE_Error
169
-     */
170
-    public function is_remaining($DTT_ID = 0)
171
-    {
172
-        $num_remaining = $this->remaining($DTT_ID);
173
-        if ($num_remaining === 0) {
174
-            return false;
175
-        }
176
-        if ($num_remaining > 0 && $num_remaining < $this->min()) {
177
-            return false;
178
-        }
179
-        return true;
180
-    }
181
-
182
-
183
-    /**
184
-     * return the total number of tickets available for purchase
185
-     *
186
-     * @param  int $DTT_ID the primary key for a particular datetime.
187
-     *                     set to 0 for all related datetimes
188
-     * @return int
189
-     * @throws EE_Error
190
-     */
191
-    public function remaining($DTT_ID = 0)
192
-    {
193
-        return $this->real_quantity_on_ticket('saleable', $DTT_ID);
194
-    }
195
-
196
-
197
-    /**
198
-     * Gets min
199
-     *
200
-     * @return int
201
-     * @throws EE_Error
202
-     */
203
-    public function min()
204
-    {
205
-        return $this->get('TKT_min');
206
-    }
207
-
208
-
209
-    /**
210
-     * return if a ticket is no longer available cause its available dates have expired.
211
-     *
212
-     * @return boolean
213
-     * @throws EE_Error
214
-     */
215
-    public function is_expired()
216
-    {
217
-        return ($this->get_raw('TKT_end_date') < time());
218
-    }
219
-
220
-
221
-    /**
222
-     * Return if a ticket is yet to go on sale or not
223
-     *
224
-     * @return boolean
225
-     * @throws EE_Error
226
-     */
227
-    public function is_pending()
228
-    {
229
-        return ($this->get_raw('TKT_start_date') > time());
230
-    }
231
-
232
-
233
-    /**
234
-     * Return if a ticket is on sale or not
235
-     *
236
-     * @return boolean
237
-     * @throws EE_Error
238
-     */
239
-    public function is_on_sale()
240
-    {
241
-        return ($this->get_raw('TKT_start_date') < time() && $this->get_raw('TKT_end_date') > time());
242
-    }
243
-
244
-
245
-    /**
246
-     * This returns the chronologically last datetime that this ticket is associated with
247
-     *
248
-     * @param string $dt_frmt
249
-     * @param string $conjunction - conjunction junction what's your function ? this string joins the start date with
250
-     *                            the end date ie: Jan 01 "to" Dec 31
251
-     * @return string
252
-     * @throws EE_Error
253
-     */
254
-    public function date_range($dt_frmt = '', $conjunction = ' - ')
255
-    {
256
-        $dt_frmt = ! empty($dt_frmt) ? $dt_frmt : $this->_dt_frmt;
257
-        $first_date = $this->first_datetime() instanceof EE_Datetime ? $this->first_datetime()->get_i18n_datetime('DTT_EVT_start', $dt_frmt)
258
-            : '';
259
-        $last_date = $this->last_datetime() instanceof EE_Datetime ? $this->last_datetime()->get_i18n_datetime('DTT_EVT_end', $dt_frmt) : '';
260
-
261
-        return $first_date && $last_date ? $first_date . $conjunction . $last_date : '';
262
-    }
263
-
264
-
265
-    /**
266
-     * This returns the chronologically first datetime that this ticket is associated with
267
-     *
268
-     * @return EE_Datetime
269
-     * @throws EE_Error
270
-     */
271
-    public function first_datetime()
272
-    {
273
-        $datetimes = $this->datetimes(array('limit' => 1));
274
-        return reset($datetimes);
275
-    }
276
-
277
-
278
-    /**
279
-     * Gets all the datetimes this ticket can be used for attending.
280
-     * Unless otherwise specified, orders datetimes by start date.
281
-     *
282
-     * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
283
-     * @return EE_Datetime[]|EE_Base_Class[]
284
-     * @throws EE_Error
285
-     */
286
-    public function datetimes($query_params = array())
287
-    {
288
-        if (! isset($query_params['order_by'])) {
289
-            $query_params['order_by']['DTT_order'] = 'ASC';
290
-        }
291
-        return $this->get_many_related('Datetime', $query_params);
292
-    }
293
-
294
-
295
-    /**
296
-     * This returns the chronologically last datetime that this ticket is associated with
297
-     *
298
-     * @return EE_Datetime
299
-     * @throws EE_Error
300
-     */
301
-    public function last_datetime()
302
-    {
303
-        $datetimes = $this->datetimes(array('limit' => 1, 'order_by' => array('DTT_EVT_start' => 'DESC')));
304
-        return end($datetimes);
305
-    }
306
-
307
-
308
-    /**
309
-     * This returns the total tickets sold depending on the given parameters.
310
-     *
311
-     * @param  string $what   Can be one of two options: 'ticket', 'datetime'.
312
-     *                        'ticket' = total ticket sales for all datetimes this ticket is related to
313
-     *                        'datetime' = total ticket sales for a specified datetime (required $dtt_id)
314
-     *                        'datetime' = total ticket sales in the datetime_ticket table.
315
-     *                        If $dtt_id is not given then we return an array of sales indexed by datetime.
316
-     *                        If $dtt_id IS given then we return the tickets sold for that given datetime.
317
-     * @param  int    $dtt_id [optional] include the dtt_id with $what = 'datetime'.
318
-     * @return mixed (array|int)          how many tickets have sold
319
-     * @throws EE_Error
320
-     */
321
-    public function tickets_sold($what = 'ticket', $dtt_id = null)
322
-    {
323
-        $total = 0;
324
-        $tickets_sold = $this->_all_tickets_sold();
325
-        switch ($what) {
326
-            case 'ticket':
327
-                return $tickets_sold['ticket'];
328
-                break;
329
-            case 'datetime':
330
-                if (empty($tickets_sold['datetime'])) {
331
-                    return $total;
332
-                }
333
-                if (! empty($dtt_id) && ! isset($tickets_sold['datetime'][ $dtt_id ])) {
334
-                    EE_Error::add_error(
335
-                        __(
336
-                            'You\'ve requested the amount of tickets sold for a given ticket and datetime, however there are no records for the datetime id you included.  Are you SURE that is a datetime related to this ticket?',
337
-                            'event_espresso'
338
-                        ),
339
-                        __FILE__,
340
-                        __FUNCTION__,
341
-                        __LINE__
342
-                    );
343
-                    return $total;
344
-                }
345
-                return empty($dtt_id) ? $tickets_sold['datetime'] : $tickets_sold['datetime'][ $dtt_id ];
346
-                break;
347
-            default:
348
-                return $total;
349
-        }
350
-    }
351
-
352
-
353
-    /**
354
-     * This returns an array indexed by datetime_id for tickets sold with this ticket.
355
-     *
356
-     * @return EE_Ticket[]
357
-     * @throws EE_Error
358
-     */
359
-    protected function _all_tickets_sold()
360
-    {
361
-        $datetimes = $this->get_many_related('Datetime');
362
-        $tickets_sold = array();
363
-        if (! empty($datetimes)) {
364
-            foreach ($datetimes as $datetime) {
365
-                $tickets_sold['datetime'][ $datetime->ID() ] = $datetime->get('DTT_sold');
366
-            }
367
-        }
368
-        // Tickets sold
369
-        $tickets_sold['ticket'] = $this->sold();
370
-        return $tickets_sold;
371
-    }
372
-
373
-
374
-    /**
375
-     * This returns the base price object for the ticket.
376
-     *
377
-     * @param  bool $return_array whether to return as an array indexed by price id or just the object.
378
-     * @return EE_Price|EE_Base_Class|EE_Price[]|EE_Base_Class[]
379
-     * @throws EE_Error
380
-     */
381
-    public function base_price($return_array = false)
382
-    {
383
-        $_where = array('Price_Type.PBT_ID' => EEM_Price_Type::base_type_base_price);
384
-        return $return_array
385
-            ? $this->get_many_related('Price', array($_where))
386
-            : $this->get_first_related('Price', array($_where));
387
-    }
388
-
389
-
390
-    /**
391
-     * This returns ONLY the price modifiers for the ticket (i.e. no taxes or base price)
392
-     *
393
-     * @access public
394
-     * @return EE_Price[]
395
-     * @throws EE_Error
396
-     */
397
-    public function price_modifiers()
398
-    {
399
-        $query_params = array(
400
-            0 => array(
401
-                'Price_Type.PBT_ID' => array(
402
-                    'NOT IN',
403
-                    array(EEM_Price_Type::base_type_base_price, EEM_Price_Type::base_type_tax),
404
-                ),
405
-            ),
406
-        );
407
-        return $this->prices($query_params);
408
-    }
409
-
410
-
411
-    /**
412
-     * Gets all the prices that combine to form the final price of this ticket
413
-     *
414
-     * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
415
-     * @return EE_Price[]|EE_Base_Class[]
416
-     * @throws EE_Error
417
-     */
418
-    public function prices($query_params = array())
419
-    {
420
-        return $this->get_many_related('Price', $query_params);
421
-    }
422
-
423
-
424
-    /**
425
-     * Gets all the ticket applicabilities (ie, relations between datetimes and tickets)
426
-     *
427
-     * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
428
-     * @return EE_Datetime_Ticket|EE_Base_Class[]
429
-     * @throws EE_Error
430
-     */
431
-    public function datetime_tickets($query_params = array())
432
-    {
433
-        return $this->get_many_related('Datetime_Ticket', $query_params);
434
-    }
435
-
436
-
437
-    /**
438
-     * Gets all the datetimes from the db ordered by DTT_order
439
-     *
440
-     * @param boolean $show_expired
441
-     * @param boolean $show_deleted
442
-     * @return EE_Datetime[]
443
-     * @throws EE_Error
444
-     */
445
-    public function datetimes_ordered($show_expired = true, $show_deleted = false)
446
-    {
447
-        return EEM_Datetime::instance($this->_timezone)->get_datetimes_for_ticket_ordered_by_DTT_order(
448
-            $this->ID(),
449
-            $show_expired,
450
-            $show_deleted
451
-        );
452
-    }
453
-
454
-
455
-    /**
456
-     * Gets ID
457
-     *
458
-     * @return string
459
-     * @throws EE_Error
460
-     */
461
-    public function ID()
462
-    {
463
-        return $this->get('TKT_ID');
464
-    }
465
-
466
-
467
-    /**
468
-     * get the author of the ticket.
469
-     *
470
-     * @since 4.5.0
471
-     * @return int
472
-     * @throws EE_Error
473
-     */
474
-    public function wp_user()
475
-    {
476
-        return $this->get('TKT_wp_user');
477
-    }
478
-
479
-
480
-    /**
481
-     * Gets the template for the ticket
482
-     *
483
-     * @return EE_Ticket_Template|EE_Base_Class
484
-     * @throws EE_Error
485
-     */
486
-    public function template()
487
-    {
488
-        return $this->get_first_related('Ticket_Template');
489
-    }
490
-
491
-
492
-    /**
493
-     * Simply returns an array of EE_Price objects that are taxes.
494
-     *
495
-     * @return EE_Price[]
496
-     * @throws EE_Error
497
-     */
498
-    public function get_ticket_taxes_for_admin()
499
-    {
500
-        return EE_Taxes::get_taxes_for_admin();
501
-    }
502
-
503
-
504
-    /**
505
-     * @return float
506
-     * @throws EE_Error
507
-     */
508
-    public function ticket_price()
509
-    {
510
-        return $this->get('TKT_price');
511
-    }
512
-
513
-
514
-    /**
515
-     * @return mixed
516
-     * @throws EE_Error
517
-     */
518
-    public function pretty_price()
519
-    {
520
-        return $this->get_pretty('TKT_price');
521
-    }
522
-
523
-
524
-    /**
525
-     * @return bool
526
-     * @throws EE_Error
527
-     */
528
-    public function is_free()
529
-    {
530
-        return $this->get_ticket_total_with_taxes() === (float) 0;
531
-    }
532
-
533
-
534
-    /**
535
-     * get_ticket_total_with_taxes
536
-     *
537
-     * @param bool $no_cache
538
-     * @return float
539
-     * @throws EE_Error
540
-     */
541
-    public function get_ticket_total_with_taxes($no_cache = false)
542
-    {
543
-        if ($this->_ticket_total_with_taxes === null || $no_cache) {
544
-            $this->_ticket_total_with_taxes = $this->get_ticket_subtotal() + $this->get_ticket_taxes_total_for_admin();
545
-        }
546
-        return (float) $this->_ticket_total_with_taxes;
547
-    }
548
-
549
-
550
-    public function ensure_TKT_Price_correct()
551
-    {
552
-        $this->set('TKT_price', EE_Taxes::get_subtotal_for_admin($this));
553
-        $this->save();
554
-    }
555
-
556
-
557
-    /**
558
-     * @return float
559
-     * @throws EE_Error
560
-     */
561
-    public function get_ticket_subtotal()
562
-    {
563
-        return EE_Taxes::get_subtotal_for_admin($this);
564
-    }
565
-
566
-
567
-    /**
568
-     * Returns the total taxes applied to this ticket
569
-     *
570
-     * @return float
571
-     * @throws EE_Error
572
-     */
573
-    public function get_ticket_taxes_total_for_admin()
574
-    {
575
-        return EE_Taxes::get_total_taxes_for_admin($this);
576
-    }
577
-
578
-
579
-    /**
580
-     * Sets name
581
-     *
582
-     * @param string $name
583
-     * @throws EE_Error
584
-     */
585
-    public function set_name($name)
586
-    {
587
-        $this->set('TKT_name', $name);
588
-    }
589
-
590
-
591
-    /**
592
-     * Gets description
593
-     *
594
-     * @return string
595
-     * @throws EE_Error
596
-     */
597
-    public function description()
598
-    {
599
-        return $this->get('TKT_description');
600
-    }
601
-
602
-
603
-    /**
604
-     * Sets description
605
-     *
606
-     * @param string $description
607
-     * @throws EE_Error
608
-     */
609
-    public function set_description($description)
610
-    {
611
-        $this->set('TKT_description', $description);
612
-    }
613
-
614
-
615
-    /**
616
-     * Gets start_date
617
-     *
618
-     * @param string $dt_frmt
619
-     * @param string $tm_frmt
620
-     * @return string
621
-     * @throws EE_Error
622
-     */
623
-    public function start_date($dt_frmt = '', $tm_frmt = '')
624
-    {
625
-        return $this->_get_datetime('TKT_start_date', $dt_frmt, $tm_frmt);
626
-    }
627
-
628
-
629
-    /**
630
-     * Sets start_date
631
-     *
632
-     * @param string $start_date
633
-     * @return void
634
-     * @throws EE_Error
635
-     */
636
-    public function set_start_date($start_date)
637
-    {
638
-        $this->_set_date_time('B', $start_date, 'TKT_start_date');
639
-    }
640
-
641
-
642
-    /**
643
-     * Gets end_date
644
-     *
645
-     * @param string $dt_frmt
646
-     * @param string $tm_frmt
647
-     * @return string
648
-     * @throws EE_Error
649
-     */
650
-    public function end_date($dt_frmt = '', $tm_frmt = '')
651
-    {
652
-        return $this->_get_datetime('TKT_end_date', $dt_frmt, $tm_frmt);
653
-    }
654
-
655
-
656
-    /**
657
-     * Sets end_date
658
-     *
659
-     * @param string $end_date
660
-     * @return void
661
-     * @throws EE_Error
662
-     */
663
-    public function set_end_date($end_date)
664
-    {
665
-        $this->_set_date_time('B', $end_date, 'TKT_end_date');
666
-    }
667
-
668
-
669
-    /**
670
-     * Sets sell until time
671
-     *
672
-     * @since 4.5.0
673
-     * @param string $time a string representation of the sell until time (ex 9am or 7:30pm)
674
-     * @throws EE_Error
675
-     */
676
-    public function set_end_time($time)
677
-    {
678
-        $this->_set_time_for($time, 'TKT_end_date');
679
-    }
680
-
681
-
682
-    /**
683
-     * Sets min
684
-     *
685
-     * @param int $min
686
-     * @return void
687
-     * @throws EE_Error
688
-     */
689
-    public function set_min($min)
690
-    {
691
-        $this->set('TKT_min', $min);
692
-    }
693
-
694
-
695
-    /**
696
-     * Gets max
697
-     *
698
-     * @return int
699
-     * @throws EE_Error
700
-     */
701
-    public function max()
702
-    {
703
-        return $this->get('TKT_max');
704
-    }
705
-
706
-
707
-    /**
708
-     * Sets max
709
-     *
710
-     * @param int $max
711
-     * @return void
712
-     * @throws EE_Error
713
-     */
714
-    public function set_max($max)
715
-    {
716
-        $this->set('TKT_max', $max);
717
-    }
718
-
719
-
720
-    /**
721
-     * Sets price
722
-     *
723
-     * @param float $price
724
-     * @return void
725
-     * @throws EE_Error
726
-     */
727
-    public function set_price($price)
728
-    {
729
-        $this->set('TKT_price', $price);
730
-    }
731
-
732
-
733
-    /**
734
-     * Gets sold
735
-     *
736
-     * @return int
737
-     * @throws EE_Error
738
-     */
739
-    public function sold()
740
-    {
741
-        return $this->get_raw('TKT_sold');
742
-    }
743
-
744
-
745
-    /**
746
-     * Sets sold
747
-     *
748
-     * @param int $sold
749
-     * @return void
750
-     * @throws EE_Error
751
-     */
752
-    public function set_sold($sold)
753
-    {
754
-        // sold can not go below zero
755
-        $sold = max(0, $sold);
756
-        $this->set('TKT_sold', $sold);
757
-    }
758
-
759
-
760
-    /**
761
-     * Increments sold by amount passed by $qty AND decrements the reserved count on both this ticket and its
762
-     * associated datetimes.
763
-     *
764
-     * @since 4.9.80.p
765
-     * @param int $qty
766
-     * @return boolean
767
-     * @throws EE_Error
768
-     * @throws InvalidArgumentException
769
-     * @throws InvalidDataTypeException
770
-     * @throws InvalidInterfaceException
771
-     * @throws ReflectionException
772
-     */
773
-    public function increaseSold($qty = 1)
774
-    {
775
-        $qty = absint($qty);
776
-        // increment sold and decrement reserved datetime quantities simultaneously
777
-        // don't worry about failures, because they must have already had a spot reserved
778
-        $this->increaseSoldForDatetimes($qty);
779
-        // Increment and decrement ticket quantities simultaneously
780
-        $success = $this->adjustNumericFieldsInDb(
781
-            [
782
-                'TKT_reserved' => $qty * -1,
783
-                'TKT_sold' => $qty
784
-            ]
785
-        );
786
-        do_action(
787
-            'AHEE__EE_Ticket__increase_sold',
788
-            $this,
789
-            $qty,
790
-            $this->sold(),
791
-            $success
792
-        );
793
-        return $success;
794
-    }
795
-
796
-    /**
797
-     * On each datetime related to this ticket, increases its sold count and decreases its reserved count by $qty.
798
-     *
799
-     * @since 4.9.80.p
800
-     * @param int $qty positive or negative. Positive means to increase sold counts (and decrease reserved counts),
801
-     *             Negative means to decreases old counts (and increase reserved counts).
802
-     * @param EE_Datetime[] $datetimes
803
-     * @throws EE_Error
804
-     * @throws InvalidArgumentException
805
-     * @throws InvalidDataTypeException
806
-     * @throws InvalidInterfaceException
807
-     * @throws ReflectionException
808
-     */
809
-    protected function increaseSoldForDatetimes($qty, array $datetimes = [])
810
-    {
811
-        $datetimes = ! empty($datetimes) ? $datetimes : $this->datetimes();
812
-        foreach ($datetimes as $datetime) {
813
-            $datetime->increaseSold($qty);
814
-        }
815
-    }
816
-
817
-
818
-
819
-    /**
820
-     * Decrements (subtracts) sold by amount passed by $qty on both the ticket and its related datetimes directly in the
821
-     * DB and then updates the model objects.
822
-     * Does not affect the reserved counts.
823
-     *
824
-     * @since 4.9.80.p
825
-     * @param int $qty
826
-     * @return boolean
827
-     * @throws EE_Error
828
-     * @throws InvalidArgumentException
829
-     * @throws InvalidDataTypeException
830
-     * @throws InvalidInterfaceException
831
-     * @throws ReflectionException
832
-     */
833
-    public function decreaseSold($qty = 1)
834
-    {
835
-        $qty = absint($qty);
836
-        $this->decreaseSoldForDatetimes($qty);
837
-        $success = $this->adjustNumericFieldsInDb(
838
-            [
839
-                'TKT_sold' => $qty * -1
840
-            ]
841
-        );
842
-        do_action(
843
-            'AHEE__EE_Ticket__decrease_sold',
844
-            $this,
845
-            $qty,
846
-            $this->sold(),
847
-            $success
848
-        );
849
-        return $success;
850
-    }
851
-
852
-
853
-    /**
854
-     * Decreases sold on related datetimes
855
-     *
856
-     * @since 4.9.80.p
857
-     * @param int $qty
858
-     * @param EE_Datetime[] $datetimes
859
-     * @return void
860
-     * @throws EE_Error
861
-     * @throws InvalidArgumentException
862
-     * @throws InvalidDataTypeException
863
-     * @throws InvalidInterfaceException
864
-     * @throws ReflectionException
865
-     */
866
-    protected function decreaseSoldForDatetimes($qty = 1, array $datetimes = [])
867
-    {
868
-        $datetimes = ! empty($datetimes) ? $datetimes : $this->datetimes();
869
-        if (is_array($datetimes)) {
870
-            foreach ($datetimes as $datetime) {
871
-                if ($datetime instanceof EE_Datetime) {
872
-                    $datetime->decreaseSold($qty);
873
-                }
874
-            }
875
-        }
876
-    }
877
-
878
-
879
-    /**
880
-     * Gets qty of reserved tickets
881
-     *
882
-     * @return int
883
-     * @throws EE_Error
884
-     */
885
-    public function reserved()
886
-    {
887
-        return $this->get_raw('TKT_reserved');
888
-    }
889
-
890
-
891
-    /**
892
-     * Sets reserved
893
-     *
894
-     * @param int $reserved
895
-     * @return void
896
-     * @throws EE_Error
897
-     */
898
-    public function set_reserved($reserved)
899
-    {
900
-        // reserved can not go below zero
901
-        $reserved = max(0, (int) $reserved);
902
-        $this->set('TKT_reserved', $reserved);
903
-    }
904
-
905
-
906
-    /**
907
-     * Increments reserved by amount passed by $qty, and persists it immediately to the database.
908
-     *
909
-     * @since 4.9.80.p
910
-     * @param int    $qty
911
-     * @param string $source
912
-     * @return bool whether we successfully reserved the ticket or not.
913
-     * @throws EE_Error
914
-     * @throws InvalidArgumentException
915
-     * @throws ReflectionException
916
-     * @throws InvalidDataTypeException
917
-     * @throws InvalidInterfaceException
918
-     */
919
-    public function increaseReserved($qty = 1, $source = 'unknown')
920
-    {
921
-        $qty = absint($qty);
922
-        do_action(
923
-            'AHEE__EE_Ticket__increase_reserved__begin',
924
-            $this,
925
-            $qty,
926
-            $source
927
-        );
928
-        $this->add_extra_meta(EE_Ticket::META_KEY_TICKET_RESERVATIONS, "{$qty} from {$source}");
929
-        $success = false;
930
-        $datetimes_adjusted_successfully = $this->increaseReservedForDatetimes($qty);
931
-        if ($datetimes_adjusted_successfully) {
932
-            $success = $this->incrementFieldConditionallyInDb(
933
-                'TKT_reserved',
934
-                'TKT_sold',
935
-                'TKT_qty',
936
-                $qty
937
-            );
938
-            if (! $success) {
939
-                // The datetimes were successfully bumped, but not the
940
-                // ticket. So we need to manually rollback the datetimes.
941
-                $this->decreaseReservedForDatetimes($qty);
942
-            }
943
-        }
944
-        do_action(
945
-            'AHEE__EE_Ticket__increase_reserved',
946
-            $this,
947
-            $qty,
948
-            $this->reserved(),
949
-            $success
950
-        );
951
-        return $success;
952
-    }
953
-
954
-
955
-    /**
956
-     * Increases reserved counts on related datetimes
957
-     *
958
-     * @since 4.9.80.p
959
-     * @param int $qty
960
-     * @param EE_Datetime[] $datetimes
961
-     * @return boolean indicating success
962
-     * @throws EE_Error
963
-     * @throws InvalidArgumentException
964
-     * @throws InvalidDataTypeException
965
-     * @throws InvalidInterfaceException
966
-     * @throws ReflectionException
967
-     */
968
-    protected function increaseReservedForDatetimes($qty = 1, array $datetimes = [])
969
-    {
970
-        $datetimes = ! empty($datetimes) ? $datetimes : $this->datetimes();
971
-        $datetimes_updated = [];
972
-        $limit_exceeded = false;
973
-        if (is_array($datetimes)) {
974
-            foreach ($datetimes as $datetime) {
975
-                if ($datetime instanceof EE_Datetime) {
976
-                    if ($datetime->increaseReserved($qty)) {
977
-                        $datetimes_updated[] = $datetime;
978
-                    } else {
979
-                        $limit_exceeded = true;
980
-                        break;
981
-                    }
982
-                }
983
-            }
984
-            // If somewhere along the way we detected a datetime whose
985
-            // limit was exceeded, do a manual rollback.
986
-            if ($limit_exceeded) {
987
-                $this->decreaseReservedForDatetimes($qty, $datetimes_updated);
988
-                return false;
989
-            }
990
-        }
991
-        return true;
992
-    }
993
-
994
-
995
-    /**
996
-     * Decrements (subtracts) reserved by amount passed by $qty, and persists it immediately to the database.
997
-     *
998
-     * @since 4.9.80.p
999
-     * @param int    $qty
1000
-     * @param bool   $adjust_datetimes
1001
-     * @param string $source
1002
-     * @return boolean
1003
-     * @throws EE_Error
1004
-     * @throws InvalidArgumentException
1005
-     * @throws ReflectionException
1006
-     * @throws InvalidDataTypeException
1007
-     * @throws InvalidInterfaceException
1008
-     */
1009
-    public function decreaseReserved($qty = 1, $adjust_datetimes = true, $source = 'unknown')
1010
-    {
1011
-        $qty = absint($qty);
1012
-        $this->add_extra_meta(EE_Ticket::META_KEY_TICKET_RESERVATIONS, "-{$qty} from {$source}");
1013
-        if ($adjust_datetimes) {
1014
-            $this->decreaseReservedForDatetimes($qty);
1015
-        }
1016
-        $success = $this->adjustNumericFieldsInDb(
1017
-            [
1018
-                'TKT_reserved' => $qty * -1
1019
-            ]
1020
-        );
1021
-        do_action(
1022
-            'AHEE__EE_Ticket__decrease_reserved',
1023
-            $this,
1024
-            $qty,
1025
-            $this->reserved(),
1026
-            $success
1027
-        );
1028
-        return $success;
1029
-    }
1030
-
1031
-
1032
-    /**
1033
-     * Decreases the reserved count on the specified datetimes.
1034
-     *
1035
-     * @since 4.9.80.p
1036
-     * @param int           $qty
1037
-     * @param EE_Datetime[] $datetimes
1038
-     * @throws EE_Error
1039
-     * @throws InvalidArgumentException
1040
-     * @throws ReflectionException
1041
-     * @throws InvalidDataTypeException
1042
-     * @throws InvalidInterfaceException
1043
-     */
1044
-    protected function decreaseReservedForDatetimes($qty = 1, array $datetimes = [])
1045
-    {
1046
-        $datetimes = ! empty($datetimes) ? $datetimes : $this->datetimes();
1047
-        foreach ($datetimes as $datetime) {
1048
-            if ($datetime instanceof EE_Datetime) {
1049
-                $datetime->decreaseReserved($qty);
1050
-            }
1051
-        }
1052
-    }
1053
-
1054
-
1055
-    /**
1056
-     * Gets ticket quantity
1057
-     *
1058
-     * @param string $context     ticket quantity is somewhat subjective depending on the exact information sought
1059
-     *                            therefore $context can be one of three values: '', 'reg_limit', or 'saleable'
1060
-     *                            '' (default) quantity is the actual db value for TKT_qty, unaffected by other objects
1061
-     *                            REG LIMIT: caps qty based on DTT_reg_limit for ALL related datetimes
1062
-     *                            SALEABLE: also considers datetime sold and returns zero if ANY DTT is sold out, and
1063
-     *                            is therefore the truest measure of tickets that can be purchased at the moment
1064
-     * @return int
1065
-     * @throws EE_Error
1066
-     */
1067
-    public function qty($context = '')
1068
-    {
1069
-        switch ($context) {
1070
-            case 'reg_limit':
1071
-                return $this->real_quantity_on_ticket();
1072
-            case 'saleable':
1073
-                return $this->real_quantity_on_ticket('saleable');
1074
-            default:
1075
-                return $this->get_raw('TKT_qty');
1076
-        }
1077
-    }
1078
-
1079
-
1080
-    /**
1081
-     * Gets ticket quantity
1082
-     *
1083
-     * @param string $context     ticket quantity is somewhat subjective depending on the exact information sought
1084
-     *                            therefore $context can be one of two values: 'reg_limit', or 'saleable'
1085
-     *                            REG LIMIT: caps qty based on DTT_reg_limit for ALL related datetimes
1086
-     *                            SALEABLE: also considers datetime sold and returns zero if ANY DTT is sold out, and
1087
-     *                            is therefore the truest measure of tickets that can be purchased at the moment
1088
-     * @param  int   $DTT_ID      the primary key for a particular datetime.
1089
-     *                            set to 0 for all related datetimes
1090
-     * @return int
1091
-     * @throws EE_Error
1092
-     */
1093
-    public function real_quantity_on_ticket($context = 'reg_limit', $DTT_ID = 0)
1094
-    {
1095
-        $raw = $this->get_raw('TKT_qty');
1096
-        // return immediately if it's zero
1097
-        if ($raw === 0) {
1098
-            return $raw;
1099
-        }
1100
-        // echo "\n\n<br />Ticket: " . $this->name() . '<br />';
1101
-        // ensure qty doesn't exceed raw value for THIS ticket
1102
-        $qty = min(EE_INF, $raw);
1103
-        // echo "\n . qty: " . $qty . '<br />';
1104
-        // calculate this ticket's total sales and reservations
1105
-        $sold_and_reserved_for_this_ticket = $this->sold() + $this->reserved();
1106
-        // echo "\n . sold: " . $this->sold() . '<br />';
1107
-        // echo "\n . reserved: " . $this->reserved() . '<br />';
1108
-        // echo "\n . sold_and_reserved_for_this_ticket: " . $sold_and_reserved_for_this_ticket . '<br />';
1109
-        // first we need to calculate the maximum number of tickets available for the datetime
1110
-        // do we want data for one datetime or all of them ?
1111
-        $query_params = $DTT_ID ? array(array('DTT_ID' => $DTT_ID)) : array();
1112
-        $datetimes = $this->datetimes($query_params);
1113
-        if (is_array($datetimes) && ! empty($datetimes)) {
1114
-            foreach ($datetimes as $datetime) {
1115
-                if ($datetime instanceof EE_Datetime) {
1116
-                    $datetime->refresh_from_db();
1117
-                    // echo "\n . . datetime name: " . $datetime->name() . '<br />';
1118
-                    // echo "\n . . datetime ID: " . $datetime->ID() . '<br />';
1119
-                    // initialize with no restrictions for each datetime
1120
-                    // but adjust datetime qty based on datetime reg limit
1121
-                    $datetime_qty = min(EE_INF, $datetime->reg_limit());
1122
-                    // echo "\n . . . datetime reg_limit: " . $datetime->reg_limit() . '<br />';
1123
-                    // echo "\n . . . datetime_qty: " . $datetime_qty . '<br />';
1124
-                    // if we want the actual saleable amount, then we need to consider OTHER ticket sales
1125
-                    // and reservations for this datetime, that do NOT include sales and reservations
1126
-                    // for this ticket (so we add $this->sold() and $this->reserved() back in)
1127
-                    if ($context === 'saleable') {
1128
-                        $datetime_qty = max(
1129
-                            $datetime_qty - $datetime->sold_and_reserved() + $sold_and_reserved_for_this_ticket,
1130
-                            0
1131
-                        );
1132
-                        // echo "\n . . . datetime sold: " . $datetime->sold() . '<br />';
1133
-                        // echo "\n . . . datetime reserved: " . $datetime->reserved() . '<br />';
1134
-                        // echo "\n . . . datetime sold_and_reserved: " . $datetime->sold_and_reserved() . '<br />';
1135
-                        // echo "\n . . . datetime_qty: " . $datetime_qty . '<br />';
1136
-                        $datetime_qty = ! $datetime->sold_out() ? $datetime_qty : 0;
1137
-                        // echo "\n . . . datetime_qty: " . $datetime_qty . '<br />';
1138
-                    }
1139
-                    $qty = min($datetime_qty, $qty);
1140
-                    // echo "\n . . qty: " . $qty . '<br />';
1141
-                }
1142
-            }
1143
-        }
1144
-        // NOW that we know the  maximum number of tickets available for the datetime
1145
-        // we can finally factor in the details for this specific ticket
1146
-        if ($qty > 0 && $context === 'saleable') {
1147
-            // and subtract the sales for THIS ticket
1148
-            $qty = max($qty - $sold_and_reserved_for_this_ticket, 0);
1149
-            // echo "\n . qty: " . $qty . '<br />';
1150
-        }
1151
-        // echo "\nFINAL QTY: " . $qty . "<br /><br />";
1152
-        return $qty;
1153
-    }
1154
-
1155
-
1156
-    /**
1157
-     * Sets qty - IMPORTANT!!! Does NOT allow QTY to be set higher than the lowest reg limit of any related datetimes
1158
-     *
1159
-     * @param int $qty
1160
-     * @return void
1161
-     * @throws EE_Error
1162
-     */
1163
-    public function set_qty($qty)
1164
-    {
1165
-        $datetimes = $this->datetimes();
1166
-        foreach ($datetimes as $datetime) {
1167
-            if ($datetime instanceof EE_Datetime) {
1168
-                $qty = min($qty, $datetime->reg_limit());
1169
-            }
1170
-        }
1171
-        $this->set('TKT_qty', $qty);
1172
-    }
1173
-
1174
-
1175
-    /**
1176
-     * Gets uses
1177
-     *
1178
-     * @return int
1179
-     * @throws EE_Error
1180
-     */
1181
-    public function uses()
1182
-    {
1183
-        return $this->get('TKT_uses');
1184
-    }
1185
-
1186
-
1187
-    /**
1188
-     * Sets uses
1189
-     *
1190
-     * @param int $uses
1191
-     * @return void
1192
-     * @throws EE_Error
1193
-     */
1194
-    public function set_uses($uses)
1195
-    {
1196
-        $this->set('TKT_uses', $uses);
1197
-    }
1198
-
1199
-
1200
-    /**
1201
-     * returns whether ticket is required or not.
1202
-     *
1203
-     * @return boolean
1204
-     * @throws EE_Error
1205
-     */
1206
-    public function required()
1207
-    {
1208
-        return $this->get('TKT_required');
1209
-    }
1210
-
1211
-
1212
-    /**
1213
-     * sets the TKT_required property
1214
-     *
1215
-     * @param boolean $required
1216
-     * @return void
1217
-     * @throws EE_Error
1218
-     */
1219
-    public function set_required($required)
1220
-    {
1221
-        $this->set('TKT_required', $required);
1222
-    }
1223
-
1224
-
1225
-    /**
1226
-     * Gets taxable
1227
-     *
1228
-     * @return boolean
1229
-     * @throws EE_Error
1230
-     */
1231
-    public function taxable()
1232
-    {
1233
-        return $this->get('TKT_taxable');
1234
-    }
1235
-
1236
-
1237
-    /**
1238
-     * Sets taxable
1239
-     *
1240
-     * @param boolean $taxable
1241
-     * @return void
1242
-     * @throws EE_Error
1243
-     */
1244
-    public function set_taxable($taxable)
1245
-    {
1246
-        $this->set('TKT_taxable', $taxable);
1247
-    }
1248
-
1249
-
1250
-    /**
1251
-     * Gets is_default
1252
-     *
1253
-     * @return boolean
1254
-     * @throws EE_Error
1255
-     */
1256
-    public function is_default()
1257
-    {
1258
-        return $this->get('TKT_is_default');
1259
-    }
1260
-
1261
-
1262
-    /**
1263
-     * Sets is_default
1264
-     *
1265
-     * @param boolean $is_default
1266
-     * @return void
1267
-     * @throws EE_Error
1268
-     */
1269
-    public function set_is_default($is_default)
1270
-    {
1271
-        $this->set('TKT_is_default', $is_default);
1272
-    }
1273
-
1274
-
1275
-    /**
1276
-     * Gets order
1277
-     *
1278
-     * @return int
1279
-     * @throws EE_Error
1280
-     */
1281
-    public function order()
1282
-    {
1283
-        return $this->get('TKT_order');
1284
-    }
1285
-
1286
-
1287
-    /**
1288
-     * Sets order
1289
-     *
1290
-     * @param int $order
1291
-     * @return void
1292
-     * @throws EE_Error
1293
-     */
1294
-    public function set_order($order)
1295
-    {
1296
-        $this->set('TKT_order', $order);
1297
-    }
1298
-
1299
-
1300
-    /**
1301
-     * Gets row
1302
-     *
1303
-     * @return int
1304
-     * @throws EE_Error
1305
-     */
1306
-    public function row()
1307
-    {
1308
-        return $this->get('TKT_row');
1309
-    }
1310
-
1311
-
1312
-    /**
1313
-     * Sets row
1314
-     *
1315
-     * @param int $row
1316
-     * @return void
1317
-     * @throws EE_Error
1318
-     */
1319
-    public function set_row($row)
1320
-    {
1321
-        $this->set('TKT_row', $row);
1322
-    }
1323
-
1324
-
1325
-    /**
1326
-     * Gets deleted
1327
-     *
1328
-     * @return boolean
1329
-     * @throws EE_Error
1330
-     */
1331
-    public function deleted()
1332
-    {
1333
-        return $this->get('TKT_deleted');
1334
-    }
1335
-
1336
-
1337
-    /**
1338
-     * Sets deleted
1339
-     *
1340
-     * @param boolean $deleted
1341
-     * @return void
1342
-     * @throws EE_Error
1343
-     */
1344
-    public function set_deleted($deleted)
1345
-    {
1346
-        $this->set('TKT_deleted', $deleted);
1347
-    }
1348
-
1349
-
1350
-    /**
1351
-     * Gets parent
1352
-     *
1353
-     * @return int
1354
-     * @throws EE_Error
1355
-     */
1356
-    public function parent_ID()
1357
-    {
1358
-        return $this->get('TKT_parent');
1359
-    }
1360
-
1361
-
1362
-    /**
1363
-     * Sets parent
1364
-     *
1365
-     * @param int $parent
1366
-     * @return void
1367
-     * @throws EE_Error
1368
-     */
1369
-    public function set_parent_ID($parent)
1370
-    {
1371
-        $this->set('TKT_parent', $parent);
1372
-    }
1373
-
1374
-
1375
-    /**
1376
-     * Gets a string which is handy for showing in gateways etc that describes the ticket.
1377
-     *
1378
-     * @return string
1379
-     * @throws EE_Error
1380
-     */
1381
-    public function name_and_info()
1382
-    {
1383
-        $times = array();
1384
-        foreach ($this->datetimes() as $datetime) {
1385
-            $times[] = $datetime->start_date_and_time();
1386
-        }
1387
-        return $this->name() . ' @ ' . implode(', ', $times) . ' for ' . $this->pretty_price();
1388
-    }
1389
-
1390
-
1391
-    /**
1392
-     * Gets name
1393
-     *
1394
-     * @return string
1395
-     * @throws EE_Error
1396
-     */
1397
-    public function name()
1398
-    {
1399
-        return $this->get('TKT_name');
1400
-    }
1401
-
1402
-
1403
-    /**
1404
-     * Gets price
1405
-     *
1406
-     * @return float
1407
-     * @throws EE_Error
1408
-     */
1409
-    public function price()
1410
-    {
1411
-        return $this->get('TKT_price');
1412
-    }
1413
-
1414
-
1415
-    /**
1416
-     * Gets all the registrations for this ticket
1417
-     *
1418
-     * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1419
-     * @return EE_Registration[]|EE_Base_Class[]
1420
-     * @throws EE_Error
1421
-     */
1422
-    public function registrations($query_params = array())
1423
-    {
1424
-        return $this->get_many_related('Registration', $query_params);
1425
-    }
1426
-
1427
-
1428
-    /**
1429
-     * Updates the TKT_sold attribute (and saves) based on the number of APPROVED registrations for this ticket.
1430
-     *
1431
-     * @return int
1432
-     * @throws EE_Error
1433
-     */
1434
-    public function update_tickets_sold()
1435
-    {
1436
-        $count_regs_for_this_ticket = $this->count_registrations(
1437
-            array(
1438
-                array(
1439
-                    'STS_ID'      => EEM_Registration::status_id_approved,
1440
-                    'REG_deleted' => 0,
1441
-                ),
1442
-            )
1443
-        );
1444
-        $this->set_sold($count_regs_for_this_ticket);
1445
-        $this->save();
1446
-        return $count_regs_for_this_ticket;
1447
-    }
1448
-
1449
-
1450
-    /**
1451
-     * Counts the registrations for this ticket
1452
-     *
1453
-     * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1454
-     * @return int
1455
-     */
1456
-    public function count_registrations($query_params = array())
1457
-    {
1458
-        return $this->count_related('Registration', $query_params);
1459
-    }
1460
-
1461
-
1462
-    /**
1463
-     * Implementation for EEI_Has_Icon interface method.
1464
-     *
1465
-     * @see EEI_Visual_Representation for comments
1466
-     * @return string
1467
-     */
1468
-    public function get_icon()
1469
-    {
1470
-        return '<span class="dashicons dashicons-tickets-alt"></span>';
1471
-    }
1472
-
1473
-
1474
-    /**
1475
-     * Implementation of the EEI_Event_Relation interface method
1476
-     *
1477
-     * @see EEI_Event_Relation for comments
1478
-     * @return EE_Event
1479
-     * @throws EE_Error
1480
-     * @throws UnexpectedEntityException
1481
-     */
1482
-    public function get_related_event()
1483
-    {
1484
-        // get one datetime to use for getting the event
1485
-        $datetime = $this->first_datetime();
1486
-        if (! $datetime instanceof \EE_Datetime) {
1487
-            throw new UnexpectedEntityException(
1488
-                $datetime,
1489
-                'EE_Datetime',
1490
-                sprintf(
1491
-                    __('The ticket (%s) is not associated with any valid datetimes.', 'event_espresso'),
1492
-                    $this->name()
1493
-                )
1494
-            );
1495
-        }
1496
-        $event = $datetime->event();
1497
-        if (! $event instanceof \EE_Event) {
1498
-            throw new UnexpectedEntityException(
1499
-                $event,
1500
-                'EE_Event',
1501
-                sprintf(
1502
-                    __('The ticket (%s) is not associated with a valid event.', 'event_espresso'),
1503
-                    $this->name()
1504
-                )
1505
-            );
1506
-        }
1507
-        return $event;
1508
-    }
1509
-
1510
-
1511
-    /**
1512
-     * Implementation of the EEI_Event_Relation interface method
1513
-     *
1514
-     * @see EEI_Event_Relation for comments
1515
-     * @return string
1516
-     * @throws UnexpectedEntityException
1517
-     * @throws EE_Error
1518
-     */
1519
-    public function get_event_name()
1520
-    {
1521
-        $event = $this->get_related_event();
1522
-        return $event instanceof EE_Event ? $event->name() : '';
1523
-    }
1524
-
1525
-
1526
-    /**
1527
-     * Implementation of the EEI_Event_Relation interface method
1528
-     *
1529
-     * @see EEI_Event_Relation for comments
1530
-     * @return int
1531
-     * @throws UnexpectedEntityException
1532
-     * @throws EE_Error
1533
-     */
1534
-    public function get_event_ID()
1535
-    {
1536
-        $event = $this->get_related_event();
1537
-        return $event instanceof EE_Event ? $event->ID() : 0;
1538
-    }
1539
-
1540
-
1541
-    /**
1542
-     * This simply returns whether a ticket can be permanently deleted or not.
1543
-     * The criteria for determining this is whether the ticket has any related registrations.
1544
-     * If there are none then it can be permanently deleted.
1545
-     *
1546
-     * @return bool
1547
-     */
1548
-    public function is_permanently_deleteable()
1549
-    {
1550
-        return $this->count_registrations() === 0;
1551
-    }
1552
-
1553
-
1554
-    /*******************************************************************
17
+	/**
18
+	 * TicKet Sold out:
19
+	 * constant used by ticket_status() to indicate that a ticket is sold out
20
+	 * and no longer available for purchase
21
+	 */
22
+	const sold_out = 'TKS';
23
+
24
+	/**
25
+	 * TicKet Expired:
26
+	 * constant used by ticket_status() to indicate that a ticket is expired
27
+	 * and no longer available for purchase
28
+	 */
29
+	const expired = 'TKE';
30
+
31
+	/**
32
+	 * TicKet Archived:
33
+	 * constant used by ticket_status() to indicate that a ticket is archived
34
+	 * and no longer available for purchase
35
+	 */
36
+	const archived = 'TKA';
37
+
38
+	/**
39
+	 * TicKet Pending:
40
+	 * constant used by ticket_status() to indicate that a ticket is pending
41
+	 * and is NOT YET available for purchase
42
+	 */
43
+	const pending = 'TKP';
44
+
45
+	/**
46
+	 * TicKet On sale:
47
+	 * constant used by ticket_status() to indicate that a ticket is On Sale
48
+	 * and IS available for purchase
49
+	 */
50
+	const onsale = 'TKO';
51
+
52
+	/**
53
+	 * extra meta key for tracking ticket reservations
54
+	 *
55
+	 * @type string
56
+	 */
57
+	const META_KEY_TICKET_RESERVATIONS = 'ticket_reservations';
58
+
59
+	/**
60
+	 * cached result from method of the same name
61
+	 *
62
+	 * @var float $_ticket_total_with_taxes
63
+	 */
64
+	private $_ticket_total_with_taxes;
65
+
66
+
67
+	/**
68
+	 * @param array  $props_n_values          incoming values
69
+	 * @param string $timezone                incoming timezone (if not set the timezone set for the website will be
70
+	 *                                        used.)
71
+	 * @param array  $date_formats            incoming date_formats in an array where the first value is the
72
+	 *                                        date_format and the second value is the time format
73
+	 * @return EE_Ticket
74
+	 * @throws EE_Error
75
+	 */
76
+	public static function new_instance($props_n_values = array(), $timezone = null, $date_formats = array())
77
+	{
78
+		$has_object = parent::_check_for_object($props_n_values, __CLASS__, $timezone, $date_formats);
79
+		return $has_object ? $has_object : new self($props_n_values, false, $timezone, $date_formats);
80
+	}
81
+
82
+
83
+	/**
84
+	 * @param array  $props_n_values  incoming values from the database
85
+	 * @param string $timezone        incoming timezone as set by the model.  If not set the timezone for
86
+	 *                                the website will be used.
87
+	 * @return EE_Ticket
88
+	 * @throws EE_Error
89
+	 */
90
+	public static function new_instance_from_db($props_n_values = array(), $timezone = null)
91
+	{
92
+		return new self($props_n_values, true, $timezone);
93
+	}
94
+
95
+
96
+	/**
97
+	 * @return bool
98
+	 * @throws EE_Error
99
+	 */
100
+	public function parent()
101
+	{
102
+		return $this->get('TKT_parent');
103
+	}
104
+
105
+
106
+	/**
107
+	 * return if a ticket has quantities available for purchase
108
+	 *
109
+	 * @param  int $DTT_ID the primary key for a particular datetime
110
+	 * @return boolean
111
+	 * @throws EE_Error
112
+	 */
113
+	public function available($DTT_ID = 0)
114
+	{
115
+		// are we checking availability for a particular datetime ?
116
+		if ($DTT_ID) {
117
+			// get that datetime object
118
+			$datetime = $this->get_first_related('Datetime', array(array('DTT_ID' => $DTT_ID)));
119
+			// if  ticket sales for this datetime have exceeded the reg limit...
120
+			if ($datetime instanceof EE_Datetime && $datetime->sold_out()) {
121
+				return false;
122
+			}
123
+		}
124
+		// datetime is still open for registration, but is this ticket sold out ?
125
+		return $this->qty() < 1 || $this->qty() > $this->sold() ? true : false;
126
+	}
127
+
128
+
129
+	/**
130
+	 * Using the start date and end date this method calculates whether the ticket is On Sale, Pending, or Expired
131
+	 *
132
+	 * @param bool        $display   true = we'll return a localized string, otherwise we just return the value of the
133
+	 *                               relevant status const
134
+	 * @param bool | null $remaining if it is already known that tickets are available, then simply pass a bool to save
135
+	 *               further processing
136
+	 * @return mixed status int if the display string isn't requested
137
+	 * @throws EE_Error
138
+	 */
139
+	public function ticket_status($display = false, $remaining = null)
140
+	{
141
+		$remaining = is_bool($remaining) ? $remaining : $this->is_remaining();
142
+		if (! $remaining) {
143
+			return $display ? EEH_Template::pretty_status(EE_Ticket::sold_out, false, 'sentence') : EE_Ticket::sold_out;
144
+		}
145
+		if ($this->get('TKT_deleted')) {
146
+			return $display ? EEH_Template::pretty_status(EE_Ticket::archived, false, 'sentence') : EE_Ticket::archived;
147
+		}
148
+		if ($this->is_expired()) {
149
+			return $display ? EEH_Template::pretty_status(EE_Ticket::expired, false, 'sentence') : EE_Ticket::expired;
150
+		}
151
+		if ($this->is_pending()) {
152
+			return $display ? EEH_Template::pretty_status(EE_Ticket::pending, false, 'sentence') : EE_Ticket::pending;
153
+		}
154
+		if ($this->is_on_sale()) {
155
+			return $display ? EEH_Template::pretty_status(EE_Ticket::onsale, false, 'sentence') : EE_Ticket::onsale;
156
+		}
157
+		return '';
158
+	}
159
+
160
+
161
+	/**
162
+	 * The purpose of this method is to simply return a boolean for whether there are any tickets remaining for sale
163
+	 * considering ALL the factors used for figuring that out.
164
+	 *
165
+	 * @access public
166
+	 * @param  int $DTT_ID if an int above 0 is included here then we get a specific dtt.
167
+	 * @return boolean         true = tickets remaining, false not.
168
+	 * @throws EE_Error
169
+	 */
170
+	public function is_remaining($DTT_ID = 0)
171
+	{
172
+		$num_remaining = $this->remaining($DTT_ID);
173
+		if ($num_remaining === 0) {
174
+			return false;
175
+		}
176
+		if ($num_remaining > 0 && $num_remaining < $this->min()) {
177
+			return false;
178
+		}
179
+		return true;
180
+	}
181
+
182
+
183
+	/**
184
+	 * return the total number of tickets available for purchase
185
+	 *
186
+	 * @param  int $DTT_ID the primary key for a particular datetime.
187
+	 *                     set to 0 for all related datetimes
188
+	 * @return int
189
+	 * @throws EE_Error
190
+	 */
191
+	public function remaining($DTT_ID = 0)
192
+	{
193
+		return $this->real_quantity_on_ticket('saleable', $DTT_ID);
194
+	}
195
+
196
+
197
+	/**
198
+	 * Gets min
199
+	 *
200
+	 * @return int
201
+	 * @throws EE_Error
202
+	 */
203
+	public function min()
204
+	{
205
+		return $this->get('TKT_min');
206
+	}
207
+
208
+
209
+	/**
210
+	 * return if a ticket is no longer available cause its available dates have expired.
211
+	 *
212
+	 * @return boolean
213
+	 * @throws EE_Error
214
+	 */
215
+	public function is_expired()
216
+	{
217
+		return ($this->get_raw('TKT_end_date') < time());
218
+	}
219
+
220
+
221
+	/**
222
+	 * Return if a ticket is yet to go on sale or not
223
+	 *
224
+	 * @return boolean
225
+	 * @throws EE_Error
226
+	 */
227
+	public function is_pending()
228
+	{
229
+		return ($this->get_raw('TKT_start_date') > time());
230
+	}
231
+
232
+
233
+	/**
234
+	 * Return if a ticket is on sale or not
235
+	 *
236
+	 * @return boolean
237
+	 * @throws EE_Error
238
+	 */
239
+	public function is_on_sale()
240
+	{
241
+		return ($this->get_raw('TKT_start_date') < time() && $this->get_raw('TKT_end_date') > time());
242
+	}
243
+
244
+
245
+	/**
246
+	 * This returns the chronologically last datetime that this ticket is associated with
247
+	 *
248
+	 * @param string $dt_frmt
249
+	 * @param string $conjunction - conjunction junction what's your function ? this string joins the start date with
250
+	 *                            the end date ie: Jan 01 "to" Dec 31
251
+	 * @return string
252
+	 * @throws EE_Error
253
+	 */
254
+	public function date_range($dt_frmt = '', $conjunction = ' - ')
255
+	{
256
+		$dt_frmt = ! empty($dt_frmt) ? $dt_frmt : $this->_dt_frmt;
257
+		$first_date = $this->first_datetime() instanceof EE_Datetime ? $this->first_datetime()->get_i18n_datetime('DTT_EVT_start', $dt_frmt)
258
+			: '';
259
+		$last_date = $this->last_datetime() instanceof EE_Datetime ? $this->last_datetime()->get_i18n_datetime('DTT_EVT_end', $dt_frmt) : '';
260
+
261
+		return $first_date && $last_date ? $first_date . $conjunction . $last_date : '';
262
+	}
263
+
264
+
265
+	/**
266
+	 * This returns the chronologically first datetime that this ticket is associated with
267
+	 *
268
+	 * @return EE_Datetime
269
+	 * @throws EE_Error
270
+	 */
271
+	public function first_datetime()
272
+	{
273
+		$datetimes = $this->datetimes(array('limit' => 1));
274
+		return reset($datetimes);
275
+	}
276
+
277
+
278
+	/**
279
+	 * Gets all the datetimes this ticket can be used for attending.
280
+	 * Unless otherwise specified, orders datetimes by start date.
281
+	 *
282
+	 * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
283
+	 * @return EE_Datetime[]|EE_Base_Class[]
284
+	 * @throws EE_Error
285
+	 */
286
+	public function datetimes($query_params = array())
287
+	{
288
+		if (! isset($query_params['order_by'])) {
289
+			$query_params['order_by']['DTT_order'] = 'ASC';
290
+		}
291
+		return $this->get_many_related('Datetime', $query_params);
292
+	}
293
+
294
+
295
+	/**
296
+	 * This returns the chronologically last datetime that this ticket is associated with
297
+	 *
298
+	 * @return EE_Datetime
299
+	 * @throws EE_Error
300
+	 */
301
+	public function last_datetime()
302
+	{
303
+		$datetimes = $this->datetimes(array('limit' => 1, 'order_by' => array('DTT_EVT_start' => 'DESC')));
304
+		return end($datetimes);
305
+	}
306
+
307
+
308
+	/**
309
+	 * This returns the total tickets sold depending on the given parameters.
310
+	 *
311
+	 * @param  string $what   Can be one of two options: 'ticket', 'datetime'.
312
+	 *                        'ticket' = total ticket sales for all datetimes this ticket is related to
313
+	 *                        'datetime' = total ticket sales for a specified datetime (required $dtt_id)
314
+	 *                        'datetime' = total ticket sales in the datetime_ticket table.
315
+	 *                        If $dtt_id is not given then we return an array of sales indexed by datetime.
316
+	 *                        If $dtt_id IS given then we return the tickets sold for that given datetime.
317
+	 * @param  int    $dtt_id [optional] include the dtt_id with $what = 'datetime'.
318
+	 * @return mixed (array|int)          how many tickets have sold
319
+	 * @throws EE_Error
320
+	 */
321
+	public function tickets_sold($what = 'ticket', $dtt_id = null)
322
+	{
323
+		$total = 0;
324
+		$tickets_sold = $this->_all_tickets_sold();
325
+		switch ($what) {
326
+			case 'ticket':
327
+				return $tickets_sold['ticket'];
328
+				break;
329
+			case 'datetime':
330
+				if (empty($tickets_sold['datetime'])) {
331
+					return $total;
332
+				}
333
+				if (! empty($dtt_id) && ! isset($tickets_sold['datetime'][ $dtt_id ])) {
334
+					EE_Error::add_error(
335
+						__(
336
+							'You\'ve requested the amount of tickets sold for a given ticket and datetime, however there are no records for the datetime id you included.  Are you SURE that is a datetime related to this ticket?',
337
+							'event_espresso'
338
+						),
339
+						__FILE__,
340
+						__FUNCTION__,
341
+						__LINE__
342
+					);
343
+					return $total;
344
+				}
345
+				return empty($dtt_id) ? $tickets_sold['datetime'] : $tickets_sold['datetime'][ $dtt_id ];
346
+				break;
347
+			default:
348
+				return $total;
349
+		}
350
+	}
351
+
352
+
353
+	/**
354
+	 * This returns an array indexed by datetime_id for tickets sold with this ticket.
355
+	 *
356
+	 * @return EE_Ticket[]
357
+	 * @throws EE_Error
358
+	 */
359
+	protected function _all_tickets_sold()
360
+	{
361
+		$datetimes = $this->get_many_related('Datetime');
362
+		$tickets_sold = array();
363
+		if (! empty($datetimes)) {
364
+			foreach ($datetimes as $datetime) {
365
+				$tickets_sold['datetime'][ $datetime->ID() ] = $datetime->get('DTT_sold');
366
+			}
367
+		}
368
+		// Tickets sold
369
+		$tickets_sold['ticket'] = $this->sold();
370
+		return $tickets_sold;
371
+	}
372
+
373
+
374
+	/**
375
+	 * This returns the base price object for the ticket.
376
+	 *
377
+	 * @param  bool $return_array whether to return as an array indexed by price id or just the object.
378
+	 * @return EE_Price|EE_Base_Class|EE_Price[]|EE_Base_Class[]
379
+	 * @throws EE_Error
380
+	 */
381
+	public function base_price($return_array = false)
382
+	{
383
+		$_where = array('Price_Type.PBT_ID' => EEM_Price_Type::base_type_base_price);
384
+		return $return_array
385
+			? $this->get_many_related('Price', array($_where))
386
+			: $this->get_first_related('Price', array($_where));
387
+	}
388
+
389
+
390
+	/**
391
+	 * This returns ONLY the price modifiers for the ticket (i.e. no taxes or base price)
392
+	 *
393
+	 * @access public
394
+	 * @return EE_Price[]
395
+	 * @throws EE_Error
396
+	 */
397
+	public function price_modifiers()
398
+	{
399
+		$query_params = array(
400
+			0 => array(
401
+				'Price_Type.PBT_ID' => array(
402
+					'NOT IN',
403
+					array(EEM_Price_Type::base_type_base_price, EEM_Price_Type::base_type_tax),
404
+				),
405
+			),
406
+		);
407
+		return $this->prices($query_params);
408
+	}
409
+
410
+
411
+	/**
412
+	 * Gets all the prices that combine to form the final price of this ticket
413
+	 *
414
+	 * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
415
+	 * @return EE_Price[]|EE_Base_Class[]
416
+	 * @throws EE_Error
417
+	 */
418
+	public function prices($query_params = array())
419
+	{
420
+		return $this->get_many_related('Price', $query_params);
421
+	}
422
+
423
+
424
+	/**
425
+	 * Gets all the ticket applicabilities (ie, relations between datetimes and tickets)
426
+	 *
427
+	 * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
428
+	 * @return EE_Datetime_Ticket|EE_Base_Class[]
429
+	 * @throws EE_Error
430
+	 */
431
+	public function datetime_tickets($query_params = array())
432
+	{
433
+		return $this->get_many_related('Datetime_Ticket', $query_params);
434
+	}
435
+
436
+
437
+	/**
438
+	 * Gets all the datetimes from the db ordered by DTT_order
439
+	 *
440
+	 * @param boolean $show_expired
441
+	 * @param boolean $show_deleted
442
+	 * @return EE_Datetime[]
443
+	 * @throws EE_Error
444
+	 */
445
+	public function datetimes_ordered($show_expired = true, $show_deleted = false)
446
+	{
447
+		return EEM_Datetime::instance($this->_timezone)->get_datetimes_for_ticket_ordered_by_DTT_order(
448
+			$this->ID(),
449
+			$show_expired,
450
+			$show_deleted
451
+		);
452
+	}
453
+
454
+
455
+	/**
456
+	 * Gets ID
457
+	 *
458
+	 * @return string
459
+	 * @throws EE_Error
460
+	 */
461
+	public function ID()
462
+	{
463
+		return $this->get('TKT_ID');
464
+	}
465
+
466
+
467
+	/**
468
+	 * get the author of the ticket.
469
+	 *
470
+	 * @since 4.5.0
471
+	 * @return int
472
+	 * @throws EE_Error
473
+	 */
474
+	public function wp_user()
475
+	{
476
+		return $this->get('TKT_wp_user');
477
+	}
478
+
479
+
480
+	/**
481
+	 * Gets the template for the ticket
482
+	 *
483
+	 * @return EE_Ticket_Template|EE_Base_Class
484
+	 * @throws EE_Error
485
+	 */
486
+	public function template()
487
+	{
488
+		return $this->get_first_related('Ticket_Template');
489
+	}
490
+
491
+
492
+	/**
493
+	 * Simply returns an array of EE_Price objects that are taxes.
494
+	 *
495
+	 * @return EE_Price[]
496
+	 * @throws EE_Error
497
+	 */
498
+	public function get_ticket_taxes_for_admin()
499
+	{
500
+		return EE_Taxes::get_taxes_for_admin();
501
+	}
502
+
503
+
504
+	/**
505
+	 * @return float
506
+	 * @throws EE_Error
507
+	 */
508
+	public function ticket_price()
509
+	{
510
+		return $this->get('TKT_price');
511
+	}
512
+
513
+
514
+	/**
515
+	 * @return mixed
516
+	 * @throws EE_Error
517
+	 */
518
+	public function pretty_price()
519
+	{
520
+		return $this->get_pretty('TKT_price');
521
+	}
522
+
523
+
524
+	/**
525
+	 * @return bool
526
+	 * @throws EE_Error
527
+	 */
528
+	public function is_free()
529
+	{
530
+		return $this->get_ticket_total_with_taxes() === (float) 0;
531
+	}
532
+
533
+
534
+	/**
535
+	 * get_ticket_total_with_taxes
536
+	 *
537
+	 * @param bool $no_cache
538
+	 * @return float
539
+	 * @throws EE_Error
540
+	 */
541
+	public function get_ticket_total_with_taxes($no_cache = false)
542
+	{
543
+		if ($this->_ticket_total_with_taxes === null || $no_cache) {
544
+			$this->_ticket_total_with_taxes = $this->get_ticket_subtotal() + $this->get_ticket_taxes_total_for_admin();
545
+		}
546
+		return (float) $this->_ticket_total_with_taxes;
547
+	}
548
+
549
+
550
+	public function ensure_TKT_Price_correct()
551
+	{
552
+		$this->set('TKT_price', EE_Taxes::get_subtotal_for_admin($this));
553
+		$this->save();
554
+	}
555
+
556
+
557
+	/**
558
+	 * @return float
559
+	 * @throws EE_Error
560
+	 */
561
+	public function get_ticket_subtotal()
562
+	{
563
+		return EE_Taxes::get_subtotal_for_admin($this);
564
+	}
565
+
566
+
567
+	/**
568
+	 * Returns the total taxes applied to this ticket
569
+	 *
570
+	 * @return float
571
+	 * @throws EE_Error
572
+	 */
573
+	public function get_ticket_taxes_total_for_admin()
574
+	{
575
+		return EE_Taxes::get_total_taxes_for_admin($this);
576
+	}
577
+
578
+
579
+	/**
580
+	 * Sets name
581
+	 *
582
+	 * @param string $name
583
+	 * @throws EE_Error
584
+	 */
585
+	public function set_name($name)
586
+	{
587
+		$this->set('TKT_name', $name);
588
+	}
589
+
590
+
591
+	/**
592
+	 * Gets description
593
+	 *
594
+	 * @return string
595
+	 * @throws EE_Error
596
+	 */
597
+	public function description()
598
+	{
599
+		return $this->get('TKT_description');
600
+	}
601
+
602
+
603
+	/**
604
+	 * Sets description
605
+	 *
606
+	 * @param string $description
607
+	 * @throws EE_Error
608
+	 */
609
+	public function set_description($description)
610
+	{
611
+		$this->set('TKT_description', $description);
612
+	}
613
+
614
+
615
+	/**
616
+	 * Gets start_date
617
+	 *
618
+	 * @param string $dt_frmt
619
+	 * @param string $tm_frmt
620
+	 * @return string
621
+	 * @throws EE_Error
622
+	 */
623
+	public function start_date($dt_frmt = '', $tm_frmt = '')
624
+	{
625
+		return $this->_get_datetime('TKT_start_date', $dt_frmt, $tm_frmt);
626
+	}
627
+
628
+
629
+	/**
630
+	 * Sets start_date
631
+	 *
632
+	 * @param string $start_date
633
+	 * @return void
634
+	 * @throws EE_Error
635
+	 */
636
+	public function set_start_date($start_date)
637
+	{
638
+		$this->_set_date_time('B', $start_date, 'TKT_start_date');
639
+	}
640
+
641
+
642
+	/**
643
+	 * Gets end_date
644
+	 *
645
+	 * @param string $dt_frmt
646
+	 * @param string $tm_frmt
647
+	 * @return string
648
+	 * @throws EE_Error
649
+	 */
650
+	public function end_date($dt_frmt = '', $tm_frmt = '')
651
+	{
652
+		return $this->_get_datetime('TKT_end_date', $dt_frmt, $tm_frmt);
653
+	}
654
+
655
+
656
+	/**
657
+	 * Sets end_date
658
+	 *
659
+	 * @param string $end_date
660
+	 * @return void
661
+	 * @throws EE_Error
662
+	 */
663
+	public function set_end_date($end_date)
664
+	{
665
+		$this->_set_date_time('B', $end_date, 'TKT_end_date');
666
+	}
667
+
668
+
669
+	/**
670
+	 * Sets sell until time
671
+	 *
672
+	 * @since 4.5.0
673
+	 * @param string $time a string representation of the sell until time (ex 9am or 7:30pm)
674
+	 * @throws EE_Error
675
+	 */
676
+	public function set_end_time($time)
677
+	{
678
+		$this->_set_time_for($time, 'TKT_end_date');
679
+	}
680
+
681
+
682
+	/**
683
+	 * Sets min
684
+	 *
685
+	 * @param int $min
686
+	 * @return void
687
+	 * @throws EE_Error
688
+	 */
689
+	public function set_min($min)
690
+	{
691
+		$this->set('TKT_min', $min);
692
+	}
693
+
694
+
695
+	/**
696
+	 * Gets max
697
+	 *
698
+	 * @return int
699
+	 * @throws EE_Error
700
+	 */
701
+	public function max()
702
+	{
703
+		return $this->get('TKT_max');
704
+	}
705
+
706
+
707
+	/**
708
+	 * Sets max
709
+	 *
710
+	 * @param int $max
711
+	 * @return void
712
+	 * @throws EE_Error
713
+	 */
714
+	public function set_max($max)
715
+	{
716
+		$this->set('TKT_max', $max);
717
+	}
718
+
719
+
720
+	/**
721
+	 * Sets price
722
+	 *
723
+	 * @param float $price
724
+	 * @return void
725
+	 * @throws EE_Error
726
+	 */
727
+	public function set_price($price)
728
+	{
729
+		$this->set('TKT_price', $price);
730
+	}
731
+
732
+
733
+	/**
734
+	 * Gets sold
735
+	 *
736
+	 * @return int
737
+	 * @throws EE_Error
738
+	 */
739
+	public function sold()
740
+	{
741
+		return $this->get_raw('TKT_sold');
742
+	}
743
+
744
+
745
+	/**
746
+	 * Sets sold
747
+	 *
748
+	 * @param int $sold
749
+	 * @return void
750
+	 * @throws EE_Error
751
+	 */
752
+	public function set_sold($sold)
753
+	{
754
+		// sold can not go below zero
755
+		$sold = max(0, $sold);
756
+		$this->set('TKT_sold', $sold);
757
+	}
758
+
759
+
760
+	/**
761
+	 * Increments sold by amount passed by $qty AND decrements the reserved count on both this ticket and its
762
+	 * associated datetimes.
763
+	 *
764
+	 * @since 4.9.80.p
765
+	 * @param int $qty
766
+	 * @return boolean
767
+	 * @throws EE_Error
768
+	 * @throws InvalidArgumentException
769
+	 * @throws InvalidDataTypeException
770
+	 * @throws InvalidInterfaceException
771
+	 * @throws ReflectionException
772
+	 */
773
+	public function increaseSold($qty = 1)
774
+	{
775
+		$qty = absint($qty);
776
+		// increment sold and decrement reserved datetime quantities simultaneously
777
+		// don't worry about failures, because they must have already had a spot reserved
778
+		$this->increaseSoldForDatetimes($qty);
779
+		// Increment and decrement ticket quantities simultaneously
780
+		$success = $this->adjustNumericFieldsInDb(
781
+			[
782
+				'TKT_reserved' => $qty * -1,
783
+				'TKT_sold' => $qty
784
+			]
785
+		);
786
+		do_action(
787
+			'AHEE__EE_Ticket__increase_sold',
788
+			$this,
789
+			$qty,
790
+			$this->sold(),
791
+			$success
792
+		);
793
+		return $success;
794
+	}
795
+
796
+	/**
797
+	 * On each datetime related to this ticket, increases its sold count and decreases its reserved count by $qty.
798
+	 *
799
+	 * @since 4.9.80.p
800
+	 * @param int $qty positive or negative. Positive means to increase sold counts (and decrease reserved counts),
801
+	 *             Negative means to decreases old counts (and increase reserved counts).
802
+	 * @param EE_Datetime[] $datetimes
803
+	 * @throws EE_Error
804
+	 * @throws InvalidArgumentException
805
+	 * @throws InvalidDataTypeException
806
+	 * @throws InvalidInterfaceException
807
+	 * @throws ReflectionException
808
+	 */
809
+	protected function increaseSoldForDatetimes($qty, array $datetimes = [])
810
+	{
811
+		$datetimes = ! empty($datetimes) ? $datetimes : $this->datetimes();
812
+		foreach ($datetimes as $datetime) {
813
+			$datetime->increaseSold($qty);
814
+		}
815
+	}
816
+
817
+
818
+
819
+	/**
820
+	 * Decrements (subtracts) sold by amount passed by $qty on both the ticket and its related datetimes directly in the
821
+	 * DB and then updates the model objects.
822
+	 * Does not affect the reserved counts.
823
+	 *
824
+	 * @since 4.9.80.p
825
+	 * @param int $qty
826
+	 * @return boolean
827
+	 * @throws EE_Error
828
+	 * @throws InvalidArgumentException
829
+	 * @throws InvalidDataTypeException
830
+	 * @throws InvalidInterfaceException
831
+	 * @throws ReflectionException
832
+	 */
833
+	public function decreaseSold($qty = 1)
834
+	{
835
+		$qty = absint($qty);
836
+		$this->decreaseSoldForDatetimes($qty);
837
+		$success = $this->adjustNumericFieldsInDb(
838
+			[
839
+				'TKT_sold' => $qty * -1
840
+			]
841
+		);
842
+		do_action(
843
+			'AHEE__EE_Ticket__decrease_sold',
844
+			$this,
845
+			$qty,
846
+			$this->sold(),
847
+			$success
848
+		);
849
+		return $success;
850
+	}
851
+
852
+
853
+	/**
854
+	 * Decreases sold on related datetimes
855
+	 *
856
+	 * @since 4.9.80.p
857
+	 * @param int $qty
858
+	 * @param EE_Datetime[] $datetimes
859
+	 * @return void
860
+	 * @throws EE_Error
861
+	 * @throws InvalidArgumentException
862
+	 * @throws InvalidDataTypeException
863
+	 * @throws InvalidInterfaceException
864
+	 * @throws ReflectionException
865
+	 */
866
+	protected function decreaseSoldForDatetimes($qty = 1, array $datetimes = [])
867
+	{
868
+		$datetimes = ! empty($datetimes) ? $datetimes : $this->datetimes();
869
+		if (is_array($datetimes)) {
870
+			foreach ($datetimes as $datetime) {
871
+				if ($datetime instanceof EE_Datetime) {
872
+					$datetime->decreaseSold($qty);
873
+				}
874
+			}
875
+		}
876
+	}
877
+
878
+
879
+	/**
880
+	 * Gets qty of reserved tickets
881
+	 *
882
+	 * @return int
883
+	 * @throws EE_Error
884
+	 */
885
+	public function reserved()
886
+	{
887
+		return $this->get_raw('TKT_reserved');
888
+	}
889
+
890
+
891
+	/**
892
+	 * Sets reserved
893
+	 *
894
+	 * @param int $reserved
895
+	 * @return void
896
+	 * @throws EE_Error
897
+	 */
898
+	public function set_reserved($reserved)
899
+	{
900
+		// reserved can not go below zero
901
+		$reserved = max(0, (int) $reserved);
902
+		$this->set('TKT_reserved', $reserved);
903
+	}
904
+
905
+
906
+	/**
907
+	 * Increments reserved by amount passed by $qty, and persists it immediately to the database.
908
+	 *
909
+	 * @since 4.9.80.p
910
+	 * @param int    $qty
911
+	 * @param string $source
912
+	 * @return bool whether we successfully reserved the ticket or not.
913
+	 * @throws EE_Error
914
+	 * @throws InvalidArgumentException
915
+	 * @throws ReflectionException
916
+	 * @throws InvalidDataTypeException
917
+	 * @throws InvalidInterfaceException
918
+	 */
919
+	public function increaseReserved($qty = 1, $source = 'unknown')
920
+	{
921
+		$qty = absint($qty);
922
+		do_action(
923
+			'AHEE__EE_Ticket__increase_reserved__begin',
924
+			$this,
925
+			$qty,
926
+			$source
927
+		);
928
+		$this->add_extra_meta(EE_Ticket::META_KEY_TICKET_RESERVATIONS, "{$qty} from {$source}");
929
+		$success = false;
930
+		$datetimes_adjusted_successfully = $this->increaseReservedForDatetimes($qty);
931
+		if ($datetimes_adjusted_successfully) {
932
+			$success = $this->incrementFieldConditionallyInDb(
933
+				'TKT_reserved',
934
+				'TKT_sold',
935
+				'TKT_qty',
936
+				$qty
937
+			);
938
+			if (! $success) {
939
+				// The datetimes were successfully bumped, but not the
940
+				// ticket. So we need to manually rollback the datetimes.
941
+				$this->decreaseReservedForDatetimes($qty);
942
+			}
943
+		}
944
+		do_action(
945
+			'AHEE__EE_Ticket__increase_reserved',
946
+			$this,
947
+			$qty,
948
+			$this->reserved(),
949
+			$success
950
+		);
951
+		return $success;
952
+	}
953
+
954
+
955
+	/**
956
+	 * Increases reserved counts on related datetimes
957
+	 *
958
+	 * @since 4.9.80.p
959
+	 * @param int $qty
960
+	 * @param EE_Datetime[] $datetimes
961
+	 * @return boolean indicating success
962
+	 * @throws EE_Error
963
+	 * @throws InvalidArgumentException
964
+	 * @throws InvalidDataTypeException
965
+	 * @throws InvalidInterfaceException
966
+	 * @throws ReflectionException
967
+	 */
968
+	protected function increaseReservedForDatetimes($qty = 1, array $datetimes = [])
969
+	{
970
+		$datetimes = ! empty($datetimes) ? $datetimes : $this->datetimes();
971
+		$datetimes_updated = [];
972
+		$limit_exceeded = false;
973
+		if (is_array($datetimes)) {
974
+			foreach ($datetimes as $datetime) {
975
+				if ($datetime instanceof EE_Datetime) {
976
+					if ($datetime->increaseReserved($qty)) {
977
+						$datetimes_updated[] = $datetime;
978
+					} else {
979
+						$limit_exceeded = true;
980
+						break;
981
+					}
982
+				}
983
+			}
984
+			// If somewhere along the way we detected a datetime whose
985
+			// limit was exceeded, do a manual rollback.
986
+			if ($limit_exceeded) {
987
+				$this->decreaseReservedForDatetimes($qty, $datetimes_updated);
988
+				return false;
989
+			}
990
+		}
991
+		return true;
992
+	}
993
+
994
+
995
+	/**
996
+	 * Decrements (subtracts) reserved by amount passed by $qty, and persists it immediately to the database.
997
+	 *
998
+	 * @since 4.9.80.p
999
+	 * @param int    $qty
1000
+	 * @param bool   $adjust_datetimes
1001
+	 * @param string $source
1002
+	 * @return boolean
1003
+	 * @throws EE_Error
1004
+	 * @throws InvalidArgumentException
1005
+	 * @throws ReflectionException
1006
+	 * @throws InvalidDataTypeException
1007
+	 * @throws InvalidInterfaceException
1008
+	 */
1009
+	public function decreaseReserved($qty = 1, $adjust_datetimes = true, $source = 'unknown')
1010
+	{
1011
+		$qty = absint($qty);
1012
+		$this->add_extra_meta(EE_Ticket::META_KEY_TICKET_RESERVATIONS, "-{$qty} from {$source}");
1013
+		if ($adjust_datetimes) {
1014
+			$this->decreaseReservedForDatetimes($qty);
1015
+		}
1016
+		$success = $this->adjustNumericFieldsInDb(
1017
+			[
1018
+				'TKT_reserved' => $qty * -1
1019
+			]
1020
+		);
1021
+		do_action(
1022
+			'AHEE__EE_Ticket__decrease_reserved',
1023
+			$this,
1024
+			$qty,
1025
+			$this->reserved(),
1026
+			$success
1027
+		);
1028
+		return $success;
1029
+	}
1030
+
1031
+
1032
+	/**
1033
+	 * Decreases the reserved count on the specified datetimes.
1034
+	 *
1035
+	 * @since 4.9.80.p
1036
+	 * @param int           $qty
1037
+	 * @param EE_Datetime[] $datetimes
1038
+	 * @throws EE_Error
1039
+	 * @throws InvalidArgumentException
1040
+	 * @throws ReflectionException
1041
+	 * @throws InvalidDataTypeException
1042
+	 * @throws InvalidInterfaceException
1043
+	 */
1044
+	protected function decreaseReservedForDatetimes($qty = 1, array $datetimes = [])
1045
+	{
1046
+		$datetimes = ! empty($datetimes) ? $datetimes : $this->datetimes();
1047
+		foreach ($datetimes as $datetime) {
1048
+			if ($datetime instanceof EE_Datetime) {
1049
+				$datetime->decreaseReserved($qty);
1050
+			}
1051
+		}
1052
+	}
1053
+
1054
+
1055
+	/**
1056
+	 * Gets ticket quantity
1057
+	 *
1058
+	 * @param string $context     ticket quantity is somewhat subjective depending on the exact information sought
1059
+	 *                            therefore $context can be one of three values: '', 'reg_limit', or 'saleable'
1060
+	 *                            '' (default) quantity is the actual db value for TKT_qty, unaffected by other objects
1061
+	 *                            REG LIMIT: caps qty based on DTT_reg_limit for ALL related datetimes
1062
+	 *                            SALEABLE: also considers datetime sold and returns zero if ANY DTT is sold out, and
1063
+	 *                            is therefore the truest measure of tickets that can be purchased at the moment
1064
+	 * @return int
1065
+	 * @throws EE_Error
1066
+	 */
1067
+	public function qty($context = '')
1068
+	{
1069
+		switch ($context) {
1070
+			case 'reg_limit':
1071
+				return $this->real_quantity_on_ticket();
1072
+			case 'saleable':
1073
+				return $this->real_quantity_on_ticket('saleable');
1074
+			default:
1075
+				return $this->get_raw('TKT_qty');
1076
+		}
1077
+	}
1078
+
1079
+
1080
+	/**
1081
+	 * Gets ticket quantity
1082
+	 *
1083
+	 * @param string $context     ticket quantity is somewhat subjective depending on the exact information sought
1084
+	 *                            therefore $context can be one of two values: 'reg_limit', or 'saleable'
1085
+	 *                            REG LIMIT: caps qty based on DTT_reg_limit for ALL related datetimes
1086
+	 *                            SALEABLE: also considers datetime sold and returns zero if ANY DTT is sold out, and
1087
+	 *                            is therefore the truest measure of tickets that can be purchased at the moment
1088
+	 * @param  int   $DTT_ID      the primary key for a particular datetime.
1089
+	 *                            set to 0 for all related datetimes
1090
+	 * @return int
1091
+	 * @throws EE_Error
1092
+	 */
1093
+	public function real_quantity_on_ticket($context = 'reg_limit', $DTT_ID = 0)
1094
+	{
1095
+		$raw = $this->get_raw('TKT_qty');
1096
+		// return immediately if it's zero
1097
+		if ($raw === 0) {
1098
+			return $raw;
1099
+		}
1100
+		// echo "\n\n<br />Ticket: " . $this->name() . '<br />';
1101
+		// ensure qty doesn't exceed raw value for THIS ticket
1102
+		$qty = min(EE_INF, $raw);
1103
+		// echo "\n . qty: " . $qty . '<br />';
1104
+		// calculate this ticket's total sales and reservations
1105
+		$sold_and_reserved_for_this_ticket = $this->sold() + $this->reserved();
1106
+		// echo "\n . sold: " . $this->sold() . '<br />';
1107
+		// echo "\n . reserved: " . $this->reserved() . '<br />';
1108
+		// echo "\n . sold_and_reserved_for_this_ticket: " . $sold_and_reserved_for_this_ticket . '<br />';
1109
+		// first we need to calculate the maximum number of tickets available for the datetime
1110
+		// do we want data for one datetime or all of them ?
1111
+		$query_params = $DTT_ID ? array(array('DTT_ID' => $DTT_ID)) : array();
1112
+		$datetimes = $this->datetimes($query_params);
1113
+		if (is_array($datetimes) && ! empty($datetimes)) {
1114
+			foreach ($datetimes as $datetime) {
1115
+				if ($datetime instanceof EE_Datetime) {
1116
+					$datetime->refresh_from_db();
1117
+					// echo "\n . . datetime name: " . $datetime->name() . '<br />';
1118
+					// echo "\n . . datetime ID: " . $datetime->ID() . '<br />';
1119
+					// initialize with no restrictions for each datetime
1120
+					// but adjust datetime qty based on datetime reg limit
1121
+					$datetime_qty = min(EE_INF, $datetime->reg_limit());
1122
+					// echo "\n . . . datetime reg_limit: " . $datetime->reg_limit() . '<br />';
1123
+					// echo "\n . . . datetime_qty: " . $datetime_qty . '<br />';
1124
+					// if we want the actual saleable amount, then we need to consider OTHER ticket sales
1125
+					// and reservations for this datetime, that do NOT include sales and reservations
1126
+					// for this ticket (so we add $this->sold() and $this->reserved() back in)
1127
+					if ($context === 'saleable') {
1128
+						$datetime_qty = max(
1129
+							$datetime_qty - $datetime->sold_and_reserved() + $sold_and_reserved_for_this_ticket,
1130
+							0
1131
+						);
1132
+						// echo "\n . . . datetime sold: " . $datetime->sold() . '<br />';
1133
+						// echo "\n . . . datetime reserved: " . $datetime->reserved() . '<br />';
1134
+						// echo "\n . . . datetime sold_and_reserved: " . $datetime->sold_and_reserved() . '<br />';
1135
+						// echo "\n . . . datetime_qty: " . $datetime_qty . '<br />';
1136
+						$datetime_qty = ! $datetime->sold_out() ? $datetime_qty : 0;
1137
+						// echo "\n . . . datetime_qty: " . $datetime_qty . '<br />';
1138
+					}
1139
+					$qty = min($datetime_qty, $qty);
1140
+					// echo "\n . . qty: " . $qty . '<br />';
1141
+				}
1142
+			}
1143
+		}
1144
+		// NOW that we know the  maximum number of tickets available for the datetime
1145
+		// we can finally factor in the details for this specific ticket
1146
+		if ($qty > 0 && $context === 'saleable') {
1147
+			// and subtract the sales for THIS ticket
1148
+			$qty = max($qty - $sold_and_reserved_for_this_ticket, 0);
1149
+			// echo "\n . qty: " . $qty . '<br />';
1150
+		}
1151
+		// echo "\nFINAL QTY: " . $qty . "<br /><br />";
1152
+		return $qty;
1153
+	}
1154
+
1155
+
1156
+	/**
1157
+	 * Sets qty - IMPORTANT!!! Does NOT allow QTY to be set higher than the lowest reg limit of any related datetimes
1158
+	 *
1159
+	 * @param int $qty
1160
+	 * @return void
1161
+	 * @throws EE_Error
1162
+	 */
1163
+	public function set_qty($qty)
1164
+	{
1165
+		$datetimes = $this->datetimes();
1166
+		foreach ($datetimes as $datetime) {
1167
+			if ($datetime instanceof EE_Datetime) {
1168
+				$qty = min($qty, $datetime->reg_limit());
1169
+			}
1170
+		}
1171
+		$this->set('TKT_qty', $qty);
1172
+	}
1173
+
1174
+
1175
+	/**
1176
+	 * Gets uses
1177
+	 *
1178
+	 * @return int
1179
+	 * @throws EE_Error
1180
+	 */
1181
+	public function uses()
1182
+	{
1183
+		return $this->get('TKT_uses');
1184
+	}
1185
+
1186
+
1187
+	/**
1188
+	 * Sets uses
1189
+	 *
1190
+	 * @param int $uses
1191
+	 * @return void
1192
+	 * @throws EE_Error
1193
+	 */
1194
+	public function set_uses($uses)
1195
+	{
1196
+		$this->set('TKT_uses', $uses);
1197
+	}
1198
+
1199
+
1200
+	/**
1201
+	 * returns whether ticket is required or not.
1202
+	 *
1203
+	 * @return boolean
1204
+	 * @throws EE_Error
1205
+	 */
1206
+	public function required()
1207
+	{
1208
+		return $this->get('TKT_required');
1209
+	}
1210
+
1211
+
1212
+	/**
1213
+	 * sets the TKT_required property
1214
+	 *
1215
+	 * @param boolean $required
1216
+	 * @return void
1217
+	 * @throws EE_Error
1218
+	 */
1219
+	public function set_required($required)
1220
+	{
1221
+		$this->set('TKT_required', $required);
1222
+	}
1223
+
1224
+
1225
+	/**
1226
+	 * Gets taxable
1227
+	 *
1228
+	 * @return boolean
1229
+	 * @throws EE_Error
1230
+	 */
1231
+	public function taxable()
1232
+	{
1233
+		return $this->get('TKT_taxable');
1234
+	}
1235
+
1236
+
1237
+	/**
1238
+	 * Sets taxable
1239
+	 *
1240
+	 * @param boolean $taxable
1241
+	 * @return void
1242
+	 * @throws EE_Error
1243
+	 */
1244
+	public function set_taxable($taxable)
1245
+	{
1246
+		$this->set('TKT_taxable', $taxable);
1247
+	}
1248
+
1249
+
1250
+	/**
1251
+	 * Gets is_default
1252
+	 *
1253
+	 * @return boolean
1254
+	 * @throws EE_Error
1255
+	 */
1256
+	public function is_default()
1257
+	{
1258
+		return $this->get('TKT_is_default');
1259
+	}
1260
+
1261
+
1262
+	/**
1263
+	 * Sets is_default
1264
+	 *
1265
+	 * @param boolean $is_default
1266
+	 * @return void
1267
+	 * @throws EE_Error
1268
+	 */
1269
+	public function set_is_default($is_default)
1270
+	{
1271
+		$this->set('TKT_is_default', $is_default);
1272
+	}
1273
+
1274
+
1275
+	/**
1276
+	 * Gets order
1277
+	 *
1278
+	 * @return int
1279
+	 * @throws EE_Error
1280
+	 */
1281
+	public function order()
1282
+	{
1283
+		return $this->get('TKT_order');
1284
+	}
1285
+
1286
+
1287
+	/**
1288
+	 * Sets order
1289
+	 *
1290
+	 * @param int $order
1291
+	 * @return void
1292
+	 * @throws EE_Error
1293
+	 */
1294
+	public function set_order($order)
1295
+	{
1296
+		$this->set('TKT_order', $order);
1297
+	}
1298
+
1299
+
1300
+	/**
1301
+	 * Gets row
1302
+	 *
1303
+	 * @return int
1304
+	 * @throws EE_Error
1305
+	 */
1306
+	public function row()
1307
+	{
1308
+		return $this->get('TKT_row');
1309
+	}
1310
+
1311
+
1312
+	/**
1313
+	 * Sets row
1314
+	 *
1315
+	 * @param int $row
1316
+	 * @return void
1317
+	 * @throws EE_Error
1318
+	 */
1319
+	public function set_row($row)
1320
+	{
1321
+		$this->set('TKT_row', $row);
1322
+	}
1323
+
1324
+
1325
+	/**
1326
+	 * Gets deleted
1327
+	 *
1328
+	 * @return boolean
1329
+	 * @throws EE_Error
1330
+	 */
1331
+	public function deleted()
1332
+	{
1333
+		return $this->get('TKT_deleted');
1334
+	}
1335
+
1336
+
1337
+	/**
1338
+	 * Sets deleted
1339
+	 *
1340
+	 * @param boolean $deleted
1341
+	 * @return void
1342
+	 * @throws EE_Error
1343
+	 */
1344
+	public function set_deleted($deleted)
1345
+	{
1346
+		$this->set('TKT_deleted', $deleted);
1347
+	}
1348
+
1349
+
1350
+	/**
1351
+	 * Gets parent
1352
+	 *
1353
+	 * @return int
1354
+	 * @throws EE_Error
1355
+	 */
1356
+	public function parent_ID()
1357
+	{
1358
+		return $this->get('TKT_parent');
1359
+	}
1360
+
1361
+
1362
+	/**
1363
+	 * Sets parent
1364
+	 *
1365
+	 * @param int $parent
1366
+	 * @return void
1367
+	 * @throws EE_Error
1368
+	 */
1369
+	public function set_parent_ID($parent)
1370
+	{
1371
+		$this->set('TKT_parent', $parent);
1372
+	}
1373
+
1374
+
1375
+	/**
1376
+	 * Gets a string which is handy for showing in gateways etc that describes the ticket.
1377
+	 *
1378
+	 * @return string
1379
+	 * @throws EE_Error
1380
+	 */
1381
+	public function name_and_info()
1382
+	{
1383
+		$times = array();
1384
+		foreach ($this->datetimes() as $datetime) {
1385
+			$times[] = $datetime->start_date_and_time();
1386
+		}
1387
+		return $this->name() . ' @ ' . implode(', ', $times) . ' for ' . $this->pretty_price();
1388
+	}
1389
+
1390
+
1391
+	/**
1392
+	 * Gets name
1393
+	 *
1394
+	 * @return string
1395
+	 * @throws EE_Error
1396
+	 */
1397
+	public function name()
1398
+	{
1399
+		return $this->get('TKT_name');
1400
+	}
1401
+
1402
+
1403
+	/**
1404
+	 * Gets price
1405
+	 *
1406
+	 * @return float
1407
+	 * @throws EE_Error
1408
+	 */
1409
+	public function price()
1410
+	{
1411
+		return $this->get('TKT_price');
1412
+	}
1413
+
1414
+
1415
+	/**
1416
+	 * Gets all the registrations for this ticket
1417
+	 *
1418
+	 * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1419
+	 * @return EE_Registration[]|EE_Base_Class[]
1420
+	 * @throws EE_Error
1421
+	 */
1422
+	public function registrations($query_params = array())
1423
+	{
1424
+		return $this->get_many_related('Registration', $query_params);
1425
+	}
1426
+
1427
+
1428
+	/**
1429
+	 * Updates the TKT_sold attribute (and saves) based on the number of APPROVED registrations for this ticket.
1430
+	 *
1431
+	 * @return int
1432
+	 * @throws EE_Error
1433
+	 */
1434
+	public function update_tickets_sold()
1435
+	{
1436
+		$count_regs_for_this_ticket = $this->count_registrations(
1437
+			array(
1438
+				array(
1439
+					'STS_ID'      => EEM_Registration::status_id_approved,
1440
+					'REG_deleted' => 0,
1441
+				),
1442
+			)
1443
+		);
1444
+		$this->set_sold($count_regs_for_this_ticket);
1445
+		$this->save();
1446
+		return $count_regs_for_this_ticket;
1447
+	}
1448
+
1449
+
1450
+	/**
1451
+	 * Counts the registrations for this ticket
1452
+	 *
1453
+	 * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1454
+	 * @return int
1455
+	 */
1456
+	public function count_registrations($query_params = array())
1457
+	{
1458
+		return $this->count_related('Registration', $query_params);
1459
+	}
1460
+
1461
+
1462
+	/**
1463
+	 * Implementation for EEI_Has_Icon interface method.
1464
+	 *
1465
+	 * @see EEI_Visual_Representation for comments
1466
+	 * @return string
1467
+	 */
1468
+	public function get_icon()
1469
+	{
1470
+		return '<span class="dashicons dashicons-tickets-alt"></span>';
1471
+	}
1472
+
1473
+
1474
+	/**
1475
+	 * Implementation of the EEI_Event_Relation interface method
1476
+	 *
1477
+	 * @see EEI_Event_Relation for comments
1478
+	 * @return EE_Event
1479
+	 * @throws EE_Error
1480
+	 * @throws UnexpectedEntityException
1481
+	 */
1482
+	public function get_related_event()
1483
+	{
1484
+		// get one datetime to use for getting the event
1485
+		$datetime = $this->first_datetime();
1486
+		if (! $datetime instanceof \EE_Datetime) {
1487
+			throw new UnexpectedEntityException(
1488
+				$datetime,
1489
+				'EE_Datetime',
1490
+				sprintf(
1491
+					__('The ticket (%s) is not associated with any valid datetimes.', 'event_espresso'),
1492
+					$this->name()
1493
+				)
1494
+			);
1495
+		}
1496
+		$event = $datetime->event();
1497
+		if (! $event instanceof \EE_Event) {
1498
+			throw new UnexpectedEntityException(
1499
+				$event,
1500
+				'EE_Event',
1501
+				sprintf(
1502
+					__('The ticket (%s) is not associated with a valid event.', 'event_espresso'),
1503
+					$this->name()
1504
+				)
1505
+			);
1506
+		}
1507
+		return $event;
1508
+	}
1509
+
1510
+
1511
+	/**
1512
+	 * Implementation of the EEI_Event_Relation interface method
1513
+	 *
1514
+	 * @see EEI_Event_Relation for comments
1515
+	 * @return string
1516
+	 * @throws UnexpectedEntityException
1517
+	 * @throws EE_Error
1518
+	 */
1519
+	public function get_event_name()
1520
+	{
1521
+		$event = $this->get_related_event();
1522
+		return $event instanceof EE_Event ? $event->name() : '';
1523
+	}
1524
+
1525
+
1526
+	/**
1527
+	 * Implementation of the EEI_Event_Relation interface method
1528
+	 *
1529
+	 * @see EEI_Event_Relation for comments
1530
+	 * @return int
1531
+	 * @throws UnexpectedEntityException
1532
+	 * @throws EE_Error
1533
+	 */
1534
+	public function get_event_ID()
1535
+	{
1536
+		$event = $this->get_related_event();
1537
+		return $event instanceof EE_Event ? $event->ID() : 0;
1538
+	}
1539
+
1540
+
1541
+	/**
1542
+	 * This simply returns whether a ticket can be permanently deleted or not.
1543
+	 * The criteria for determining this is whether the ticket has any related registrations.
1544
+	 * If there are none then it can be permanently deleted.
1545
+	 *
1546
+	 * @return bool
1547
+	 */
1548
+	public function is_permanently_deleteable()
1549
+	{
1550
+		return $this->count_registrations() === 0;
1551
+	}
1552
+
1553
+
1554
+	/*******************************************************************
1555 1555
      ***********************  DEPRECATED METHODS  **********************
1556 1556
      *******************************************************************/
1557 1557
 
1558 1558
 
1559
-    /**
1560
-     * Increments sold by amount passed by $qty AND decrements the reserved count on both this ticket and its
1561
-     * associated datetimes.
1562
-     *
1563
-     * @deprecated 4.9.80.p
1564
-     * @param int $qty
1565
-     * @return void
1566
-     * @throws EE_Error
1567
-     * @throws InvalidArgumentException
1568
-     * @throws InvalidDataTypeException
1569
-     * @throws InvalidInterfaceException
1570
-     * @throws ReflectionException
1571
-     */
1572
-    public function increase_sold($qty = 1)
1573
-    {
1574
-        EE_Error::doing_it_wrong(
1575
-            __FUNCTION__,
1576
-            esc_html__('Please use EE_Ticket::increaseSold() instead', 'event_espresso'),
1577
-            '4.9.80.p',
1578
-            '5.0.0.p'
1579
-        );
1580
-        $this->increaseSold($qty);
1581
-    }
1582
-
1583
-
1584
-    /**
1585
-     * On each datetime related to this ticket, increases its sold count and decreases its reserved count by $qty.
1586
-     *
1587
-     * @deprecated 4.9.80.p
1588
-     * @param int $qty positive or negative. Positive means to increase sold counts (and decrease reserved counts),
1589
-     *                 Negative means to decreases old counts (and increase reserved counts).
1590
-     * @throws EE_Error
1591
-     * @throws InvalidArgumentException
1592
-     * @throws InvalidDataTypeException
1593
-     * @throws InvalidInterfaceException
1594
-     * @throws ReflectionException
1595
-     */
1596
-    protected function _increase_sold_for_datetimes($qty)
1597
-    {
1598
-        EE_Error::doing_it_wrong(
1599
-            __FUNCTION__,
1600
-            esc_html__('Please use EE_Ticket::increaseSoldForDatetimes() instead', 'event_espresso'),
1601
-            '4.9.80.p',
1602
-            '5.0.0.p'
1603
-        );
1604
-        $this->increaseSoldForDatetimes($qty);
1605
-    }
1606
-
1607
-
1608
-    /**
1609
-     * Decrements (subtracts) sold by amount passed by $qty on both the ticket and its related datetimes directly in the
1610
-     * DB and then updates the model objects.
1611
-     * Does not affect the reserved counts.
1612
-     *
1613
-     * @deprecated 4.9.80.p
1614
-     * @param int $qty
1615
-     * @return void
1616
-     * @throws EE_Error
1617
-     * @throws InvalidArgumentException
1618
-     * @throws InvalidDataTypeException
1619
-     * @throws InvalidInterfaceException
1620
-     * @throws ReflectionException
1621
-     */
1622
-    public function decrease_sold($qty = 1)
1623
-    {
1624
-        EE_Error::doing_it_wrong(
1625
-            __FUNCTION__,
1626
-            esc_html__('Please use EE_Ticket::decreaseSold() instead', 'event_espresso'),
1627
-            '4.9.80.p',
1628
-            '5.0.0.p'
1629
-        );
1630
-        $this->decreaseSold($qty);
1631
-    }
1632
-
1633
-
1634
-    /**
1635
-     * Decreases sold on related datetimes
1636
-     *
1637
-     * @deprecated 4.9.80.p
1638
-     * @param int $qty
1639
-     * @return void
1640
-     * @throws EE_Error
1641
-     * @throws InvalidArgumentException
1642
-     * @throws InvalidDataTypeException
1643
-     * @throws InvalidInterfaceException
1644
-     * @throws ReflectionException
1645
-     */
1646
-    protected function _decrease_sold_for_datetimes($qty = 1)
1647
-    {
1648
-        EE_Error::doing_it_wrong(
1649
-            __FUNCTION__,
1650
-            esc_html__('Please use EE_Ticket::decreaseSoldForDatetimes() instead', 'event_espresso'),
1651
-            '4.9.80.p',
1652
-            '5.0.0.p'
1653
-        );
1654
-        $this->decreaseSoldForDatetimes($qty);
1655
-    }
1656
-
1657
-
1658
-    /**
1659
-     * Increments reserved by amount passed by $qty, and persists it immediately to the database.
1660
-     *
1661
-     * @deprecated 4.9.80.p
1662
-     * @param int    $qty
1663
-     * @param string $source
1664
-     * @return bool whether we successfully reserved the ticket or not.
1665
-     * @throws EE_Error
1666
-     * @throws InvalidArgumentException
1667
-     * @throws ReflectionException
1668
-     * @throws InvalidDataTypeException
1669
-     * @throws InvalidInterfaceException
1670
-     */
1671
-    public function increase_reserved($qty = 1, $source = 'unknown')
1672
-    {
1673
-        EE_Error::doing_it_wrong(
1674
-            __FUNCTION__,
1675
-            esc_html__('Please use EE_Ticket::increaseReserved() instead', 'event_espresso'),
1676
-            '4.9.80.p',
1677
-            '5.0.0.p'
1678
-        );
1679
-        return $this->increaseReserved($qty);
1680
-    }
1681
-
1682
-
1683
-    /**
1684
-     * Increases sold on related datetimes
1685
-     *
1686
-     * @deprecated 4.9.80.p
1687
-     * @param int $qty
1688
-     * @return boolean indicating success
1689
-     * @throws EE_Error
1690
-     * @throws InvalidArgumentException
1691
-     * @throws InvalidDataTypeException
1692
-     * @throws InvalidInterfaceException
1693
-     * @throws ReflectionException
1694
-     */
1695
-    protected function _increase_reserved_for_datetimes($qty = 1)
1696
-    {
1697
-        EE_Error::doing_it_wrong(
1698
-            __FUNCTION__,
1699
-            esc_html__('Please use EE_Ticket::increaseReservedForDatetimes() instead', 'event_espresso'),
1700
-            '4.9.80.p',
1701
-            '5.0.0.p'
1702
-        );
1703
-        return $this->increaseReservedForDatetimes($qty);
1704
-    }
1705
-
1706
-
1707
-    /**
1708
-     * Decrements (subtracts) reserved by amount passed by $qty, and persists it immediately to the database.
1709
-     *
1710
-     * @deprecated 4.9.80.p
1711
-     * @param int    $qty
1712
-     * @param bool   $adjust_datetimes
1713
-     * @param string $source
1714
-     * @return void
1715
-     * @throws EE_Error
1716
-     * @throws InvalidArgumentException
1717
-     * @throws ReflectionException
1718
-     * @throws InvalidDataTypeException
1719
-     * @throws InvalidInterfaceException
1720
-     */
1721
-    public function decrease_reserved($qty = 1, $adjust_datetimes = true, $source = 'unknown')
1722
-    {
1723
-        EE_Error::doing_it_wrong(
1724
-            __FUNCTION__,
1725
-            esc_html__('Please use EE_Ticket::decreaseReserved() instead', 'event_espresso'),
1726
-            '4.9.80.p',
1727
-            '5.0.0.p'
1728
-        );
1729
-        $this->decreaseReserved($qty);
1730
-    }
1731
-
1732
-
1733
-    /**
1734
-     * Decreases reserved on related datetimes
1735
-     *
1736
-     * @deprecated 4.9.80.p
1737
-     * @param int $qty
1738
-     * @return void
1739
-     * @throws EE_Error
1740
-     * @throws InvalidArgumentException
1741
-     * @throws ReflectionException
1742
-     * @throws InvalidDataTypeException
1743
-     * @throws InvalidInterfaceException
1744
-     */
1745
-    protected function _decrease_reserved_for_datetimes($qty = 1)
1746
-    {
1747
-        EE_Error::doing_it_wrong(
1748
-            __FUNCTION__,
1749
-            esc_html__('Please use EE_Ticket::decreaseReservedForDatetimes() instead', 'event_espresso'),
1750
-            '4.9.80.p',
1751
-            '5.0.0.p'
1752
-        );
1753
-        $this->decreaseReservedForDatetimes($qty);
1754
-    }
1559
+	/**
1560
+	 * Increments sold by amount passed by $qty AND decrements the reserved count on both this ticket and its
1561
+	 * associated datetimes.
1562
+	 *
1563
+	 * @deprecated 4.9.80.p
1564
+	 * @param int $qty
1565
+	 * @return void
1566
+	 * @throws EE_Error
1567
+	 * @throws InvalidArgumentException
1568
+	 * @throws InvalidDataTypeException
1569
+	 * @throws InvalidInterfaceException
1570
+	 * @throws ReflectionException
1571
+	 */
1572
+	public function increase_sold($qty = 1)
1573
+	{
1574
+		EE_Error::doing_it_wrong(
1575
+			__FUNCTION__,
1576
+			esc_html__('Please use EE_Ticket::increaseSold() instead', 'event_espresso'),
1577
+			'4.9.80.p',
1578
+			'5.0.0.p'
1579
+		);
1580
+		$this->increaseSold($qty);
1581
+	}
1582
+
1583
+
1584
+	/**
1585
+	 * On each datetime related to this ticket, increases its sold count and decreases its reserved count by $qty.
1586
+	 *
1587
+	 * @deprecated 4.9.80.p
1588
+	 * @param int $qty positive or negative. Positive means to increase sold counts (and decrease reserved counts),
1589
+	 *                 Negative means to decreases old counts (and increase reserved counts).
1590
+	 * @throws EE_Error
1591
+	 * @throws InvalidArgumentException
1592
+	 * @throws InvalidDataTypeException
1593
+	 * @throws InvalidInterfaceException
1594
+	 * @throws ReflectionException
1595
+	 */
1596
+	protected function _increase_sold_for_datetimes($qty)
1597
+	{
1598
+		EE_Error::doing_it_wrong(
1599
+			__FUNCTION__,
1600
+			esc_html__('Please use EE_Ticket::increaseSoldForDatetimes() instead', 'event_espresso'),
1601
+			'4.9.80.p',
1602
+			'5.0.0.p'
1603
+		);
1604
+		$this->increaseSoldForDatetimes($qty);
1605
+	}
1606
+
1607
+
1608
+	/**
1609
+	 * Decrements (subtracts) sold by amount passed by $qty on both the ticket and its related datetimes directly in the
1610
+	 * DB and then updates the model objects.
1611
+	 * Does not affect the reserved counts.
1612
+	 *
1613
+	 * @deprecated 4.9.80.p
1614
+	 * @param int $qty
1615
+	 * @return void
1616
+	 * @throws EE_Error
1617
+	 * @throws InvalidArgumentException
1618
+	 * @throws InvalidDataTypeException
1619
+	 * @throws InvalidInterfaceException
1620
+	 * @throws ReflectionException
1621
+	 */
1622
+	public function decrease_sold($qty = 1)
1623
+	{
1624
+		EE_Error::doing_it_wrong(
1625
+			__FUNCTION__,
1626
+			esc_html__('Please use EE_Ticket::decreaseSold() instead', 'event_espresso'),
1627
+			'4.9.80.p',
1628
+			'5.0.0.p'
1629
+		);
1630
+		$this->decreaseSold($qty);
1631
+	}
1632
+
1633
+
1634
+	/**
1635
+	 * Decreases sold on related datetimes
1636
+	 *
1637
+	 * @deprecated 4.9.80.p
1638
+	 * @param int $qty
1639
+	 * @return void
1640
+	 * @throws EE_Error
1641
+	 * @throws InvalidArgumentException
1642
+	 * @throws InvalidDataTypeException
1643
+	 * @throws InvalidInterfaceException
1644
+	 * @throws ReflectionException
1645
+	 */
1646
+	protected function _decrease_sold_for_datetimes($qty = 1)
1647
+	{
1648
+		EE_Error::doing_it_wrong(
1649
+			__FUNCTION__,
1650
+			esc_html__('Please use EE_Ticket::decreaseSoldForDatetimes() instead', 'event_espresso'),
1651
+			'4.9.80.p',
1652
+			'5.0.0.p'
1653
+		);
1654
+		$this->decreaseSoldForDatetimes($qty);
1655
+	}
1656
+
1657
+
1658
+	/**
1659
+	 * Increments reserved by amount passed by $qty, and persists it immediately to the database.
1660
+	 *
1661
+	 * @deprecated 4.9.80.p
1662
+	 * @param int    $qty
1663
+	 * @param string $source
1664
+	 * @return bool whether we successfully reserved the ticket or not.
1665
+	 * @throws EE_Error
1666
+	 * @throws InvalidArgumentException
1667
+	 * @throws ReflectionException
1668
+	 * @throws InvalidDataTypeException
1669
+	 * @throws InvalidInterfaceException
1670
+	 */
1671
+	public function increase_reserved($qty = 1, $source = 'unknown')
1672
+	{
1673
+		EE_Error::doing_it_wrong(
1674
+			__FUNCTION__,
1675
+			esc_html__('Please use EE_Ticket::increaseReserved() instead', 'event_espresso'),
1676
+			'4.9.80.p',
1677
+			'5.0.0.p'
1678
+		);
1679
+		return $this->increaseReserved($qty);
1680
+	}
1681
+
1682
+
1683
+	/**
1684
+	 * Increases sold on related datetimes
1685
+	 *
1686
+	 * @deprecated 4.9.80.p
1687
+	 * @param int $qty
1688
+	 * @return boolean indicating success
1689
+	 * @throws EE_Error
1690
+	 * @throws InvalidArgumentException
1691
+	 * @throws InvalidDataTypeException
1692
+	 * @throws InvalidInterfaceException
1693
+	 * @throws ReflectionException
1694
+	 */
1695
+	protected function _increase_reserved_for_datetimes($qty = 1)
1696
+	{
1697
+		EE_Error::doing_it_wrong(
1698
+			__FUNCTION__,
1699
+			esc_html__('Please use EE_Ticket::increaseReservedForDatetimes() instead', 'event_espresso'),
1700
+			'4.9.80.p',
1701
+			'5.0.0.p'
1702
+		);
1703
+		return $this->increaseReservedForDatetimes($qty);
1704
+	}
1705
+
1706
+
1707
+	/**
1708
+	 * Decrements (subtracts) reserved by amount passed by $qty, and persists it immediately to the database.
1709
+	 *
1710
+	 * @deprecated 4.9.80.p
1711
+	 * @param int    $qty
1712
+	 * @param bool   $adjust_datetimes
1713
+	 * @param string $source
1714
+	 * @return void
1715
+	 * @throws EE_Error
1716
+	 * @throws InvalidArgumentException
1717
+	 * @throws ReflectionException
1718
+	 * @throws InvalidDataTypeException
1719
+	 * @throws InvalidInterfaceException
1720
+	 */
1721
+	public function decrease_reserved($qty = 1, $adjust_datetimes = true, $source = 'unknown')
1722
+	{
1723
+		EE_Error::doing_it_wrong(
1724
+			__FUNCTION__,
1725
+			esc_html__('Please use EE_Ticket::decreaseReserved() instead', 'event_espresso'),
1726
+			'4.9.80.p',
1727
+			'5.0.0.p'
1728
+		);
1729
+		$this->decreaseReserved($qty);
1730
+	}
1731
+
1732
+
1733
+	/**
1734
+	 * Decreases reserved on related datetimes
1735
+	 *
1736
+	 * @deprecated 4.9.80.p
1737
+	 * @param int $qty
1738
+	 * @return void
1739
+	 * @throws EE_Error
1740
+	 * @throws InvalidArgumentException
1741
+	 * @throws ReflectionException
1742
+	 * @throws InvalidDataTypeException
1743
+	 * @throws InvalidInterfaceException
1744
+	 */
1745
+	protected function _decrease_reserved_for_datetimes($qty = 1)
1746
+	{
1747
+		EE_Error::doing_it_wrong(
1748
+			__FUNCTION__,
1749
+			esc_html__('Please use EE_Ticket::decreaseReservedForDatetimes() instead', 'event_espresso'),
1750
+			'4.9.80.p',
1751
+			'5.0.0.p'
1752
+		);
1753
+		$this->decreaseReservedForDatetimes($qty);
1754
+	}
1755 1755
 }
Please login to merge, or discard this patch.
core/domain/services/assets/CoreAssetManager.php 1 patch
Indentation   +544 added lines, -544 removed lines patch added patch discarded remove patch
@@ -32,570 +32,570 @@
 block discarded – undo
32 32
 class CoreAssetManager extends AssetManager
33 33
 {
34 34
 
35
-    // WordPress core / Third party JS asset handles
36
-    const JS_HANDLE_JQUERY = 'jquery';
35
+	// WordPress core / Third party JS asset handles
36
+	const JS_HANDLE_JQUERY = 'jquery';
37 37
 
38
-    const JS_HANDLE_JQUERY_VALIDATE = 'jquery-validate';
38
+	const JS_HANDLE_JQUERY_VALIDATE = 'jquery-validate';
39 39
 
40
-    const JS_HANDLE_JQUERY_VALIDATE_EXTRA = 'jquery-validate-extra-methods';
40
+	const JS_HANDLE_JQUERY_VALIDATE_EXTRA = 'jquery-validate-extra-methods';
41 41
 
42
-    const JS_HANDLE_UNDERSCORE = 'underscore';
42
+	const JS_HANDLE_UNDERSCORE = 'underscore';
43 43
 
44
-    const JS_HANDLE_ACCOUNTING_CORE = 'ee-accounting-core';
44
+	const JS_HANDLE_ACCOUNTING_CORE = 'ee-accounting-core';
45 45
 
46
-    /**
47
-     * @since 4.9.71.p
48
-     */
49
-    const JS_HANDLE_REACT = 'react';
46
+	/**
47
+	 * @since 4.9.71.p
48
+	 */
49
+	const JS_HANDLE_REACT = 'react';
50 50
 
51
-    /**
52
-     * @since 4.9.71.p
53
-     */
54
-    const JS_HANDLE_REACT_DOM = 'react-dom';
51
+	/**
52
+	 * @since 4.9.71.p
53
+	 */
54
+	const JS_HANDLE_REACT_DOM = 'react-dom';
55 55
 
56
-    /**
57
-     * @since 4.9.71.p
58
-     */
59
-    const JS_HANDLE_LODASH = 'lodash';
56
+	/**
57
+	 * @since 4.9.71.p
58
+	 */
59
+	const JS_HANDLE_LODASH = 'lodash';
60 60
 
61
-    // EE JS assets handles
62
-    const JS_HANDLE_MANIFEST = 'ee-manifest';
61
+	// EE JS assets handles
62
+	const JS_HANDLE_MANIFEST = 'ee-manifest';
63 63
 
64
-    const JS_HANDLE_JS_CORE = 'eejs-core';
64
+	const JS_HANDLE_JS_CORE = 'eejs-core';
65 65
 
66
-    const JS_HANDLE_VENDOR = 'eventespresso-vendor';
66
+	const JS_HANDLE_VENDOR = 'eventespresso-vendor';
67 67
 
68
-    const JS_HANDLE_DATA_STORES = 'eventespresso-data-stores';
68
+	const JS_HANDLE_DATA_STORES = 'eventespresso-data-stores';
69 69
 
70
-    const JS_HANDLE_HELPERS = 'eventespresso-helpers';
70
+	const JS_HANDLE_HELPERS = 'eventespresso-helpers';
71 71
 
72
-    const JS_HANDLE_MODEL = 'eventespresso-model';
72
+	const JS_HANDLE_MODEL = 'eventespresso-model';
73 73
 
74
-    const JS_HANDLE_VALUE_OBJECTS = 'eventespresso-value-objects';
74
+	const JS_HANDLE_VALUE_OBJECTS = 'eventespresso-value-objects';
75 75
 
76
-    const JS_HANDLE_HOCS = 'eventespresso-hocs';
76
+	const JS_HANDLE_HOCS = 'eventespresso-hocs';
77 77
 
78
-    const JS_HANDLE_COMPONENTS = 'eventespresso-components';
78
+	const JS_HANDLE_COMPONENTS = 'eventespresso-components';
79 79
 
80
-    const JS_HANDLE_EDITOR_HOCS = 'eventespresso-editor-hocs';
80
+	const JS_HANDLE_EDITOR_HOCS = 'eventespresso-editor-hocs';
81 81
 
82
-    const JS_HANDLE_VALIDATORS = 'eventespresso-validators';
82
+	const JS_HANDLE_VALIDATORS = 'eventespresso-validators';
83 83
 
84
-    const JS_HANDLE_CORE = 'espresso_core';
84
+	const JS_HANDLE_CORE = 'espresso_core';
85 85
 
86
-    const JS_HANDLE_I18N = 'eei18n';
86
+	const JS_HANDLE_I18N = 'eei18n';
87 87
 
88
-    const JS_HANDLE_ACCOUNTING = 'ee-accounting';
88
+	const JS_HANDLE_ACCOUNTING = 'ee-accounting';
89 89
 
90
-    const JS_HANDLE_WP_PLUGINS_PAGE = 'ee-wp-plugins-page';
91
-
92
-    // EE CSS assets handles
93
-    const CSS_HANDLE_DEFAULT = 'espresso_default';
94
-
95
-    const CSS_HANDLE_CUSTOM = 'espresso_custom_css';
96
-
97
-    const CSS_HANDLE_COMPONENTS = 'eventespresso-components';
98
-
99
-    const CSS_HANDLE_CORE_CSS_DEFAULT = 'eventespresso-core-css-default';
100
-
101
-    /**
102
-     * @var EE_Currency_Config $currency_config
103
-     */
104
-    protected $currency_config;
105
-
106
-    /**
107
-     * @var EE_Template_Config $template_config
108
-     */
109
-    protected $template_config;
110
-
111
-
112
-    /**
113
-     * CoreAssetRegister constructor.
114
-     *
115
-     * @param AssetCollection    $assets
116
-     * @param EE_Currency_Config $currency_config
117
-     * @param EE_Template_Config $template_config
118
-     * @param DomainInterface    $domain
119
-     * @param Registry           $registry
120
-     */
121
-    public function __construct(
122
-        AssetCollection $assets,
123
-        EE_Currency_Config $currency_config,
124
-        EE_Template_Config $template_config,
125
-        DomainInterface $domain,
126
-        Registry $registry
127
-    ) {
128
-        $this->currency_config = $currency_config;
129
-        $this->template_config = $template_config;
130
-        parent::__construct($domain, $assets, $registry);
131
-    }
132
-
133
-
134
-    /**
135
-     * @since 4.9.62.p
136
-     * @throws DomainException
137
-     * @throws DuplicateCollectionIdentifierException
138
-     * @throws InvalidArgumentException
139
-     * @throws InvalidDataTypeException
140
-     * @throws InvalidEntityException
141
-     * @throws InvalidInterfaceException
142
-     */
143
-    public function addAssets()
144
-    {
145
-        $this->addJavascriptFiles();
146
-        $this->addStylesheetFiles();
147
-    }
148
-
149
-
150
-    /**
151
-     * @since 4.9.62.p
152
-     * @throws DomainException
153
-     * @throws DuplicateCollectionIdentifierException
154
-     * @throws InvalidArgumentException
155
-     * @throws InvalidDataTypeException
156
-     * @throws InvalidEntityException
157
-     * @throws InvalidInterfaceException
158
-     */
159
-    public function addJavascriptFiles()
160
-    {
161
-        $this->loadCoreJs();
162
-        $this->loadJqueryValidate();
163
-        $this->loadAccountingJs();
164
-        add_action(
165
-            'AHEE__EventEspresso_core_services_assets_Registry__registerScripts__before_script',
166
-            array($this, 'loadQtipJs')
167
-        );
168
-        $this->registerAdminAssets();
169
-    }
170
-
171
-
172
-    /**
173
-     * @since 4.9.62.p
174
-     * @throws DuplicateCollectionIdentifierException
175
-     * @throws InvalidDataTypeException
176
-     * @throws InvalidEntityException
177
-     */
178
-    public function addStylesheetFiles()
179
-    {
180
-        $this->loadCoreCss();
181
-    }
182
-
183
-
184
-    /**
185
-     * core default javascript
186
-     *
187
-     * @since 4.9.62.p
188
-     * @throws DomainException
189
-     * @throws DuplicateCollectionIdentifierException
190
-     * @throws InvalidArgumentException
191
-     * @throws InvalidDataTypeException
192
-     * @throws InvalidEntityException
193
-     * @throws InvalidInterfaceException
194
-     */
195
-    private function loadCoreJs()
196
-    {
197
-        // conditionally load third-party libraries that WP core MIGHT have.
198
-        $this->registerWpAssets();
199
-
200
-        $this->addJavascript(
201
-            CoreAssetManager::JS_HANDLE_MANIFEST,
202
-            $this->registry->getJsUrl($this->domain->assetNamespace(), 'manifest')
203
-        );
204
-
205
-        $this->addJavascript(
206
-            CoreAssetManager::JS_HANDLE_JS_CORE,
207
-            $this->registry->getJsUrl($this->domain->assetNamespace(), 'eejs'),
208
-            array(CoreAssetManager::JS_HANDLE_MANIFEST)
209
-        )
210
-        ->setHasInlineData();
211
-
212
-        $this->addJavascript(
213
-            CoreAssetManager::JS_HANDLE_VENDOR,
214
-            $this->registry->getJsUrl($this->domain->assetNamespace(), 'vendor'),
215
-            array(
216
-                CoreAssetManager::JS_HANDLE_JS_CORE,
217
-                CoreAssetManager::JS_HANDLE_REACT,
218
-                CoreAssetManager::JS_HANDLE_REACT_DOM,
219
-                CoreAssetManager::JS_HANDLE_LODASH,
220
-            )
221
-        );
222
-
223
-        $this->addJavascript(
224
-            CoreAssetManager::JS_HANDLE_VALIDATORS,
225
-            $this->registry->getJsUrl($this->domain->assetNamespace(), 'validators')
226
-        )->setRequiresTranslation();
227
-
228
-        $this->addJavascript(
229
-            CoreAssetManager::JS_HANDLE_HELPERS,
230
-            $this->registry->getJsUrl($this->domain->assetNamespace(), 'helpers'),
231
-            array(
232
-                CoreAssetManager::JS_HANDLE_VALIDATORS
233
-            )
234
-        )->setRequiresTranslation();
235
-
236
-        $this->addJavascript(
237
-            CoreAssetManager::JS_HANDLE_MODEL,
238
-            $this->registry->getJsUrl($this->domain->assetNamespace(), 'model'),
239
-            array(
240
-                CoreAssetManager::JS_HANDLE_HELPERS,
241
-                CoreAssetManager::JS_HANDLE_VALUE_OBJECTS,
242
-            )
243
-        )->setRequiresTranslation();
244
-
245
-        $this->addJavascript(
246
-            CoreAssetManager::JS_HANDLE_VALUE_OBJECTS,
247
-            $this->registry->getJsUrl($this->domain->assetNamespace(), 'valueObjects'),
248
-            array(
249
-                CoreAssetManager::JS_HANDLE_VALIDATORS,
250
-                CoreAssetManager::JS_HANDLE_HELPERS,
251
-            )
252
-        )->setRequiresTranslation();
253
-
254
-        $this->addJavascript(
255
-            CoreAssetManager::JS_HANDLE_DATA_STORES,
256
-            $this->registry->getJsUrl($this->domain->assetNamespace(), 'data-stores'),
257
-            array(
258
-                CoreAssetManager::JS_HANDLE_VENDOR,
259
-                'wp-data',
260
-                'wp-api-fetch',
261
-                CoreAssetManager::JS_HANDLE_VALUE_OBJECTS,
262
-                CoreAssetManager::JS_HANDLE_MODEL,
263
-            )
264
-        )
265
-             ->setRequiresTranslation()
266
-             ->setInlineDataCallback(
267
-                 function() {
268
-                     wp_add_inline_script(
269
-                         CoreAssetManager::JS_HANDLE_DATA_STORES,
270
-                         is_admin()
271
-                             ? 'wp.apiFetch.use( eejs.middleWares.apiFetch.capsMiddleware( eejs.middleWares.apiFetch.CONTEXT_CAPS_EDIT ) )'
272
-                             : 'wp.apiFetch.use( eejs.middleWares.apiFetch.capsMiddleware )'
273
-                     );
274
-                 }
275
-             );
276
-
277
-        $this->addJavascript(
278
-            CoreAssetManager::JS_HANDLE_HOCS,
279
-            $this->registry->getJsUrl($this->domain->assetNamespace(), 'hocs'),
280
-            array(
281
-                CoreAssetManager::JS_HANDLE_DATA_STORES,
282
-                CoreAssetManager::JS_HANDLE_VALUE_OBJECTS,
283
-                'wp-components',
284
-            )
285
-        )->setRequiresTranslation();
286
-
287
-        $this->addJavascript(
288
-            CoreAssetManager::JS_HANDLE_COMPONENTS,
289
-            $this->registry->getJsUrl($this->domain->assetNamespace(), 'components'),
290
-            array(
291
-                CoreAssetManager::JS_HANDLE_DATA_STORES,
292
-                CoreAssetManager::JS_HANDLE_VALUE_OBJECTS,
293
-                'wp-components',
294
-            )
295
-        )
296
-        ->setRequiresTranslation();
297
-
298
-        $this->addJavascript(
299
-            CoreAssetManager::JS_HANDLE_EDITOR_HOCS,
300
-            $this->registry->getJsUrl($this->domain->assetNamespace(), 'editor-hocs'),
301
-            array(
302
-                CoreAssetManager::JS_HANDLE_COMPONENTS
303
-            )
304
-        )->setRequiresTranslation();
305
-
306
-        $this->registry->addData('eejs_api_nonce', wp_create_nonce('wp_rest'));
307
-        $this->registry->addData(
308
-            'paths',
309
-            array(
310
-                'base_rest_route' => rest_url(),
311
-                'rest_route' => rest_url('ee/v4.8.36/'),
312
-                'collection_endpoints' => EED_Core_Rest_Api::getCollectionRoutesIndexedByModelName(),
313
-                'primary_keys' => EED_Core_Rest_Api::getPrimaryKeyNamesIndexedByModelName(),
314
-                'site_url' => site_url('/'),
315
-                'admin_url' => admin_url('/'),
316
-            )
317
-        );
318
-        // Event Espresso brand name
319
-        $this->registry->addData('brandName', Domain::brandName());
320
-        /** site formatting values **/
321
-        $this->registry->addData(
322
-            'site_formats',
323
-            array(
324
-                'date_formats' => EEH_DTT_Helper::convert_php_to_js_and_moment_date_formats()
325
-            )
326
-        );
327
-        /** currency data **/
328
-        $this->registry->addData(
329
-            'currency_config',
330
-            $this->getCurrencySettings()
331
-        );
332
-        /** site timezone */
333
-        $this->registry->addData(
334
-            'default_timezone',
335
-            array(
336
-                'pretty' => EEH_DTT_Helper::get_timezone_string_for_display(),
337
-                'string' => get_option('timezone_string'),
338
-                'offset' => EEH_DTT_Helper::get_site_timezone_gmt_offset(),
339
-            )
340
-        );
341
-        /** site locale (user locale if user logged in) */
342
-        $this->registry->addData(
343
-            'locale',
344
-            array(
345
-                'user' => get_user_locale(),
346
-                'site' => get_locale()
347
-            )
348
-        );
349
-
350
-        $this->addJavascript(
351
-            CoreAssetManager::JS_HANDLE_CORE,
352
-            EE_GLOBAL_ASSETS_URL . 'scripts/espresso_core.js',
353
-            array(CoreAssetManager::JS_HANDLE_JQUERY)
354
-        )
355
-        ->setInlineDataCallback(
356
-            function () {
357
-                wp_localize_script(
358
-                    CoreAssetManager::JS_HANDLE_CORE,
359
-                    CoreAssetManager::JS_HANDLE_I18N,
360
-                    EE_Registry::$i18n_js_strings
361
-                );
362
-            }
363
-        );
364
-    }
365
-
366
-
367
-    /**
368
-     * Registers vendor files that are bundled with a later version WP but might not be for the current version of
369
-     * WordPress in the running environment.
370
-     *
371
-     * @throws DuplicateCollectionIdentifierException
372
-     * @throws InvalidDataTypeException
373
-     * @throws InvalidEntityException
374
-     * @throws DomainException
375
-     * @since 4.9.71.p
376
-     */
377
-    private function registerWpAssets()
378
-    {
379
-        global $wp_version;
380
-        if (version_compare($wp_version, '5.0.beta', '>=')) {
381
-            return;
382
-        }
383
-        $this->addVendorJavascript(CoreAssetManager::JS_HANDLE_REACT)
384
-            ->setVersion('16.6.0');
385
-        $this->addVendorJavascript(
386
-            CoreAssetManager::JS_HANDLE_REACT_DOM,
387
-            array(CoreAssetManager::JS_HANDLE_REACT)
388
-        )->setVersion('16.6.0');
389
-        $this->addVendorJavascript(CoreAssetManager::JS_HANDLE_LODASH)
390
-            ->setInlineDataCallback(
391
-                function() {
392
-                    wp_add_inline_script(
393
-                        CoreAssetManager::JS_HANDLE_LODASH,
394
-                        'window.lodash = _.noConflict();'
395
-                    );
396
-                }
397
-            )
398
-            ->setVersion('4.17.11');
399
-    }
400
-
401
-
402
-    /**
403
-     * Returns configuration data for the accounting-js library.
404
-     * @since 4.9.71.p
405
-     * @return array
406
-     */
407
-    private function getAccountingSettings() {
408
-        return array(
409
-            'currency' => array(
410
-                'symbol'    => $this->currency_config->sign,
411
-                'format'    => array(
412
-                    'pos'  => $this->currency_config->sign_b4 ? '%s%v' : '%v%s',
413
-                    'neg'  => $this->currency_config->sign_b4 ? '- %s%v' : '- %v%s',
414
-                    'zero' => $this->currency_config->sign_b4 ? '%s--' : '--%s',
415
-                ),
416
-                'decimal'   => $this->currency_config->dec_mrk,
417
-                'thousand'  => $this->currency_config->thsnds,
418
-                'precision' => $this->currency_config->dec_plc,
419
-            ),
420
-            'number'   => array(
421
-                'precision' => $this->currency_config->dec_plc,
422
-                'thousand'  => $this->currency_config->thsnds,
423
-                'decimal'   => $this->currency_config->dec_mrk,
424
-            ),
425
-        );
426
-    }
427
-
428
-
429
-    /**
430
-     * Returns configuration data for the js Currency VO.
431
-     * @since 4.9.71.p
432
-     * @return array
433
-     */
434
-    private function getCurrencySettings()
435
-    {
436
-        return array(
437
-            'code' => $this->currency_config->code,
438
-            'singularLabel' => $this->currency_config->name,
439
-            'pluralLabel' => $this->currency_config->plural,
440
-            'sign' => $this->currency_config->sign,
441
-            'signB4' => $this->currency_config->sign_b4,
442
-            'decimalPlaces' => $this->currency_config->dec_plc,
443
-            'decimalMark' => $this->currency_config->dec_mrk,
444
-            'thousandsSeparator' => $this->currency_config->thsnds,
445
-        );
446
-    }
447
-
448
-
449
-    /**
450
-     * @since 4.9.62.p
451
-     * @throws DuplicateCollectionIdentifierException
452
-     * @throws InvalidDataTypeException
453
-     * @throws InvalidEntityException
454
-     */
455
-    private function loadCoreCss()
456
-    {
457
-        if ($this->template_config->enable_default_style && ! is_admin()) {
458
-            $this->addStylesheet(
459
-                CoreAssetManager::CSS_HANDLE_DEFAULT,
460
-                is_readable(EVENT_ESPRESSO_UPLOAD_DIR . 'css/style.css')
461
-                    ? EVENT_ESPRESSO_UPLOAD_DIR . 'css/espresso_default.css'
462
-                    : EE_GLOBAL_ASSETS_URL . 'css/espresso_default.css',
463
-                array('dashicons')
464
-            );
465
-            //Load custom style sheet if available
466
-            if ($this->template_config->custom_style_sheet !== null) {
467
-                $this->addStylesheet(
468
-                    CoreAssetManager::CSS_HANDLE_CUSTOM,
469
-                    EVENT_ESPRESSO_UPLOAD_URL . 'css/' . $this->template_config->custom_style_sheet,
470
-                    array(CoreAssetManager::CSS_HANDLE_DEFAULT)
471
-                );
472
-            }
473
-        }
474
-        $this->addStylesheet(
475
-            CoreAssetManager::CSS_HANDLE_CORE_CSS_DEFAULT,
476
-            $this->registry->getCssUrl(
477
-                $this->domain->assetNamespace(),
478
-                'core-default-theme'
479
-            ),
480
-            ['dashicons']
481
-        );
482
-        $this->addStylesheet(
483
-            CoreAssetManager::CSS_HANDLE_COMPONENTS,
484
-            $this->registry->getCssUrl(
485
-                $this->domain->assetNamespace(),
486
-                'components'
487
-            ),
488
-            [CoreAssetManager::CSS_HANDLE_CORE_CSS_DEFAULT, 'wp-components']
489
-        );
490
-    }
491
-
492
-
493
-    /**
494
-     * jQuery Validate for form validation
495
-     *
496
-     * @since 4.9.62.p
497
-     * @throws DomainException
498
-     * @throws DuplicateCollectionIdentifierException
499
-     * @throws InvalidDataTypeException
500
-     * @throws InvalidEntityException
501
-     */
502
-    private function loadJqueryValidate()
503
-    {
504
-        $this->addJavascript(
505
-            CoreAssetManager::JS_HANDLE_JQUERY_VALIDATE,
506
-            EE_GLOBAL_ASSETS_URL . 'scripts/jquery.validate.min.js',
507
-            array(CoreAssetManager::JS_HANDLE_JQUERY)
508
-        )
509
-        ->setVersion('1.15.0');
510
-
511
-        $this->addJavascript(
512
-            CoreAssetManager::JS_HANDLE_JQUERY_VALIDATE_EXTRA,
513
-            EE_GLOBAL_ASSETS_URL . 'scripts/jquery.validate.additional-methods.min.js',
514
-            array(CoreAssetManager::JS_HANDLE_JQUERY_VALIDATE)
515
-        )
516
-        ->setVersion('1.15.0');
517
-    }
518
-
519
-
520
-    /**
521
-     * accounting.js for performing client-side calculations
522
-     *
523
-     * @since 4.9.62.p
524
-     * @throws DomainException
525
-     * @throws DuplicateCollectionIdentifierException
526
-     * @throws InvalidDataTypeException
527
-     * @throws InvalidEntityException
528
-     */
529
-    private function loadAccountingJs()
530
-    {
531
-        //accounting.js library
532
-        // @link http://josscrowcroft.github.io/accounting.js/
533
-        $this->addJavascript(
534
-            CoreAssetManager::JS_HANDLE_ACCOUNTING_CORE,
535
-            EE_THIRD_PARTY_URL . 'accounting/accounting.js',
536
-            array(CoreAssetManager::JS_HANDLE_UNDERSCORE)
537
-        )
538
-        ->setVersion('0.3.2');
539
-
540
-        $this->addJavascript(
541
-            CoreAssetManager::JS_HANDLE_ACCOUNTING,
542
-            EE_GLOBAL_ASSETS_URL . 'scripts/ee-accounting-config.js',
543
-            array(CoreAssetManager::JS_HANDLE_ACCOUNTING_CORE)
544
-        )
545
-        ->setInlineDataCallback(
546
-            function () {
547
-                 wp_localize_script(
548
-                     CoreAssetManager::JS_HANDLE_ACCOUNTING,
549
-                     'EE_ACCOUNTING_CFG',
550
-                     $this->getAccountingSettings()
551
-                 );
552
-            }
553
-        )
554
-        ->setVersion();
555
-    }
556
-
557
-
558
-    /**
559
-     * registers assets for cleaning your ears
560
-     *
561
-     * @param JavascriptAsset $script
562
-     */
563
-    public function loadQtipJs(JavascriptAsset $script)
564
-    {
565
-        // qtip is turned OFF by default, but prior to the wp_enqueue_scripts hook,
566
-        // can be turned back on again via: add_filter('FHEE_load_qtip', '__return_true' );
567
-        if (
568
-            $script->handle() === CoreAssetManager::JS_HANDLE_WP_PLUGINS_PAGE
569
-            && apply_filters('FHEE_load_qtip', false)
570
-        ) {
571
-            EEH_Qtip_Loader::instance()->register_and_enqueue();
572
-        }
573
-    }
574
-
575
-
576
-    /**
577
-     * assets that are used in the WordPress admin
578
-     *
579
-     * @since 4.9.62.p
580
-     * @throws DuplicateCollectionIdentifierException
581
-     * @throws InvalidDataTypeException
582
-     * @throws InvalidEntityException
583
-     */
584
-    private function registerAdminAssets()
585
-    {
586
-        $this->addJavascript(
587
-            CoreAssetManager::JS_HANDLE_WP_PLUGINS_PAGE,
588
-            $this->registry->getJsUrl($this->domain->assetNamespace(), 'wp-plugins-page'),
589
-            array(
590
-                CoreAssetManager::JS_HANDLE_JQUERY,
591
-                CoreAssetManager::JS_HANDLE_VENDOR,
592
-            )
593
-        )
594
-        ->setRequiresTranslation();
595
-
596
-        $this->addStylesheet(
597
-            CoreAssetManager::JS_HANDLE_WP_PLUGINS_PAGE,
598
-            $this->registry->getCssUrl($this->domain->assetNamespace(), 'wp-plugins-page')
599
-        );
600
-    }
90
+	const JS_HANDLE_WP_PLUGINS_PAGE = 'ee-wp-plugins-page';
91
+
92
+	// EE CSS assets handles
93
+	const CSS_HANDLE_DEFAULT = 'espresso_default';
94
+
95
+	const CSS_HANDLE_CUSTOM = 'espresso_custom_css';
96
+
97
+	const CSS_HANDLE_COMPONENTS = 'eventespresso-components';
98
+
99
+	const CSS_HANDLE_CORE_CSS_DEFAULT = 'eventespresso-core-css-default';
100
+
101
+	/**
102
+	 * @var EE_Currency_Config $currency_config
103
+	 */
104
+	protected $currency_config;
105
+
106
+	/**
107
+	 * @var EE_Template_Config $template_config
108
+	 */
109
+	protected $template_config;
110
+
111
+
112
+	/**
113
+	 * CoreAssetRegister constructor.
114
+	 *
115
+	 * @param AssetCollection    $assets
116
+	 * @param EE_Currency_Config $currency_config
117
+	 * @param EE_Template_Config $template_config
118
+	 * @param DomainInterface    $domain
119
+	 * @param Registry           $registry
120
+	 */
121
+	public function __construct(
122
+		AssetCollection $assets,
123
+		EE_Currency_Config $currency_config,
124
+		EE_Template_Config $template_config,
125
+		DomainInterface $domain,
126
+		Registry $registry
127
+	) {
128
+		$this->currency_config = $currency_config;
129
+		$this->template_config = $template_config;
130
+		parent::__construct($domain, $assets, $registry);
131
+	}
132
+
133
+
134
+	/**
135
+	 * @since 4.9.62.p
136
+	 * @throws DomainException
137
+	 * @throws DuplicateCollectionIdentifierException
138
+	 * @throws InvalidArgumentException
139
+	 * @throws InvalidDataTypeException
140
+	 * @throws InvalidEntityException
141
+	 * @throws InvalidInterfaceException
142
+	 */
143
+	public function addAssets()
144
+	{
145
+		$this->addJavascriptFiles();
146
+		$this->addStylesheetFiles();
147
+	}
148
+
149
+
150
+	/**
151
+	 * @since 4.9.62.p
152
+	 * @throws DomainException
153
+	 * @throws DuplicateCollectionIdentifierException
154
+	 * @throws InvalidArgumentException
155
+	 * @throws InvalidDataTypeException
156
+	 * @throws InvalidEntityException
157
+	 * @throws InvalidInterfaceException
158
+	 */
159
+	public function addJavascriptFiles()
160
+	{
161
+		$this->loadCoreJs();
162
+		$this->loadJqueryValidate();
163
+		$this->loadAccountingJs();
164
+		add_action(
165
+			'AHEE__EventEspresso_core_services_assets_Registry__registerScripts__before_script',
166
+			array($this, 'loadQtipJs')
167
+		);
168
+		$this->registerAdminAssets();
169
+	}
170
+
171
+
172
+	/**
173
+	 * @since 4.9.62.p
174
+	 * @throws DuplicateCollectionIdentifierException
175
+	 * @throws InvalidDataTypeException
176
+	 * @throws InvalidEntityException
177
+	 */
178
+	public function addStylesheetFiles()
179
+	{
180
+		$this->loadCoreCss();
181
+	}
182
+
183
+
184
+	/**
185
+	 * core default javascript
186
+	 *
187
+	 * @since 4.9.62.p
188
+	 * @throws DomainException
189
+	 * @throws DuplicateCollectionIdentifierException
190
+	 * @throws InvalidArgumentException
191
+	 * @throws InvalidDataTypeException
192
+	 * @throws InvalidEntityException
193
+	 * @throws InvalidInterfaceException
194
+	 */
195
+	private function loadCoreJs()
196
+	{
197
+		// conditionally load third-party libraries that WP core MIGHT have.
198
+		$this->registerWpAssets();
199
+
200
+		$this->addJavascript(
201
+			CoreAssetManager::JS_HANDLE_MANIFEST,
202
+			$this->registry->getJsUrl($this->domain->assetNamespace(), 'manifest')
203
+		);
204
+
205
+		$this->addJavascript(
206
+			CoreAssetManager::JS_HANDLE_JS_CORE,
207
+			$this->registry->getJsUrl($this->domain->assetNamespace(), 'eejs'),
208
+			array(CoreAssetManager::JS_HANDLE_MANIFEST)
209
+		)
210
+		->setHasInlineData();
211
+
212
+		$this->addJavascript(
213
+			CoreAssetManager::JS_HANDLE_VENDOR,
214
+			$this->registry->getJsUrl($this->domain->assetNamespace(), 'vendor'),
215
+			array(
216
+				CoreAssetManager::JS_HANDLE_JS_CORE,
217
+				CoreAssetManager::JS_HANDLE_REACT,
218
+				CoreAssetManager::JS_HANDLE_REACT_DOM,
219
+				CoreAssetManager::JS_HANDLE_LODASH,
220
+			)
221
+		);
222
+
223
+		$this->addJavascript(
224
+			CoreAssetManager::JS_HANDLE_VALIDATORS,
225
+			$this->registry->getJsUrl($this->domain->assetNamespace(), 'validators')
226
+		)->setRequiresTranslation();
227
+
228
+		$this->addJavascript(
229
+			CoreAssetManager::JS_HANDLE_HELPERS,
230
+			$this->registry->getJsUrl($this->domain->assetNamespace(), 'helpers'),
231
+			array(
232
+				CoreAssetManager::JS_HANDLE_VALIDATORS
233
+			)
234
+		)->setRequiresTranslation();
235
+
236
+		$this->addJavascript(
237
+			CoreAssetManager::JS_HANDLE_MODEL,
238
+			$this->registry->getJsUrl($this->domain->assetNamespace(), 'model'),
239
+			array(
240
+				CoreAssetManager::JS_HANDLE_HELPERS,
241
+				CoreAssetManager::JS_HANDLE_VALUE_OBJECTS,
242
+			)
243
+		)->setRequiresTranslation();
244
+
245
+		$this->addJavascript(
246
+			CoreAssetManager::JS_HANDLE_VALUE_OBJECTS,
247
+			$this->registry->getJsUrl($this->domain->assetNamespace(), 'valueObjects'),
248
+			array(
249
+				CoreAssetManager::JS_HANDLE_VALIDATORS,
250
+				CoreAssetManager::JS_HANDLE_HELPERS,
251
+			)
252
+		)->setRequiresTranslation();
253
+
254
+		$this->addJavascript(
255
+			CoreAssetManager::JS_HANDLE_DATA_STORES,
256
+			$this->registry->getJsUrl($this->domain->assetNamespace(), 'data-stores'),
257
+			array(
258
+				CoreAssetManager::JS_HANDLE_VENDOR,
259
+				'wp-data',
260
+				'wp-api-fetch',
261
+				CoreAssetManager::JS_HANDLE_VALUE_OBJECTS,
262
+				CoreAssetManager::JS_HANDLE_MODEL,
263
+			)
264
+		)
265
+			 ->setRequiresTranslation()
266
+			 ->setInlineDataCallback(
267
+				 function() {
268
+					 wp_add_inline_script(
269
+						 CoreAssetManager::JS_HANDLE_DATA_STORES,
270
+						 is_admin()
271
+							 ? 'wp.apiFetch.use( eejs.middleWares.apiFetch.capsMiddleware( eejs.middleWares.apiFetch.CONTEXT_CAPS_EDIT ) )'
272
+							 : 'wp.apiFetch.use( eejs.middleWares.apiFetch.capsMiddleware )'
273
+					 );
274
+				 }
275
+			 );
276
+
277
+		$this->addJavascript(
278
+			CoreAssetManager::JS_HANDLE_HOCS,
279
+			$this->registry->getJsUrl($this->domain->assetNamespace(), 'hocs'),
280
+			array(
281
+				CoreAssetManager::JS_HANDLE_DATA_STORES,
282
+				CoreAssetManager::JS_HANDLE_VALUE_OBJECTS,
283
+				'wp-components',
284
+			)
285
+		)->setRequiresTranslation();
286
+
287
+		$this->addJavascript(
288
+			CoreAssetManager::JS_HANDLE_COMPONENTS,
289
+			$this->registry->getJsUrl($this->domain->assetNamespace(), 'components'),
290
+			array(
291
+				CoreAssetManager::JS_HANDLE_DATA_STORES,
292
+				CoreAssetManager::JS_HANDLE_VALUE_OBJECTS,
293
+				'wp-components',
294
+			)
295
+		)
296
+		->setRequiresTranslation();
297
+
298
+		$this->addJavascript(
299
+			CoreAssetManager::JS_HANDLE_EDITOR_HOCS,
300
+			$this->registry->getJsUrl($this->domain->assetNamespace(), 'editor-hocs'),
301
+			array(
302
+				CoreAssetManager::JS_HANDLE_COMPONENTS
303
+			)
304
+		)->setRequiresTranslation();
305
+
306
+		$this->registry->addData('eejs_api_nonce', wp_create_nonce('wp_rest'));
307
+		$this->registry->addData(
308
+			'paths',
309
+			array(
310
+				'base_rest_route' => rest_url(),
311
+				'rest_route' => rest_url('ee/v4.8.36/'),
312
+				'collection_endpoints' => EED_Core_Rest_Api::getCollectionRoutesIndexedByModelName(),
313
+				'primary_keys' => EED_Core_Rest_Api::getPrimaryKeyNamesIndexedByModelName(),
314
+				'site_url' => site_url('/'),
315
+				'admin_url' => admin_url('/'),
316
+			)
317
+		);
318
+		// Event Espresso brand name
319
+		$this->registry->addData('brandName', Domain::brandName());
320
+		/** site formatting values **/
321
+		$this->registry->addData(
322
+			'site_formats',
323
+			array(
324
+				'date_formats' => EEH_DTT_Helper::convert_php_to_js_and_moment_date_formats()
325
+			)
326
+		);
327
+		/** currency data **/
328
+		$this->registry->addData(
329
+			'currency_config',
330
+			$this->getCurrencySettings()
331
+		);
332
+		/** site timezone */
333
+		$this->registry->addData(
334
+			'default_timezone',
335
+			array(
336
+				'pretty' => EEH_DTT_Helper::get_timezone_string_for_display(),
337
+				'string' => get_option('timezone_string'),
338
+				'offset' => EEH_DTT_Helper::get_site_timezone_gmt_offset(),
339
+			)
340
+		);
341
+		/** site locale (user locale if user logged in) */
342
+		$this->registry->addData(
343
+			'locale',
344
+			array(
345
+				'user' => get_user_locale(),
346
+				'site' => get_locale()
347
+			)
348
+		);
349
+
350
+		$this->addJavascript(
351
+			CoreAssetManager::JS_HANDLE_CORE,
352
+			EE_GLOBAL_ASSETS_URL . 'scripts/espresso_core.js',
353
+			array(CoreAssetManager::JS_HANDLE_JQUERY)
354
+		)
355
+		->setInlineDataCallback(
356
+			function () {
357
+				wp_localize_script(
358
+					CoreAssetManager::JS_HANDLE_CORE,
359
+					CoreAssetManager::JS_HANDLE_I18N,
360
+					EE_Registry::$i18n_js_strings
361
+				);
362
+			}
363
+		);
364
+	}
365
+
366
+
367
+	/**
368
+	 * Registers vendor files that are bundled with a later version WP but might not be for the current version of
369
+	 * WordPress in the running environment.
370
+	 *
371
+	 * @throws DuplicateCollectionIdentifierException
372
+	 * @throws InvalidDataTypeException
373
+	 * @throws InvalidEntityException
374
+	 * @throws DomainException
375
+	 * @since 4.9.71.p
376
+	 */
377
+	private function registerWpAssets()
378
+	{
379
+		global $wp_version;
380
+		if (version_compare($wp_version, '5.0.beta', '>=')) {
381
+			return;
382
+		}
383
+		$this->addVendorJavascript(CoreAssetManager::JS_HANDLE_REACT)
384
+			->setVersion('16.6.0');
385
+		$this->addVendorJavascript(
386
+			CoreAssetManager::JS_HANDLE_REACT_DOM,
387
+			array(CoreAssetManager::JS_HANDLE_REACT)
388
+		)->setVersion('16.6.0');
389
+		$this->addVendorJavascript(CoreAssetManager::JS_HANDLE_LODASH)
390
+			->setInlineDataCallback(
391
+				function() {
392
+					wp_add_inline_script(
393
+						CoreAssetManager::JS_HANDLE_LODASH,
394
+						'window.lodash = _.noConflict();'
395
+					);
396
+				}
397
+			)
398
+			->setVersion('4.17.11');
399
+	}
400
+
401
+
402
+	/**
403
+	 * Returns configuration data for the accounting-js library.
404
+	 * @since 4.9.71.p
405
+	 * @return array
406
+	 */
407
+	private function getAccountingSettings() {
408
+		return array(
409
+			'currency' => array(
410
+				'symbol'    => $this->currency_config->sign,
411
+				'format'    => array(
412
+					'pos'  => $this->currency_config->sign_b4 ? '%s%v' : '%v%s',
413
+					'neg'  => $this->currency_config->sign_b4 ? '- %s%v' : '- %v%s',
414
+					'zero' => $this->currency_config->sign_b4 ? '%s--' : '--%s',
415
+				),
416
+				'decimal'   => $this->currency_config->dec_mrk,
417
+				'thousand'  => $this->currency_config->thsnds,
418
+				'precision' => $this->currency_config->dec_plc,
419
+			),
420
+			'number'   => array(
421
+				'precision' => $this->currency_config->dec_plc,
422
+				'thousand'  => $this->currency_config->thsnds,
423
+				'decimal'   => $this->currency_config->dec_mrk,
424
+			),
425
+		);
426
+	}
427
+
428
+
429
+	/**
430
+	 * Returns configuration data for the js Currency VO.
431
+	 * @since 4.9.71.p
432
+	 * @return array
433
+	 */
434
+	private function getCurrencySettings()
435
+	{
436
+		return array(
437
+			'code' => $this->currency_config->code,
438
+			'singularLabel' => $this->currency_config->name,
439
+			'pluralLabel' => $this->currency_config->plural,
440
+			'sign' => $this->currency_config->sign,
441
+			'signB4' => $this->currency_config->sign_b4,
442
+			'decimalPlaces' => $this->currency_config->dec_plc,
443
+			'decimalMark' => $this->currency_config->dec_mrk,
444
+			'thousandsSeparator' => $this->currency_config->thsnds,
445
+		);
446
+	}
447
+
448
+
449
+	/**
450
+	 * @since 4.9.62.p
451
+	 * @throws DuplicateCollectionIdentifierException
452
+	 * @throws InvalidDataTypeException
453
+	 * @throws InvalidEntityException
454
+	 */
455
+	private function loadCoreCss()
456
+	{
457
+		if ($this->template_config->enable_default_style && ! is_admin()) {
458
+			$this->addStylesheet(
459
+				CoreAssetManager::CSS_HANDLE_DEFAULT,
460
+				is_readable(EVENT_ESPRESSO_UPLOAD_DIR . 'css/style.css')
461
+					? EVENT_ESPRESSO_UPLOAD_DIR . 'css/espresso_default.css'
462
+					: EE_GLOBAL_ASSETS_URL . 'css/espresso_default.css',
463
+				array('dashicons')
464
+			);
465
+			//Load custom style sheet if available
466
+			if ($this->template_config->custom_style_sheet !== null) {
467
+				$this->addStylesheet(
468
+					CoreAssetManager::CSS_HANDLE_CUSTOM,
469
+					EVENT_ESPRESSO_UPLOAD_URL . 'css/' . $this->template_config->custom_style_sheet,
470
+					array(CoreAssetManager::CSS_HANDLE_DEFAULT)
471
+				);
472
+			}
473
+		}
474
+		$this->addStylesheet(
475
+			CoreAssetManager::CSS_HANDLE_CORE_CSS_DEFAULT,
476
+			$this->registry->getCssUrl(
477
+				$this->domain->assetNamespace(),
478
+				'core-default-theme'
479
+			),
480
+			['dashicons']
481
+		);
482
+		$this->addStylesheet(
483
+			CoreAssetManager::CSS_HANDLE_COMPONENTS,
484
+			$this->registry->getCssUrl(
485
+				$this->domain->assetNamespace(),
486
+				'components'
487
+			),
488
+			[CoreAssetManager::CSS_HANDLE_CORE_CSS_DEFAULT, 'wp-components']
489
+		);
490
+	}
491
+
492
+
493
+	/**
494
+	 * jQuery Validate for form validation
495
+	 *
496
+	 * @since 4.9.62.p
497
+	 * @throws DomainException
498
+	 * @throws DuplicateCollectionIdentifierException
499
+	 * @throws InvalidDataTypeException
500
+	 * @throws InvalidEntityException
501
+	 */
502
+	private function loadJqueryValidate()
503
+	{
504
+		$this->addJavascript(
505
+			CoreAssetManager::JS_HANDLE_JQUERY_VALIDATE,
506
+			EE_GLOBAL_ASSETS_URL . 'scripts/jquery.validate.min.js',
507
+			array(CoreAssetManager::JS_HANDLE_JQUERY)
508
+		)
509
+		->setVersion('1.15.0');
510
+
511
+		$this->addJavascript(
512
+			CoreAssetManager::JS_HANDLE_JQUERY_VALIDATE_EXTRA,
513
+			EE_GLOBAL_ASSETS_URL . 'scripts/jquery.validate.additional-methods.min.js',
514
+			array(CoreAssetManager::JS_HANDLE_JQUERY_VALIDATE)
515
+		)
516
+		->setVersion('1.15.0');
517
+	}
518
+
519
+
520
+	/**
521
+	 * accounting.js for performing client-side calculations
522
+	 *
523
+	 * @since 4.9.62.p
524
+	 * @throws DomainException
525
+	 * @throws DuplicateCollectionIdentifierException
526
+	 * @throws InvalidDataTypeException
527
+	 * @throws InvalidEntityException
528
+	 */
529
+	private function loadAccountingJs()
530
+	{
531
+		//accounting.js library
532
+		// @link http://josscrowcroft.github.io/accounting.js/
533
+		$this->addJavascript(
534
+			CoreAssetManager::JS_HANDLE_ACCOUNTING_CORE,
535
+			EE_THIRD_PARTY_URL . 'accounting/accounting.js',
536
+			array(CoreAssetManager::JS_HANDLE_UNDERSCORE)
537
+		)
538
+		->setVersion('0.3.2');
539
+
540
+		$this->addJavascript(
541
+			CoreAssetManager::JS_HANDLE_ACCOUNTING,
542
+			EE_GLOBAL_ASSETS_URL . 'scripts/ee-accounting-config.js',
543
+			array(CoreAssetManager::JS_HANDLE_ACCOUNTING_CORE)
544
+		)
545
+		->setInlineDataCallback(
546
+			function () {
547
+				 wp_localize_script(
548
+					 CoreAssetManager::JS_HANDLE_ACCOUNTING,
549
+					 'EE_ACCOUNTING_CFG',
550
+					 $this->getAccountingSettings()
551
+				 );
552
+			}
553
+		)
554
+		->setVersion();
555
+	}
556
+
557
+
558
+	/**
559
+	 * registers assets for cleaning your ears
560
+	 *
561
+	 * @param JavascriptAsset $script
562
+	 */
563
+	public function loadQtipJs(JavascriptAsset $script)
564
+	{
565
+		// qtip is turned OFF by default, but prior to the wp_enqueue_scripts hook,
566
+		// can be turned back on again via: add_filter('FHEE_load_qtip', '__return_true' );
567
+		if (
568
+			$script->handle() === CoreAssetManager::JS_HANDLE_WP_PLUGINS_PAGE
569
+			&& apply_filters('FHEE_load_qtip', false)
570
+		) {
571
+			EEH_Qtip_Loader::instance()->register_and_enqueue();
572
+		}
573
+	}
574
+
575
+
576
+	/**
577
+	 * assets that are used in the WordPress admin
578
+	 *
579
+	 * @since 4.9.62.p
580
+	 * @throws DuplicateCollectionIdentifierException
581
+	 * @throws InvalidDataTypeException
582
+	 * @throws InvalidEntityException
583
+	 */
584
+	private function registerAdminAssets()
585
+	{
586
+		$this->addJavascript(
587
+			CoreAssetManager::JS_HANDLE_WP_PLUGINS_PAGE,
588
+			$this->registry->getJsUrl($this->domain->assetNamespace(), 'wp-plugins-page'),
589
+			array(
590
+				CoreAssetManager::JS_HANDLE_JQUERY,
591
+				CoreAssetManager::JS_HANDLE_VENDOR,
592
+			)
593
+		)
594
+		->setRequiresTranslation();
595
+
596
+		$this->addStylesheet(
597
+			CoreAssetManager::JS_HANDLE_WP_PLUGINS_PAGE,
598
+			$this->registry->getCssUrl($this->domain->assetNamespace(), 'wp-plugins-page')
599
+		);
600
+	}
601 601
 }
Please login to merge, or discard this patch.