Completed
Branch rest-authorization (c7240a)
by
unknown
02:23
created
core/admin/templates/espresso_ratings_request_content.template.php 1 patch
Indentation   +8 added lines, -8 removed lines patch added patch discarded remove patch
@@ -1,9 +1,9 @@  discard block
 block discarded – undo
1 1
 <div class="padding">
2 2
     <p><?php
3
-        esc_html_e(
4
-            'We need your help to continue maintaining and providing this plugin for free. You can help by leaving a positive review in the WordPress plugin directory. 5 star ratings bring Event Espresso Decaf to the attention of more users which increases our support and features for this version of Event Espresso.',
5
-            'event_espresso'
6
-        ); ?></p>
3
+		esc_html_e(
4
+			'We need your help to continue maintaining and providing this plugin for free. You can help by leaving a positive review in the WordPress plugin directory. 5 star ratings bring Event Espresso Decaf to the attention of more users which increases our support and features for this version of Event Espresso.',
5
+			'event_espresso'
6
+		); ?></p>
7 7
     <p><?php esc_html_e('Rate it five stars today!', 'event_espresso'); ?></p><span
8 8
         class="ee-wp-blue dashicons dashicons-star-filled"></span><span
9 9
         class="ee-wp-blue dashicons dashicons-star-filled"></span><span
@@ -12,8 +12,8 @@  discard block
 block discarded – undo
12 12
         class="ee-wp-blue dashicons dashicons-star-filled"></span>
13 13
     <p><a class="button button-primary"
14 14
           href="https://login.wordpress.org/?redirect_to=https%3A%2F%2Fwordpress.org%2Fsupport%2Fview%2Fplugin-reviews%2Fevent-espresso-decaf%3Frate%3D5%23postform"><?php
15
-            esc_html_e(
16
-                'Rate It!',
17
-                'event_espresso'
18
-            ); ?></a></p>
15
+			esc_html_e(
16
+				'Rate It!',
17
+				'event_espresso'
18
+			); ?></a></p>
19 19
 </div>
20 20
\ No newline at end of file
Please login to merge, or discard this patch.
templates/admin_general_metabox_contents_espresso_sponsors.template.php 1 patch
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -11,7 +11,7 @@
 block discarded – undo
11 11
     <a href="https://eventespresso.com/?ee_ver=ee4&utm_source=ee4_plugin_admin&utm_medium=link&utm_campaign=event_espresso_highlights_widget&utm_content=banner"
12 12
        target="_blank"
13 13
     >
14
-        <img src="<?php echo esc_url_raw(EE_GLOBAL_ASSETS_URL . 'images/manage-events-faster-240x240.jpg'); ?>" />
14
+        <img src="<?php echo esc_url_raw(EE_GLOBAL_ASSETS_URL.'images/manage-events-faster-240x240.jpg'); ?>" />
15 15
     </a>
16 16
     <p>Visit
17 17
         <a href="https://eventespresso.com/?ee_ver=ee4&utm_source=ee4_plugin_admin&utm_medium=link&utm_campaign
Please login to merge, or discard this patch.
core/admin/EE_Admin.core.php 2 patches
Spacing   +29 added lines, -29 removed lines patch added patch discarded remove patch
@@ -51,7 +51,7 @@  discard block
 block discarded – undo
51 51
     public static function instance(RequestInterface $request = null)
52 52
     {
53 53
         // check if class object is instantiated
54
-        if (! self::$_instance instanceof EE_Admin) {
54
+        if ( ! self::$_instance instanceof EE_Admin) {
55 55
             self::$_instance = new self($request);
56 56
         }
57 57
         return self::$_instance;
@@ -113,11 +113,11 @@  discard block
 block discarded – undo
113 113
      */
114 114
     private function _define_all_constants()
115 115
     {
116
-        if (! defined('EE_ADMIN_URL')) {
117
-            define('EE_ADMIN_URL', EE_PLUGIN_DIR_URL . 'core/admin/');
118
-            define('EE_ADMIN_PAGES_URL', EE_PLUGIN_DIR_URL . 'admin_pages/');
119
-            define('EE_ADMIN_TEMPLATE', EE_ADMIN . 'templates/');
120
-            define('WP_ADMIN_PATH', ABSPATH . 'wp-admin/');
116
+        if ( ! defined('EE_ADMIN_URL')) {
117
+            define('EE_ADMIN_URL', EE_PLUGIN_DIR_URL.'core/admin/');
118
+            define('EE_ADMIN_PAGES_URL', EE_PLUGIN_DIR_URL.'admin_pages/');
119
+            define('EE_ADMIN_TEMPLATE', EE_ADMIN.'templates/');
120
+            define('WP_ADMIN_PATH', ABSPATH.'wp-admin/');
121 121
             define('WP_AJAX_URL', admin_url('admin-ajax.php'));
122 122
         }
123 123
     }
@@ -135,7 +135,7 @@  discard block
 block discarded – undo
135 135
         // set $main_file in stone
136 136
         static $main_file;
137 137
         // if $main_file is not set yet
138
-        if (! $main_file) {
138
+        if ( ! $main_file) {
139 139
             $main_file = EE_PLUGIN_BASENAME;
140 140
         }
141 141
         if ($plugin === $main_file) {
@@ -178,9 +178,9 @@  discard block
 block discarded – undo
178 178
     public function hide_admin_pages_except_maintenance_mode($admin_page_folder_names = [])
179 179
     {
180 180
         return [
181
-            'maintenance' => EE_ADMIN_PAGES . 'maintenance/',
182
-            'about'       => EE_ADMIN_PAGES . 'about/',
183
-            'support'     => EE_ADMIN_PAGES . 'support/',
181
+            'maintenance' => EE_ADMIN_PAGES.'maintenance/',
182
+            'about'       => EE_ADMIN_PAGES.'about/',
183
+            'support'     => EE_ADMIN_PAGES.'support/',
184 184
         ];
185 185
     }
186 186
 
@@ -299,13 +299,13 @@  discard block
 block discarded – undo
299 299
                     '</strong>',
300 300
                     '<a href="https://eventespresso.com/2017/08/important-upcoming-changes-dates-times">',
301 301
                     '</a>',
302
-                    '<a href="' . EE_Admin_Page::add_query_args_and_nonce(
302
+                    '<a href="'.EE_Admin_Page::add_query_args_and_nonce(
303 303
                         [
304 304
                             'page'   => 'espresso_maintenance_settings',
305 305
                             'action' => 'datetime_tools',
306 306
                         ],
307 307
                         admin_url('admin.php')
308
-                    ) . '">'
308
+                    ).'">'
309 309
                 ),
310 310
                 false,
311 311
                 'manage_options',
@@ -351,7 +351,7 @@  discard block
 block discarded – undo
351 351
     public function enable_hidden_ee_nav_menu_metaboxes()
352 352
     {
353 353
         global $wp_meta_boxes, $pagenow;
354
-        if (! is_array($wp_meta_boxes) || $pagenow !== 'nav-menus.php') {
354
+        if ( ! is_array($wp_meta_boxes) || $pagenow !== 'nav-menus.php') {
355 355
             return;
356 356
         }
357 357
         $user = wp_get_current_user();
@@ -380,7 +380,7 @@  discard block
 block discarded – undo
380 380
         if (is_array($hidden_meta_boxes)) {
381 381
             foreach ($hidden_meta_boxes as $key => $meta_box_id) {
382 382
                 if (in_array($meta_box_id, $initial_meta_boxes, true)) {
383
-                    unset($hidden_meta_boxes[ $key ]);
383
+                    unset($hidden_meta_boxes[$key]);
384 384
                 }
385 385
             }
386 386
         }
@@ -420,7 +420,7 @@  discard block
 block discarded – undo
420 420
      */
421 421
     public function modify_edit_post_link($link, $id)
422 422
     {
423
-        if (! $post = get_post($id)) {
423
+        if ( ! $post = get_post($id)) {
424 424
             return $link;
425 425
         }
426 426
         if ($post->post_type === 'espresso_attendees') {
@@ -479,7 +479,7 @@  discard block
 block discarded – undo
479 479
         );
480 480
 
481 481
         EEH_Template::display_template(
482
-            EE_ADMIN_TEMPLATE . 'cpt_archive_page.template.php',
482
+            EE_ADMIN_TEMPLATE.'cpt_archive_page.template.php',
483 483
             [
484 484
                 $nav_menu_pages_items,
485 485
                 $nav_tab_link,
@@ -537,7 +537,7 @@  discard block
 block discarded – undo
537 537
         ];
538 538
 
539 539
         foreach ($keys as $key => $value) {
540
-            $menu_item->{$key} = isset($menu_item_values[ $key ]) ? $menu_item_values[ $key ] : $value;
540
+            $menu_item->{$key} = isset($menu_item_values[$key]) ? $menu_item_values[$key] : $value;
541 541
         }
542 542
         return $menu_item;
543 543
     }
@@ -633,10 +633,10 @@  discard block
 block discarded – undo
633 633
 
634 634
         // loop through to remove any critical pages from the array.
635 635
         foreach ($critical_pages as $page_id) {
636
-            $needle = 'value="' . $page_id . '"';
636
+            $needle = 'value="'.$page_id.'"';
637 637
             foreach ($split_output as $key => $haystack) {
638 638
                 if (strpos($haystack, $needle) !== false) {
639
-                    unset($split_output[ $key ]);
639
+                    unset($split_output[$key]);
640 640
                 }
641 641
             }
642 642
         }
@@ -657,7 +657,7 @@  discard block
 block discarded – undo
657 657
         // calls.
658 658
         wp_enqueue_script(
659 659
             'ee-inject-wp',
660
-            EE_ADMIN_URL . 'assets/ee-cpt-wp-injects.js',
660
+            EE_ADMIN_URL.'assets/ee-cpt-wp-injects.js',
661 661
             ['jquery'],
662 662
             EVENT_ESPRESSO_VERSION,
663 663
             true
@@ -665,7 +665,7 @@  discard block
 block discarded – undo
665 665
         // register cookie script for future dependencies
666 666
         wp_register_script(
667 667
             'jquery-cookie',
668
-            EE_THIRD_PARTY_URL . 'joyride/jquery.cookie.js',
668
+            EE_THIRD_PARTY_URL.'joyride/jquery.cookie.js',
669 669
             ['jquery'],
670 670
             '2.1',
671 671
             true
@@ -731,7 +731,7 @@  discard block
 block discarded – undo
731 731
             ['page' => 'espresso_events'],
732 732
             admin_url('admin.php')
733 733
         );
734
-        $items['events']['text']         = sprintf(
734
+        $items['events']['text'] = sprintf(
735 735
             esc_html(
736 736
                 _n('%s Event', '%s Events', $events, 'event_espresso')
737 737
             ),
@@ -745,11 +745,11 @@  discard block
 block discarded – undo
745 745
                 ],
746 746
             ]
747 747
         );
748
-        $items['registrations']['url']   = EE_Admin_Page::add_query_args_and_nonce(
748
+        $items['registrations']['url'] = EE_Admin_Page::add_query_args_and_nonce(
749 749
             ['page' => 'espresso_registrations'],
750 750
             admin_url('admin.php')
751 751
         );
752
-        $items['registrations']['text']  = sprintf(
752
+        $items['registrations']['text'] = sprintf(
753 753
             esc_html(
754 754
                 _n('%s Registration', '%s Registrations', $registrations, 'event_espresso')
755 755
             ),
@@ -761,7 +761,7 @@  discard block
 block discarded – undo
761 761
 
762 762
         foreach ($items as $type => $item_properties) {
763 763
             $elements[] = sprintf(
764
-                '<a class="ee-dashboard-link-' . $type . '" href="%s" title="%s">%s</a>',
764
+                '<a class="ee-dashboard-link-'.$type.'" href="%s" title="%s">%s</a>',
765 765
                 $item_properties['url'],
766 766
                 $item_properties['title'],
767 767
                 $item_properties['text']
@@ -785,10 +785,10 @@  discard block
 block discarded – undo
785 785
         // check for date_format or time_format
786 786
         switch ($option) {
787 787
             case 'date_format':
788
-                $date_time_format = $value . ' ' . get_option('time_format');
788
+                $date_time_format = $value.' '.get_option('time_format');
789 789
                 break;
790 790
             case 'time_format':
791
-                $date_time_format = get_option('date_format') . ' ' . $value;
791
+                $date_time_format = get_option('date_format').' '.$value;
792 792
                 break;
793 793
             default:
794 794
                 $date_time_format = false;
@@ -811,7 +811,7 @@  discard block
 block discarded – undo
811 811
 
812 812
 
813 813
                 foreach ($error_msg as $error) {
814
-                    $msg .= '<li>' . $error . '</li>';
814
+                    $msg .= '<li>'.$error.'</li>';
815 815
                 }
816 816
 
817 817
                 $msg .= '</ul></p><p>'
@@ -1002,7 +1002,7 @@  discard block
 block discarded – undo
1002 1002
     public function displayStateForCriticalPages($post_states, $post)
1003 1003
     {
1004 1004
         $post_states = (array) $post_states;
1005
-        if (! $post instanceof WP_Post || $post->post_type !== 'page') {
1005
+        if ( ! $post instanceof WP_Post || $post->post_type !== 'page') {
1006 1006
             return $post_states;
1007 1007
         }
1008 1008
         /** @var EE_Core_Config $config */
Please login to merge, or discard this patch.
Indentation   +994 added lines, -994 removed lines patch added patch discarded remove patch
@@ -20,998 +20,998 @@
 block discarded – undo
20 20
  */
21 21
 final class EE_Admin implements InterminableInterface
22 22
 {
23
-    /**
24
-     * @var EE_Admin $_instance
25
-     */
26
-    private static $_instance;
27
-
28
-    /**
29
-     * @var PersistentAdminNoticeManager $persistent_admin_notice_manager
30
-     */
31
-    private $persistent_admin_notice_manager;
32
-
33
-    /**
34
-     * @var LoaderInterface
35
-     */
36
-    protected $loader;
37
-
38
-    /**
39
-     * @var RequestInterface
40
-     */
41
-    protected $request;
42
-
43
-
44
-    /**
45
-     * @param RequestInterface $request
46
-     * @singleton method used to instantiate class object
47
-     * @return EE_Admin
48
-     * @throws EE_Error
49
-     */
50
-    public static function instance(RequestInterface $request = null)
51
-    {
52
-        // check if class object is instantiated
53
-        if (! self::$_instance instanceof EE_Admin) {
54
-            self::$_instance = new self($request);
55
-        }
56
-        return self::$_instance;
57
-    }
58
-
59
-
60
-    /**
61
-     * @return EE_Admin
62
-     * @throws EE_Error
63
-     */
64
-    public static function reset()
65
-    {
66
-        self::$_instance = null;
67
-        $request         = LoaderFactory::getLoader()->getShared(RequestInterface::class);
68
-        return self::instance($request);
69
-    }
70
-
71
-
72
-    /**
73
-     * @param RequestInterface $request
74
-     * @throws EE_Error
75
-     * @throws InvalidDataTypeException
76
-     * @throws InvalidInterfaceException
77
-     * @throws InvalidArgumentException
78
-     */
79
-    protected function __construct(RequestInterface $request)
80
-    {
81
-        $this->request = $request;
82
-        $this->loader = LoaderFactory::getLoader();
83
-        // define global EE_Admin constants
84
-        $this->_define_all_constants();
85
-        // set autoloaders for our admin page classes based on included path information
86
-        EEH_Autoloader::instance()->register_autoloaders_for_each_file_in_folder(EE_ADMIN);
87
-        // admin hooks
88
-        add_filter('plugin_action_links', [$this, 'filter_plugin_actions'], 10, 2);
89
-        add_action('AHEE__EE_System__initialize_last', [$this, 'init']);
90
-        add_action('AHEE__EE_Admin_Page__route_admin_request', [$this, 'route_admin_request'], 100, 2);
91
-        add_action('wp_loaded', [$this, 'wp_loaded'], 100);
92
-        add_action('admin_init', [$this, 'admin_init'], 100);
93
-        add_action('admin_enqueue_scripts', [$this, 'enqueue_admin_scripts'], 20);
94
-        add_action('admin_notices', [$this, 'display_admin_notices'], 10);
95
-        add_action('network_admin_notices', [$this, 'display_admin_notices'], 10);
96
-        add_filter('pre_update_option', [$this, 'check_for_invalid_datetime_formats'], 100, 2);
97
-        add_filter('admin_footer_text', [$this, 'espresso_admin_footer']);
98
-        add_action('load-plugins.php', [$this, 'hookIntoWpPluginsPage']);
99
-        add_action('display_post_states', [$this, 'displayStateForCriticalPages'], 10, 2);
100
-        add_filter('plugin_row_meta', [$this, 'addLinksToPluginRowMeta'], 10, 2);
101
-        // reset Environment config (we only do this on admin page loads);
102
-        EE_Registry::instance()->CFG->environment->recheck_values();
103
-        do_action('AHEE__EE_Admin__loaded');
104
-    }
105
-
106
-
107
-    /**
108
-     * _define_all_constants
109
-     * define constants that are set globally for all admin pages
110
-     *
111
-     * @return void
112
-     */
113
-    private function _define_all_constants()
114
-    {
115
-        if (! defined('EE_ADMIN_URL')) {
116
-            define('EE_ADMIN_URL', EE_PLUGIN_DIR_URL . 'core/admin/');
117
-            define('EE_ADMIN_PAGES_URL', EE_PLUGIN_DIR_URL . 'admin_pages/');
118
-            define('EE_ADMIN_TEMPLATE', EE_ADMIN . 'templates/');
119
-            define('WP_ADMIN_PATH', ABSPATH . 'wp-admin/');
120
-            define('WP_AJAX_URL', admin_url('admin-ajax.php'));
121
-        }
122
-    }
123
-
124
-
125
-    /**
126
-     * filter_plugin_actions - adds links to the Plugins page listing
127
-     *
128
-     * @param array  $links
129
-     * @param string $plugin
130
-     * @return    array
131
-     */
132
-    public function filter_plugin_actions($links, $plugin)
133
-    {
134
-        // set $main_file in stone
135
-        static $main_file;
136
-        // if $main_file is not set yet
137
-        if (! $main_file) {
138
-            $main_file = EE_PLUGIN_BASENAME;
139
-        }
140
-        if ($plugin === $main_file) {
141
-            // compare current plugin to this one
142
-            if (EE_Maintenance_Mode::instance()->level() === EE_Maintenance_Mode::level_2_complete_maintenance) {
143
-                $maintenance_link = '<a href="admin.php?page=espresso_maintenance_settings"'
144
-                                    . ' title="Event Espresso is in maintenance mode.  Click this link to learn why.">'
145
-                                    . esc_html__('Maintenance Mode Active', 'event_espresso')
146
-                                    . '</a>';
147
-                array_unshift($links, $maintenance_link);
148
-            } else {
149
-                $org_settings_link = '<a href="admin.php?page=espresso_general_settings">'
150
-                                     . esc_html__('Settings', 'event_espresso')
151
-                                     . '</a>';
152
-                $events_link       = '<a href="admin.php?page=espresso_events">'
153
-                                     . esc_html__('Events', 'event_espresso')
154
-                                     . '</a>';
155
-                // add before other links
156
-                array_unshift($links, $org_settings_link, $events_link);
157
-            }
158
-        }
159
-        return $links;
160
-    }
161
-
162
-
163
-    /**
164
-     * @deprecated 4.10.14.p
165
-     */
166
-    public function get_request()
167
-    {
168
-    }
169
-
170
-
171
-    /**
172
-     * hide_admin_pages_except_maintenance_mode
173
-     *
174
-     * @param array $admin_page_folder_names
175
-     * @return array
176
-     */
177
-    public function hide_admin_pages_except_maintenance_mode($admin_page_folder_names = [])
178
-    {
179
-        return [
180
-            'maintenance' => EE_ADMIN_PAGES . 'maintenance/',
181
-            'about'       => EE_ADMIN_PAGES . 'about/',
182
-            'support'     => EE_ADMIN_PAGES . 'support/',
183
-        ];
184
-    }
185
-
186
-
187
-    /**
188
-     * init- should fire after shortcode, module,  addon, other plugin (default priority), and even
189
-     * EE_Front_Controller's init phases have run
190
-     *
191
-     * @return void
192
-     * @throws EE_Error
193
-     * @throws InvalidArgumentException
194
-     * @throws InvalidDataTypeException
195
-     * @throws InvalidInterfaceException
196
-     * @throws ReflectionException
197
-     * @throws ServiceNotFoundException
198
-     */
199
-    public function init()
200
-    {
201
-        // only enable most of the EE_Admin IF we're not in full maintenance mode
202
-        if (EE_Maintenance_Mode::instance()->models_can_query()) {
203
-            $this->initModelsReady();
204
-        }
205
-        // run the admin page factory but ONLY if:
206
-        // - it is a regular non ajax admin request
207
-        // - we are doing an ee admin ajax request
208
-        if ($this->request->isAdmin() || $this->request->isAdminAjax()) {
209
-            // this loads the controller for the admin pages which will setup routing etc
210
-            $this->loader->getShared('EE_Admin_Page_Loader', [$this->loader]);
211
-        }
212
-        if ($this->request->isAdminAjax()) {
213
-            return;
214
-        }
215
-        add_filter('content_save_pre', [$this, 'its_eSpresso'], 10, 1);
216
-        // make sure our CPTs and custom taxonomy metaboxes get shown for first time users
217
-        add_action('admin_head', [$this, 'enable_hidden_ee_nav_menu_metaboxes'], 10);
218
-        add_action('admin_head', [$this, 'register_custom_nav_menu_boxes'], 10);
219
-        // exclude EE critical pages from all nav menus and wp_list_pages
220
-        add_filter('nav_menu_meta_box_object', [$this, 'remove_pages_from_nav_menu'], 10);
221
-    }
222
-
223
-
224
-    /**
225
-     * Gets the loader (and if it wasn't previously set, sets it)
226
-     *
227
-     * @return LoaderInterface
228
-     * @throws InvalidArgumentException
229
-     * @throws InvalidDataTypeException
230
-     * @throws InvalidInterfaceException
231
-     */
232
-    protected function getLoader()
233
-    {
234
-        return $this->loader;
235
-    }
236
-
237
-
238
-    /**
239
-     * Method that's fired on admin requests (including admin ajax) but only when the models are usable
240
-     * (ie, the site isn't in maintenance mode)
241
-     *
242
-     * @return void
243
-     * @throws EE_Error
244
-     * @since 4.9.63.p
245
-     */
246
-    protected function initModelsReady()
247
-    {
248
-        // ok so we want to enable the entire admin
249
-        $this->persistent_admin_notice_manager = $this->loader->getShared(
250
-            'EventEspresso\core\services\notifications\PersistentAdminNoticeManager'
251
-        );
252
-        $this->persistent_admin_notice_manager->setReturnUrl(
253
-            EE_Admin_Page::add_query_args_and_nonce(
254
-                [
255
-                    'page'   => $this->request->getRequestParam('page'),
256
-                    'action' => $this->request->getRequestParam('action'),
257
-                ],
258
-                EE_ADMIN_URL
259
-            )
260
-        );
261
-        $this->maybeSetDatetimeWarningNotice();
262
-        // at a glance dashboard widget
263
-        add_filter('dashboard_glance_items', [$this, 'dashboard_glance_items'], 10);
264
-        // filter for get_edit_post_link used on comments for custom post types
265
-        add_filter('get_edit_post_link', [$this, 'modify_edit_post_link'], 10, 2);
266
-    }
267
-
268
-
269
-    /**
270
-     *    get_persistent_admin_notices
271
-     *
272
-     * @access    public
273
-     * @return void
274
-     * @throws EE_Error
275
-     * @throws InvalidArgumentException
276
-     * @throws InvalidDataTypeException
277
-     * @throws InvalidInterfaceException
278
-     */
279
-    public function maybeSetDatetimeWarningNotice()
280
-    {
281
-        // add dismissible notice for datetime changes.  Only valid if site does not have a timezone_string set.
282
-        // @todo This needs to stay in core for a bit to catch anyone upgrading from a version without this to a version
283
-        // with this.  But after enough time (indeterminate at this point) we can just remove this notice.
284
-        // this was added with https://events.codebasehq.com/projects/event-espresso/tickets/10626
285
-        if (
286
-            apply_filters('FHEE__EE_Admin__maybeSetDatetimeWarningNotice', true)
287
-            && ! get_option('timezone_string')
288
-            && EEM_Event::instance()->count() > 0
289
-        ) {
290
-            new PersistentAdminNotice(
291
-                'datetime_fix_notice',
292
-                sprintf(
293
-                    esc_html__(
294
-                        '%1$sImportant announcement related to your install of Event Espresso%2$s: There are some changes made to your site that could affect how dates display for your events and other related items with dates and times.  Read more about it %3$shere%4$s. If your dates and times are displaying incorrectly (incorrect offset), you can fix it using the tool on %5$sthis page%4$s.',
295
-                        'event_espresso'
296
-                    ),
297
-                    '<strong>',
298
-                    '</strong>',
299
-                    '<a href="https://eventespresso.com/2017/08/important-upcoming-changes-dates-times">',
300
-                    '</a>',
301
-                    '<a href="' . EE_Admin_Page::add_query_args_and_nonce(
302
-                        [
303
-                            'page'   => 'espresso_maintenance_settings',
304
-                            'action' => 'datetime_tools',
305
-                        ],
306
-                        admin_url('admin.php')
307
-                    ) . '">'
308
-                ),
309
-                false,
310
-                'manage_options',
311
-                'datetime_fix_persistent_notice'
312
-            );
313
-        }
314
-    }
315
-
316
-
317
-    /**
318
-     * this simply hooks into the nav menu setup of pages metabox and makes sure that we remove EE critical pages from
319
-     * the list of options. the wp function "wp_nav_menu_item_post_type_meta_box" found in
320
-     * wp-admin/includes/nav-menu.php looks for the "_default_query" property on the post_type object and it uses that
321
-     * to override any queries found in the existing query for the given post type.  Note that _default_query is not a
322
-     * normal property on the post_type object.  It's found ONLY in this particular context.
323
-     *
324
-     * @param WP_Post $post_type WP post type object
325
-     * @return WP_Post
326
-     * @throws InvalidArgumentException
327
-     * @throws InvalidDataTypeException
328
-     * @throws InvalidInterfaceException
329
-     */
330
-    public function remove_pages_from_nav_menu($post_type)
331
-    {
332
-        // if this isn't the "pages" post type let's get out
333
-        if ($post_type->name !== 'page') {
334
-            return $post_type;
335
-        }
336
-        $critical_pages            = EE_Registry::instance()->CFG->core->get_critical_pages_array();
337
-        $post_type->_default_query = [
338
-            'post__not_in' => $critical_pages,
339
-        ];
340
-        return $post_type;
341
-    }
342
-
343
-
344
-    /**
345
-     * WP by default only shows three metaboxes in "nav-menus.php" for first times users.  We want to make sure our
346
-     * metaboxes get shown as well
347
-     *
348
-     * @return void
349
-     */
350
-    public function enable_hidden_ee_nav_menu_metaboxes()
351
-    {
352
-        global $wp_meta_boxes, $pagenow;
353
-        if (! is_array($wp_meta_boxes) || $pagenow !== 'nav-menus.php') {
354
-            return;
355
-        }
356
-        $user = wp_get_current_user();
357
-        // has this been done yet?
358
-        if (get_user_option('ee_nav_menu_initialized', $user->ID)) {
359
-            return;
360
-        }
361
-
362
-        $hidden_meta_boxes  = get_user_option('metaboxhidden_nav-menus', $user->ID);
363
-        $initial_meta_boxes = apply_filters(
364
-            'FHEE__EE_Admin__enable_hidden_ee_nav_menu_boxes__initial_meta_boxes',
365
-            [
366
-                'nav-menu-theme-locations',
367
-                'add-page',
368
-                'add-custom-links',
369
-                'add-category',
370
-                'add-espresso_events',
371
-                'add-espresso_venues',
372
-                'add-espresso_event_categories',
373
-                'add-espresso_venue_categories',
374
-                'add-post-type-post',
375
-                'add-post-type-page',
376
-            ]
377
-        );
378
-
379
-        if (is_array($hidden_meta_boxes)) {
380
-            foreach ($hidden_meta_boxes as $key => $meta_box_id) {
381
-                if (in_array($meta_box_id, $initial_meta_boxes, true)) {
382
-                    unset($hidden_meta_boxes[ $key ]);
383
-                }
384
-            }
385
-        }
386
-        update_user_option($user->ID, 'metaboxhidden_nav-menus', $hidden_meta_boxes, true);
387
-        update_user_option($user->ID, 'ee_nav_menu_initialized', 1, true);
388
-    }
389
-
390
-
391
-    /**
392
-     * This method simply registers custom nav menu boxes for "nav_menus.php route"
393
-     * Currently EE is using this to make sure there are menu options for our CPT archive page routes.
394
-     *
395
-     * @return void
396
-     * @todo   modify this so its more dynamic and automatic for all ee CPTs and setups and can also be hooked into by
397
-     *         addons etc.
398
-     */
399
-    public function register_custom_nav_menu_boxes()
400
-    {
401
-        add_meta_box(
402
-            'add-extra-nav-menu-pages',
403
-            esc_html__('Event Espresso Pages', 'event_espresso'),
404
-            [$this, 'ee_cpt_archive_pages'],
405
-            'nav-menus',
406
-            'side',
407
-            'core'
408
-        );
409
-    }
410
-
411
-
412
-    /**
413
-     * Use this to edit the post link for our cpts so that the edit link points to the correct page.
414
-     *
415
-     * @param string $link the original link generated by wp
416
-     * @param int    $id   post id
417
-     * @return string  the (maybe) modified link
418
-     * @since   4.3.0
419
-     */
420
-    public function modify_edit_post_link($link, $id)
421
-    {
422
-        if (! $post = get_post($id)) {
423
-            return $link;
424
-        }
425
-        if ($post->post_type === 'espresso_attendees') {
426
-            $query_args = [
427
-                'action' => 'edit_attendee',
428
-                'post'   => $id,
429
-            ];
430
-            return EEH_URL::add_query_args_and_nonce(
431
-                $query_args,
432
-                admin_url('admin.php?page=espresso_registrations')
433
-            );
434
-        }
435
-        return $link;
436
-    }
437
-
438
-
439
-    public function ee_cpt_archive_pages()
440
-    {
441
-        global $nav_menu_selected_id;
442
-        $removed_args = [
443
-            'action',
444
-            'customlink-tab',
445
-            'edit-menu-item',
446
-            'menu-item',
447
-            'page-tab',
448
-            '_wpnonce',
449
-        ];
450
-        $nav_tab_link = $nav_menu_selected_id
451
-            ? esc_url(
452
-                add_query_arg(
453
-                    'extra-nav-menu-pages-tab',
454
-                    'event-archives',
455
-                    remove_query_arg($removed_args)
456
-                )
457
-            )
458
-            : '';
459
-        $select_all_link = esc_url(
460
-            add_query_arg(
461
-                [
462
-                    'extra-nav-menu-pages-tab' => 'event-archives',
463
-                    'selectall'                => 1,
464
-                ],
465
-                remove_query_arg($removed_args)
466
-            )
467
-        );
468
-        $pages = $this->_get_extra_nav_menu_pages_items();
469
-        $args['walker'] = new Walker_Nav_Menu_Checklist(false);
470
-        ;
471
-        $nav_menu_pages_items = walk_nav_menu_tree(
472
-            array_map(
473
-                [$this, '_setup_extra_nav_menu_pages_items'],
474
-                $pages
475
-            ),
476
-            0,
477
-            (object) $args
478
-        );
479
-
480
-        EEH_Template::display_template(
481
-            EE_ADMIN_TEMPLATE . 'cpt_archive_page.template.php',
482
-            [
483
-                $nav_menu_pages_items,
484
-                $nav_tab_link,
485
-                $select_all_link,
486
-            ]
487
-        );
488
-    }
489
-
490
-
491
-    /**
492
-     * Returns an array of event archive nav items.
493
-     *
494
-     * @return array
495
-     * @todo  for now this method is just in place so when it gets abstracted further we can substitute in whatever
496
-     *        method we use for getting the extra nav menu items
497
-     */
498
-    private function _get_extra_nav_menu_pages_items()
499
-    {
500
-        $menuitems[] = [
501
-            'title'       => esc_html__('Event List', 'event_espresso'),
502
-            'url'         => get_post_type_archive_link('espresso_events'),
503
-            'description' => esc_html__('Archive page for all events.', 'event_espresso'),
504
-        ];
505
-        return apply_filters('FHEE__EE_Admin__get_extra_nav_menu_pages_items', $menuitems);
506
-    }
507
-
508
-
509
-    /**
510
-     * Setup nav menu walker item for usage in the event archive nav menu metabox.  It receives a menu_item array with
511
-     * the properties and converts it to the menu item object.
512
-     *
513
-     * @param $menu_item_values
514
-     * @return stdClass
515
-     * @see wp_setup_nav_menu_item() in wp-includes/nav-menu.php
516
-     */
517
-    private function _setup_extra_nav_menu_pages_items($menu_item_values)
518
-    {
519
-        $menu_item = new stdClass();
520
-        $keys      = [
521
-            'ID'               => 0,
522
-            'db_id'            => 0,
523
-            'menu_item_parent' => 0,
524
-            'object_id'        => -1,
525
-            'post_parent'      => 0,
526
-            'type'             => 'custom',
527
-            'object'           => '',
528
-            'type_label'       => esc_html__('Extra Nav Menu Item', 'event_espresso'),
529
-            'title'            => '',
530
-            'url'              => '',
531
-            'target'           => '',
532
-            'attr_title'       => '',
533
-            'description'      => '',
534
-            'classes'          => [],
535
-            'xfn'              => '',
536
-        ];
537
-
538
-        foreach ($keys as $key => $value) {
539
-            $menu_item->{$key} = isset($menu_item_values[ $key ]) ? $menu_item_values[ $key ] : $value;
540
-        }
541
-        return $menu_item;
542
-    }
543
-
544
-
545
-    /**
546
-     * This is the action hook for the AHEE__EE_Admin_Page__route_admin_request hook that fires off right before an
547
-     * EE_Admin_Page route is called.
548
-     *
549
-     * @return void
550
-     */
551
-    public function route_admin_request()
552
-    {
553
-    }
554
-
555
-
556
-    /**
557
-     * wp_loaded should fire on the WordPress wp_loaded hook.  This fires on a VERY late priority.
558
-     *
559
-     * @return void
560
-     */
561
-    public function wp_loaded()
562
-    {
563
-    }
564
-
565
-
566
-    /**
567
-     * admin_init
568
-     *
569
-     * @return void
570
-     * @throws InvalidArgumentException
571
-     * @throws InvalidDataTypeException
572
-     * @throws InvalidInterfaceException
573
-     */
574
-    public function admin_init()
575
-    {
576
-        /**
577
-         * our cpt models must be instantiated on WordPress post processing routes (wp-admin/post.php),
578
-         * so any hooking into core WP routes is taken care of.  So in this next few lines of code:
579
-         * - check if doing post processing.
580
-         * - check if doing post processing of one of EE CPTs
581
-         * - instantiate the corresponding EE CPT model for the post_type being processed.
582
-         */
583
-        $action    = $this->request->getRequestParam('action');
584
-        $post_type = $this->request->getRequestParam('post_type');
585
-        if ($post_type && $action === 'editpost') {
586
-            /** @var CustomPostTypeDefinitions $custom_post_types */
587
-            $custom_post_types = $this->loader->getShared(CustomPostTypeDefinitions::class);
588
-            $custom_post_types->getCustomPostTypeModels($post_type);
589
-        }
590
-
591
-
592
-        /**
593
-         * This code excludes EE critical pages anywhere `wp_dropdown_pages` is used to create a dropdown for selecting
594
-         * critical pages.  The only place critical pages need included in a generated dropdown is on the "Critical
595
-         * Pages" tab in the EE General Settings Admin page.
596
-         * This is for user-proofing.
597
-         */
598
-        add_filter('wp_dropdown_pages', [$this, 'modify_dropdown_pages']);
599
-        if (EE_Maintenance_Mode::instance()->models_can_query()) {
600
-            $this->adminInitModelsReady();
601
-        }
602
-    }
603
-
604
-
605
-    /**
606
-     * Runs on admin_init but only if models are usable (ie, we're not in maintenance mode)
607
-     */
608
-    protected function adminInitModelsReady()
609
-    {
610
-        if (function_exists('wp_add_privacy_policy_content')) {
611
-            $this->loader->getShared('EventEspresso\core\services\privacy\policy\PrivacyPolicyManager');
612
-        }
613
-    }
614
-
615
-
616
-    /**
617
-     * Callback for wp_dropdown_pages hook to remove ee critical pages from the dropdown selection.
618
-     *
619
-     * @param string $output Current output.
620
-     * @return string
621
-     * @throws InvalidArgumentException
622
-     * @throws InvalidDataTypeException
623
-     * @throws InvalidInterfaceException
624
-     */
625
-    public function modify_dropdown_pages($output)
626
-    {
627
-        // get critical pages
628
-        $critical_pages = EE_Registry::instance()->CFG->core->get_critical_pages_array();
629
-
630
-        // split current output by line break for easier parsing.
631
-        $split_output = explode("\n", $output);
632
-
633
-        // loop through to remove any critical pages from the array.
634
-        foreach ($critical_pages as $page_id) {
635
-            $needle = 'value="' . $page_id . '"';
636
-            foreach ($split_output as $key => $haystack) {
637
-                if (strpos($haystack, $needle) !== false) {
638
-                    unset($split_output[ $key ]);
639
-                }
640
-            }
641
-        }
642
-        // replace output with the new contents
643
-        return implode("\n", $split_output);
644
-    }
645
-
646
-
647
-    /**
648
-     * enqueue all admin scripts that need loaded for admin pages
649
-     *
650
-     * @return void
651
-     */
652
-    public function enqueue_admin_scripts()
653
-    {
654
-        // this javascript is loaded on every admin page to catch any injections ee needs to add to wp run js.
655
-        // Note: the intention of this script is to only do TARGETED injections.  I.E, only injecting on certain script
656
-        // calls.
657
-        wp_enqueue_script(
658
-            'ee-inject-wp',
659
-            EE_ADMIN_URL . 'assets/ee-cpt-wp-injects.js',
660
-            ['jquery'],
661
-            EVENT_ESPRESSO_VERSION,
662
-            true
663
-        );
664
-        // register cookie script for future dependencies
665
-        wp_register_script(
666
-            'jquery-cookie',
667
-            EE_THIRD_PARTY_URL . 'joyride/jquery.cookie.js',
668
-            ['jquery'],
669
-            '2.1',
670
-            true
671
-        );
672
-    }
673
-
674
-
675
-    /**
676
-     * display_admin_notices
677
-     *
678
-     * @return void
679
-     */
680
-    public function display_admin_notices()
681
-    {
682
-        echo EE_Error::get_notices(); // already escaped
683
-    }
684
-
685
-
686
-    /**
687
-     * @param array $elements
688
-     * @return array
689
-     * @throws EE_Error
690
-     * @throws InvalidArgumentException
691
-     * @throws InvalidDataTypeException
692
-     * @throws InvalidInterfaceException
693
-     */
694
-    public function dashboard_glance_items($elements)
695
-    {
696
-        $elements                        = is_array($elements) ? $elements : [$elements];
697
-        $events                          = EEM_Event::instance()->count();
698
-        $items['events']['url']          = EE_Admin_Page::add_query_args_and_nonce(
699
-            ['page' => 'espresso_events'],
700
-            admin_url('admin.php')
701
-        );
702
-        $items['events']['text']         = sprintf(
703
-            esc_html(
704
-                _n('%s Event', '%s Events', $events, 'event_espresso')
705
-            ),
706
-            number_format_i18n($events)
707
-        );
708
-        $items['events']['title']        = esc_html__('Click to view all Events', 'event_espresso');
709
-        $registrations                   = EEM_Registration::instance()->count(
710
-            [
711
-                [
712
-                    'STS_ID' => ['!=', EEM_Registration::status_id_incomplete],
713
-                ],
714
-            ]
715
-        );
716
-        $items['registrations']['url']   = EE_Admin_Page::add_query_args_and_nonce(
717
-            ['page' => 'espresso_registrations'],
718
-            admin_url('admin.php')
719
-        );
720
-        $items['registrations']['text']  = sprintf(
721
-            esc_html(
722
-                _n('%s Registration', '%s Registrations', $registrations, 'event_espresso')
723
-            ),
724
-            number_format_i18n($registrations)
725
-        );
726
-        $items['registrations']['title'] = esc_html__('Click to view all registrations', 'event_espresso');
727
-
728
-        $items = (array) apply_filters('FHEE__EE_Admin__dashboard_glance_items__items', $items);
729
-
730
-        foreach ($items as $type => $item_properties) {
731
-            $elements[] = sprintf(
732
-                '<a class="ee-dashboard-link-' . $type . '" href="%s" title="%s">%s</a>',
733
-                $item_properties['url'],
734
-                $item_properties['title'],
735
-                $item_properties['text']
736
-            );
737
-        }
738
-        return $elements;
739
-    }
740
-
741
-
742
-    /**
743
-     * check_for_invalid_datetime_formats
744
-     * if an admin changes their date or time format settings on the WP General Settings admin page, verify that
745
-     * their selected format can be parsed by PHP
746
-     *
747
-     * @param    $value
748
-     * @param    $option
749
-     * @return    string
750
-     */
751
-    public function check_for_invalid_datetime_formats($value, $option)
752
-    {
753
-        // check for date_format or time_format
754
-        switch ($option) {
755
-            case 'date_format':
756
-                $date_time_format = $value . ' ' . get_option('time_format');
757
-                break;
758
-            case 'time_format':
759
-                $date_time_format = get_option('date_format') . ' ' . $value;
760
-                break;
761
-            default:
762
-                $date_time_format = false;
763
-        }
764
-        // do we have a date_time format to check ?
765
-        if ($date_time_format) {
766
-            $error_msg = EEH_DTT_Helper::validate_format_string($date_time_format);
767
-
768
-            if (is_array($error_msg)) {
769
-                $msg = '<p>'
770
-                       . sprintf(
771
-                           esc_html__(
772
-                               'The following date time "%s" ( %s ) is difficult to be properly parsed by PHP for the following reasons:',
773
-                               'event_espresso'
774
-                           ),
775
-                           date($date_time_format),
776
-                           $date_time_format
777
-                       )
778
-                       . '</p><p><ul>';
779
-
780
-
781
-                foreach ($error_msg as $error) {
782
-                    $msg .= '<li>' . $error . '</li>';
783
-                }
784
-
785
-                $msg .= '</ul></p><p>'
786
-                        . sprintf(
787
-                            esc_html__(
788
-                                '%sPlease note that your date and time formats have been reset to "F j, Y" and "g:i a" respectively.%s',
789
-                                'event_espresso'
790
-                            ),
791
-                            '<span style="color:#D54E21;">',
792
-                            '</span>'
793
-                        )
794
-                        . '</p>';
795
-
796
-                // trigger WP settings error
797
-                add_settings_error(
798
-                    'date_format',
799
-                    'date_format',
800
-                    $msg
801
-                );
802
-
803
-                // set format to something valid
804
-                switch ($option) {
805
-                    case 'date_format':
806
-                        $value = 'F j, Y';
807
-                        break;
808
-                    case 'time_format':
809
-                        $value = 'g:i a';
810
-                        break;
811
-                }
812
-            }
813
-        }
814
-        return $value;
815
-    }
816
-
817
-
818
-    /**
819
-     * its_eSpresso - converts the less commonly used spelling of "Expresso" to "Espresso"
820
-     *
821
-     * @param $content
822
-     * @return    string
823
-     */
824
-    public function its_eSpresso($content)
825
-    {
826
-        return str_replace('[EXPRESSO_', '[ESPRESSO_', $content);
827
-    }
828
-
829
-
830
-    /**
831
-     * espresso_admin_footer
832
-     *
833
-     * @return    string
834
-     */
835
-    public function espresso_admin_footer()
836
-    {
837
-        return EEH_Template::powered_by_event_espresso('aln-cntr', '', ['utm_content' => 'admin_footer']);
838
-    }
839
-
840
-
841
-    /**
842
-     * static method for registering ee admin page.
843
-     * This method is deprecated in favor of the new location in EE_Register_Admin_Page::register.
844
-     *
845
-     * @param       $page_basename
846
-     * @param       $page_path
847
-     * @param array $config
848
-     * @return void
849
-     * @throws EE_Error
850
-     * @see        EE_Register_Admin_Page::register()
851
-     * @since      4.3.0
852
-     * @deprecated 4.3.0    Use EE_Register_Admin_Page::register() instead
853
-     */
854
-    public static function register_ee_admin_page($page_basename, $page_path, $config = [])
855
-    {
856
-        EE_Error::doing_it_wrong(
857
-            __METHOD__,
858
-            sprintf(
859
-                esc_html__(
860
-                    'Usage is deprecated.  Use EE_Register_Admin_Page::register() for registering the %s admin page.',
861
-                    'event_espresso'
862
-                ),
863
-                $page_basename
864
-            ),
865
-            '4.3'
866
-        );
867
-        if (class_exists('EE_Register_Admin_Page')) {
868
-            $config['page_path'] = $page_path;
869
-        }
870
-        EE_Register_Admin_Page::register($page_basename, $config);
871
-    }
872
-
873
-
874
-    /**
875
-     * @param int     $post_ID
876
-     * @param WP_Post $post
877
-     * @return void
878
-     * @deprecated 4.8.41
879
-     */
880
-    public static function parse_post_content_on_save($post_ID, $post)
881
-    {
882
-        EE_Error::doing_it_wrong(
883
-            __METHOD__,
884
-            esc_html__('Usage is deprecated', 'event_espresso'),
885
-            '4.8.41'
886
-        );
887
-    }
888
-
889
-
890
-    /**
891
-     * @param  $option
892
-     * @param  $old_value
893
-     * @param  $value
894
-     * @return void
895
-     * @deprecated 4.8.41
896
-     */
897
-    public function reset_page_for_posts_on_change($option, $old_value, $value)
898
-    {
899
-        EE_Error::doing_it_wrong(
900
-            __METHOD__,
901
-            esc_html__('Usage is deprecated', 'event_espresso'),
902
-            '4.8.41'
903
-        );
904
-    }
905
-
906
-
907
-    /**
908
-     * @return void
909
-     * @deprecated 4.9.27
910
-     */
911
-    public function get_persistent_admin_notices()
912
-    {
913
-        EE_Error::doing_it_wrong(
914
-            __METHOD__,
915
-            sprintf(
916
-                esc_html__('Usage is deprecated. Use "%1$s" instead.', 'event_espresso'),
917
-                '\EventEspresso\core\services\notifications\PersistentAdminNoticeManager'
918
-            ),
919
-            '4.9.27'
920
-        );
921
-    }
922
-
923
-
924
-    /**
925
-     * @throws InvalidInterfaceException
926
-     * @throws InvalidDataTypeException
927
-     * @throws DomainException
928
-     * @deprecated 4.9.27
929
-     */
930
-    public function dismiss_ee_nag_notice_callback()
931
-    {
932
-        EE_Error::doing_it_wrong(
933
-            __METHOD__,
934
-            sprintf(
935
-                esc_html__('Usage is deprecated. Use "%1$s" instead.', 'event_espresso'),
936
-                '\EventEspresso\core\services\notifications\PersistentAdminNoticeManager'
937
-            ),
938
-            '4.9.27'
939
-        );
940
-        $this->persistent_admin_notice_manager->dismissNotice();
941
-    }
942
-
943
-
944
-    /**
945
-     * Callback on load-plugins.php hook for setting up anything hooking into the wp plugins page.
946
-     *
947
-     * @throws InvalidArgumentException
948
-     * @throws InvalidDataTypeException
949
-     * @throws InvalidInterfaceException
950
-     */
951
-    public function hookIntoWpPluginsPage()
952
-    {
953
-        $this->loader->getShared('EventEspresso\core\domain\services\admin\ExitModal');
954
-        $this->loader
955
-             ->getShared('EventEspresso\core\domain\services\admin\PluginUpsells')
956
-             ->decafUpsells();
957
-    }
958
-
959
-
960
-    /**
961
-     * Hooks into the "post states" filter in a wp post type list table.
962
-     *
963
-     * @param array   $post_states
964
-     * @param WP_Post $post
965
-     * @return array
966
-     * @throws InvalidArgumentException
967
-     * @throws InvalidDataTypeException
968
-     * @throws InvalidInterfaceException
969
-     */
970
-    public function displayStateForCriticalPages($post_states, $post)
971
-    {
972
-        $post_states = (array) $post_states;
973
-        if (! $post instanceof WP_Post || $post->post_type !== 'page') {
974
-            return $post_states;
975
-        }
976
-        /** @var EE_Core_Config $config */
977
-        $config = $this->loader->getShared('EE_Config')->core;
978
-        if (in_array($post->ID, $config->get_critical_pages_array(), true)) {
979
-            $post_states[] = sprintf(
980
-            /* Translators: Using company name - Event Espresso Critical Page */
981
-                esc_html__('%s Critical Page', 'event_espresso'),
982
-                'Event Espresso'
983
-            );
984
-        }
985
-        return $post_states;
986
-    }
987
-
988
-
989
-    /**
990
-     * Show documentation links on the plugins page
991
-     *
992
-     * @param mixed $meta Plugin Row Meta
993
-     * @param mixed $file Plugin Base file
994
-     * @return array
995
-     */
996
-    public function addLinksToPluginRowMeta($meta, $file)
997
-    {
998
-        if (EE_PLUGIN_BASENAME === $file) {
999
-            $row_meta = [
1000
-                'docs' => '<a href="https://eventespresso.com/support/documentation/versioned-docs/?doc_ver=ee4"'
1001
-                          . ' aria-label="'
1002
-                          . esc_attr__('View Event Espresso documentation', 'event_espresso')
1003
-                          . '">'
1004
-                          . esc_html__('Docs', 'event_espresso')
1005
-                          . '</a>',
1006
-                'api'  => '<a href="https://github.com/eventespresso/event-espresso-core/tree/master/docs/C--REST-API"'
1007
-                          . ' aria-label="'
1008
-                          . esc_attr__('View Event Espresso API docs', 'event_espresso')
1009
-                          . '">'
1010
-                          . esc_html__('API docs', 'event_espresso')
1011
-                          . '</a>',
1012
-            ];
1013
-            return array_merge($meta, $row_meta);
1014
-        }
1015
-        return (array) $meta;
1016
-    }
23
+	/**
24
+	 * @var EE_Admin $_instance
25
+	 */
26
+	private static $_instance;
27
+
28
+	/**
29
+	 * @var PersistentAdminNoticeManager $persistent_admin_notice_manager
30
+	 */
31
+	private $persistent_admin_notice_manager;
32
+
33
+	/**
34
+	 * @var LoaderInterface
35
+	 */
36
+	protected $loader;
37
+
38
+	/**
39
+	 * @var RequestInterface
40
+	 */
41
+	protected $request;
42
+
43
+
44
+	/**
45
+	 * @param RequestInterface $request
46
+	 * @singleton method used to instantiate class object
47
+	 * @return EE_Admin
48
+	 * @throws EE_Error
49
+	 */
50
+	public static function instance(RequestInterface $request = null)
51
+	{
52
+		// check if class object is instantiated
53
+		if (! self::$_instance instanceof EE_Admin) {
54
+			self::$_instance = new self($request);
55
+		}
56
+		return self::$_instance;
57
+	}
58
+
59
+
60
+	/**
61
+	 * @return EE_Admin
62
+	 * @throws EE_Error
63
+	 */
64
+	public static function reset()
65
+	{
66
+		self::$_instance = null;
67
+		$request         = LoaderFactory::getLoader()->getShared(RequestInterface::class);
68
+		return self::instance($request);
69
+	}
70
+
71
+
72
+	/**
73
+	 * @param RequestInterface $request
74
+	 * @throws EE_Error
75
+	 * @throws InvalidDataTypeException
76
+	 * @throws InvalidInterfaceException
77
+	 * @throws InvalidArgumentException
78
+	 */
79
+	protected function __construct(RequestInterface $request)
80
+	{
81
+		$this->request = $request;
82
+		$this->loader = LoaderFactory::getLoader();
83
+		// define global EE_Admin constants
84
+		$this->_define_all_constants();
85
+		// set autoloaders for our admin page classes based on included path information
86
+		EEH_Autoloader::instance()->register_autoloaders_for_each_file_in_folder(EE_ADMIN);
87
+		// admin hooks
88
+		add_filter('plugin_action_links', [$this, 'filter_plugin_actions'], 10, 2);
89
+		add_action('AHEE__EE_System__initialize_last', [$this, 'init']);
90
+		add_action('AHEE__EE_Admin_Page__route_admin_request', [$this, 'route_admin_request'], 100, 2);
91
+		add_action('wp_loaded', [$this, 'wp_loaded'], 100);
92
+		add_action('admin_init', [$this, 'admin_init'], 100);
93
+		add_action('admin_enqueue_scripts', [$this, 'enqueue_admin_scripts'], 20);
94
+		add_action('admin_notices', [$this, 'display_admin_notices'], 10);
95
+		add_action('network_admin_notices', [$this, 'display_admin_notices'], 10);
96
+		add_filter('pre_update_option', [$this, 'check_for_invalid_datetime_formats'], 100, 2);
97
+		add_filter('admin_footer_text', [$this, 'espresso_admin_footer']);
98
+		add_action('load-plugins.php', [$this, 'hookIntoWpPluginsPage']);
99
+		add_action('display_post_states', [$this, 'displayStateForCriticalPages'], 10, 2);
100
+		add_filter('plugin_row_meta', [$this, 'addLinksToPluginRowMeta'], 10, 2);
101
+		// reset Environment config (we only do this on admin page loads);
102
+		EE_Registry::instance()->CFG->environment->recheck_values();
103
+		do_action('AHEE__EE_Admin__loaded');
104
+	}
105
+
106
+
107
+	/**
108
+	 * _define_all_constants
109
+	 * define constants that are set globally for all admin pages
110
+	 *
111
+	 * @return void
112
+	 */
113
+	private function _define_all_constants()
114
+	{
115
+		if (! defined('EE_ADMIN_URL')) {
116
+			define('EE_ADMIN_URL', EE_PLUGIN_DIR_URL . 'core/admin/');
117
+			define('EE_ADMIN_PAGES_URL', EE_PLUGIN_DIR_URL . 'admin_pages/');
118
+			define('EE_ADMIN_TEMPLATE', EE_ADMIN . 'templates/');
119
+			define('WP_ADMIN_PATH', ABSPATH . 'wp-admin/');
120
+			define('WP_AJAX_URL', admin_url('admin-ajax.php'));
121
+		}
122
+	}
123
+
124
+
125
+	/**
126
+	 * filter_plugin_actions - adds links to the Plugins page listing
127
+	 *
128
+	 * @param array  $links
129
+	 * @param string $plugin
130
+	 * @return    array
131
+	 */
132
+	public function filter_plugin_actions($links, $plugin)
133
+	{
134
+		// set $main_file in stone
135
+		static $main_file;
136
+		// if $main_file is not set yet
137
+		if (! $main_file) {
138
+			$main_file = EE_PLUGIN_BASENAME;
139
+		}
140
+		if ($plugin === $main_file) {
141
+			// compare current plugin to this one
142
+			if (EE_Maintenance_Mode::instance()->level() === EE_Maintenance_Mode::level_2_complete_maintenance) {
143
+				$maintenance_link = '<a href="admin.php?page=espresso_maintenance_settings"'
144
+									. ' title="Event Espresso is in maintenance mode.  Click this link to learn why.">'
145
+									. esc_html__('Maintenance Mode Active', 'event_espresso')
146
+									. '</a>';
147
+				array_unshift($links, $maintenance_link);
148
+			} else {
149
+				$org_settings_link = '<a href="admin.php?page=espresso_general_settings">'
150
+									 . esc_html__('Settings', 'event_espresso')
151
+									 . '</a>';
152
+				$events_link       = '<a href="admin.php?page=espresso_events">'
153
+									 . esc_html__('Events', 'event_espresso')
154
+									 . '</a>';
155
+				// add before other links
156
+				array_unshift($links, $org_settings_link, $events_link);
157
+			}
158
+		}
159
+		return $links;
160
+	}
161
+
162
+
163
+	/**
164
+	 * @deprecated 4.10.14.p
165
+	 */
166
+	public function get_request()
167
+	{
168
+	}
169
+
170
+
171
+	/**
172
+	 * hide_admin_pages_except_maintenance_mode
173
+	 *
174
+	 * @param array $admin_page_folder_names
175
+	 * @return array
176
+	 */
177
+	public function hide_admin_pages_except_maintenance_mode($admin_page_folder_names = [])
178
+	{
179
+		return [
180
+			'maintenance' => EE_ADMIN_PAGES . 'maintenance/',
181
+			'about'       => EE_ADMIN_PAGES . 'about/',
182
+			'support'     => EE_ADMIN_PAGES . 'support/',
183
+		];
184
+	}
185
+
186
+
187
+	/**
188
+	 * init- should fire after shortcode, module,  addon, other plugin (default priority), and even
189
+	 * EE_Front_Controller's init phases have run
190
+	 *
191
+	 * @return void
192
+	 * @throws EE_Error
193
+	 * @throws InvalidArgumentException
194
+	 * @throws InvalidDataTypeException
195
+	 * @throws InvalidInterfaceException
196
+	 * @throws ReflectionException
197
+	 * @throws ServiceNotFoundException
198
+	 */
199
+	public function init()
200
+	{
201
+		// only enable most of the EE_Admin IF we're not in full maintenance mode
202
+		if (EE_Maintenance_Mode::instance()->models_can_query()) {
203
+			$this->initModelsReady();
204
+		}
205
+		// run the admin page factory but ONLY if:
206
+		// - it is a regular non ajax admin request
207
+		// - we are doing an ee admin ajax request
208
+		if ($this->request->isAdmin() || $this->request->isAdminAjax()) {
209
+			// this loads the controller for the admin pages which will setup routing etc
210
+			$this->loader->getShared('EE_Admin_Page_Loader', [$this->loader]);
211
+		}
212
+		if ($this->request->isAdminAjax()) {
213
+			return;
214
+		}
215
+		add_filter('content_save_pre', [$this, 'its_eSpresso'], 10, 1);
216
+		// make sure our CPTs and custom taxonomy metaboxes get shown for first time users
217
+		add_action('admin_head', [$this, 'enable_hidden_ee_nav_menu_metaboxes'], 10);
218
+		add_action('admin_head', [$this, 'register_custom_nav_menu_boxes'], 10);
219
+		// exclude EE critical pages from all nav menus and wp_list_pages
220
+		add_filter('nav_menu_meta_box_object', [$this, 'remove_pages_from_nav_menu'], 10);
221
+	}
222
+
223
+
224
+	/**
225
+	 * Gets the loader (and if it wasn't previously set, sets it)
226
+	 *
227
+	 * @return LoaderInterface
228
+	 * @throws InvalidArgumentException
229
+	 * @throws InvalidDataTypeException
230
+	 * @throws InvalidInterfaceException
231
+	 */
232
+	protected function getLoader()
233
+	{
234
+		return $this->loader;
235
+	}
236
+
237
+
238
+	/**
239
+	 * Method that's fired on admin requests (including admin ajax) but only when the models are usable
240
+	 * (ie, the site isn't in maintenance mode)
241
+	 *
242
+	 * @return void
243
+	 * @throws EE_Error
244
+	 * @since 4.9.63.p
245
+	 */
246
+	protected function initModelsReady()
247
+	{
248
+		// ok so we want to enable the entire admin
249
+		$this->persistent_admin_notice_manager = $this->loader->getShared(
250
+			'EventEspresso\core\services\notifications\PersistentAdminNoticeManager'
251
+		);
252
+		$this->persistent_admin_notice_manager->setReturnUrl(
253
+			EE_Admin_Page::add_query_args_and_nonce(
254
+				[
255
+					'page'   => $this->request->getRequestParam('page'),
256
+					'action' => $this->request->getRequestParam('action'),
257
+				],
258
+				EE_ADMIN_URL
259
+			)
260
+		);
261
+		$this->maybeSetDatetimeWarningNotice();
262
+		// at a glance dashboard widget
263
+		add_filter('dashboard_glance_items', [$this, 'dashboard_glance_items'], 10);
264
+		// filter for get_edit_post_link used on comments for custom post types
265
+		add_filter('get_edit_post_link', [$this, 'modify_edit_post_link'], 10, 2);
266
+	}
267
+
268
+
269
+	/**
270
+	 *    get_persistent_admin_notices
271
+	 *
272
+	 * @access    public
273
+	 * @return void
274
+	 * @throws EE_Error
275
+	 * @throws InvalidArgumentException
276
+	 * @throws InvalidDataTypeException
277
+	 * @throws InvalidInterfaceException
278
+	 */
279
+	public function maybeSetDatetimeWarningNotice()
280
+	{
281
+		// add dismissible notice for datetime changes.  Only valid if site does not have a timezone_string set.
282
+		// @todo This needs to stay in core for a bit to catch anyone upgrading from a version without this to a version
283
+		// with this.  But after enough time (indeterminate at this point) we can just remove this notice.
284
+		// this was added with https://events.codebasehq.com/projects/event-espresso/tickets/10626
285
+		if (
286
+			apply_filters('FHEE__EE_Admin__maybeSetDatetimeWarningNotice', true)
287
+			&& ! get_option('timezone_string')
288
+			&& EEM_Event::instance()->count() > 0
289
+		) {
290
+			new PersistentAdminNotice(
291
+				'datetime_fix_notice',
292
+				sprintf(
293
+					esc_html__(
294
+						'%1$sImportant announcement related to your install of Event Espresso%2$s: There are some changes made to your site that could affect how dates display for your events and other related items with dates and times.  Read more about it %3$shere%4$s. If your dates and times are displaying incorrectly (incorrect offset), you can fix it using the tool on %5$sthis page%4$s.',
295
+						'event_espresso'
296
+					),
297
+					'<strong>',
298
+					'</strong>',
299
+					'<a href="https://eventespresso.com/2017/08/important-upcoming-changes-dates-times">',
300
+					'</a>',
301
+					'<a href="' . EE_Admin_Page::add_query_args_and_nonce(
302
+						[
303
+							'page'   => 'espresso_maintenance_settings',
304
+							'action' => 'datetime_tools',
305
+						],
306
+						admin_url('admin.php')
307
+					) . '">'
308
+				),
309
+				false,
310
+				'manage_options',
311
+				'datetime_fix_persistent_notice'
312
+			);
313
+		}
314
+	}
315
+
316
+
317
+	/**
318
+	 * this simply hooks into the nav menu setup of pages metabox and makes sure that we remove EE critical pages from
319
+	 * the list of options. the wp function "wp_nav_menu_item_post_type_meta_box" found in
320
+	 * wp-admin/includes/nav-menu.php looks for the "_default_query" property on the post_type object and it uses that
321
+	 * to override any queries found in the existing query for the given post type.  Note that _default_query is not a
322
+	 * normal property on the post_type object.  It's found ONLY in this particular context.
323
+	 *
324
+	 * @param WP_Post $post_type WP post type object
325
+	 * @return WP_Post
326
+	 * @throws InvalidArgumentException
327
+	 * @throws InvalidDataTypeException
328
+	 * @throws InvalidInterfaceException
329
+	 */
330
+	public function remove_pages_from_nav_menu($post_type)
331
+	{
332
+		// if this isn't the "pages" post type let's get out
333
+		if ($post_type->name !== 'page') {
334
+			return $post_type;
335
+		}
336
+		$critical_pages            = EE_Registry::instance()->CFG->core->get_critical_pages_array();
337
+		$post_type->_default_query = [
338
+			'post__not_in' => $critical_pages,
339
+		];
340
+		return $post_type;
341
+	}
342
+
343
+
344
+	/**
345
+	 * WP by default only shows three metaboxes in "nav-menus.php" for first times users.  We want to make sure our
346
+	 * metaboxes get shown as well
347
+	 *
348
+	 * @return void
349
+	 */
350
+	public function enable_hidden_ee_nav_menu_metaboxes()
351
+	{
352
+		global $wp_meta_boxes, $pagenow;
353
+		if (! is_array($wp_meta_boxes) || $pagenow !== 'nav-menus.php') {
354
+			return;
355
+		}
356
+		$user = wp_get_current_user();
357
+		// has this been done yet?
358
+		if (get_user_option('ee_nav_menu_initialized', $user->ID)) {
359
+			return;
360
+		}
361
+
362
+		$hidden_meta_boxes  = get_user_option('metaboxhidden_nav-menus', $user->ID);
363
+		$initial_meta_boxes = apply_filters(
364
+			'FHEE__EE_Admin__enable_hidden_ee_nav_menu_boxes__initial_meta_boxes',
365
+			[
366
+				'nav-menu-theme-locations',
367
+				'add-page',
368
+				'add-custom-links',
369
+				'add-category',
370
+				'add-espresso_events',
371
+				'add-espresso_venues',
372
+				'add-espresso_event_categories',
373
+				'add-espresso_venue_categories',
374
+				'add-post-type-post',
375
+				'add-post-type-page',
376
+			]
377
+		);
378
+
379
+		if (is_array($hidden_meta_boxes)) {
380
+			foreach ($hidden_meta_boxes as $key => $meta_box_id) {
381
+				if (in_array($meta_box_id, $initial_meta_boxes, true)) {
382
+					unset($hidden_meta_boxes[ $key ]);
383
+				}
384
+			}
385
+		}
386
+		update_user_option($user->ID, 'metaboxhidden_nav-menus', $hidden_meta_boxes, true);
387
+		update_user_option($user->ID, 'ee_nav_menu_initialized', 1, true);
388
+	}
389
+
390
+
391
+	/**
392
+	 * This method simply registers custom nav menu boxes for "nav_menus.php route"
393
+	 * Currently EE is using this to make sure there are menu options for our CPT archive page routes.
394
+	 *
395
+	 * @return void
396
+	 * @todo   modify this so its more dynamic and automatic for all ee CPTs and setups and can also be hooked into by
397
+	 *         addons etc.
398
+	 */
399
+	public function register_custom_nav_menu_boxes()
400
+	{
401
+		add_meta_box(
402
+			'add-extra-nav-menu-pages',
403
+			esc_html__('Event Espresso Pages', 'event_espresso'),
404
+			[$this, 'ee_cpt_archive_pages'],
405
+			'nav-menus',
406
+			'side',
407
+			'core'
408
+		);
409
+	}
410
+
411
+
412
+	/**
413
+	 * Use this to edit the post link for our cpts so that the edit link points to the correct page.
414
+	 *
415
+	 * @param string $link the original link generated by wp
416
+	 * @param int    $id   post id
417
+	 * @return string  the (maybe) modified link
418
+	 * @since   4.3.0
419
+	 */
420
+	public function modify_edit_post_link($link, $id)
421
+	{
422
+		if (! $post = get_post($id)) {
423
+			return $link;
424
+		}
425
+		if ($post->post_type === 'espresso_attendees') {
426
+			$query_args = [
427
+				'action' => 'edit_attendee',
428
+				'post'   => $id,
429
+			];
430
+			return EEH_URL::add_query_args_and_nonce(
431
+				$query_args,
432
+				admin_url('admin.php?page=espresso_registrations')
433
+			);
434
+		}
435
+		return $link;
436
+	}
437
+
438
+
439
+	public function ee_cpt_archive_pages()
440
+	{
441
+		global $nav_menu_selected_id;
442
+		$removed_args = [
443
+			'action',
444
+			'customlink-tab',
445
+			'edit-menu-item',
446
+			'menu-item',
447
+			'page-tab',
448
+			'_wpnonce',
449
+		];
450
+		$nav_tab_link = $nav_menu_selected_id
451
+			? esc_url(
452
+				add_query_arg(
453
+					'extra-nav-menu-pages-tab',
454
+					'event-archives',
455
+					remove_query_arg($removed_args)
456
+				)
457
+			)
458
+			: '';
459
+		$select_all_link = esc_url(
460
+			add_query_arg(
461
+				[
462
+					'extra-nav-menu-pages-tab' => 'event-archives',
463
+					'selectall'                => 1,
464
+				],
465
+				remove_query_arg($removed_args)
466
+			)
467
+		);
468
+		$pages = $this->_get_extra_nav_menu_pages_items();
469
+		$args['walker'] = new Walker_Nav_Menu_Checklist(false);
470
+		;
471
+		$nav_menu_pages_items = walk_nav_menu_tree(
472
+			array_map(
473
+				[$this, '_setup_extra_nav_menu_pages_items'],
474
+				$pages
475
+			),
476
+			0,
477
+			(object) $args
478
+		);
479
+
480
+		EEH_Template::display_template(
481
+			EE_ADMIN_TEMPLATE . 'cpt_archive_page.template.php',
482
+			[
483
+				$nav_menu_pages_items,
484
+				$nav_tab_link,
485
+				$select_all_link,
486
+			]
487
+		);
488
+	}
489
+
490
+
491
+	/**
492
+	 * Returns an array of event archive nav items.
493
+	 *
494
+	 * @return array
495
+	 * @todo  for now this method is just in place so when it gets abstracted further we can substitute in whatever
496
+	 *        method we use for getting the extra nav menu items
497
+	 */
498
+	private function _get_extra_nav_menu_pages_items()
499
+	{
500
+		$menuitems[] = [
501
+			'title'       => esc_html__('Event List', 'event_espresso'),
502
+			'url'         => get_post_type_archive_link('espresso_events'),
503
+			'description' => esc_html__('Archive page for all events.', 'event_espresso'),
504
+		];
505
+		return apply_filters('FHEE__EE_Admin__get_extra_nav_menu_pages_items', $menuitems);
506
+	}
507
+
508
+
509
+	/**
510
+	 * Setup nav menu walker item for usage in the event archive nav menu metabox.  It receives a menu_item array with
511
+	 * the properties and converts it to the menu item object.
512
+	 *
513
+	 * @param $menu_item_values
514
+	 * @return stdClass
515
+	 * @see wp_setup_nav_menu_item() in wp-includes/nav-menu.php
516
+	 */
517
+	private function _setup_extra_nav_menu_pages_items($menu_item_values)
518
+	{
519
+		$menu_item = new stdClass();
520
+		$keys      = [
521
+			'ID'               => 0,
522
+			'db_id'            => 0,
523
+			'menu_item_parent' => 0,
524
+			'object_id'        => -1,
525
+			'post_parent'      => 0,
526
+			'type'             => 'custom',
527
+			'object'           => '',
528
+			'type_label'       => esc_html__('Extra Nav Menu Item', 'event_espresso'),
529
+			'title'            => '',
530
+			'url'              => '',
531
+			'target'           => '',
532
+			'attr_title'       => '',
533
+			'description'      => '',
534
+			'classes'          => [],
535
+			'xfn'              => '',
536
+		];
537
+
538
+		foreach ($keys as $key => $value) {
539
+			$menu_item->{$key} = isset($menu_item_values[ $key ]) ? $menu_item_values[ $key ] : $value;
540
+		}
541
+		return $menu_item;
542
+	}
543
+
544
+
545
+	/**
546
+	 * This is the action hook for the AHEE__EE_Admin_Page__route_admin_request hook that fires off right before an
547
+	 * EE_Admin_Page route is called.
548
+	 *
549
+	 * @return void
550
+	 */
551
+	public function route_admin_request()
552
+	{
553
+	}
554
+
555
+
556
+	/**
557
+	 * wp_loaded should fire on the WordPress wp_loaded hook.  This fires on a VERY late priority.
558
+	 *
559
+	 * @return void
560
+	 */
561
+	public function wp_loaded()
562
+	{
563
+	}
564
+
565
+
566
+	/**
567
+	 * admin_init
568
+	 *
569
+	 * @return void
570
+	 * @throws InvalidArgumentException
571
+	 * @throws InvalidDataTypeException
572
+	 * @throws InvalidInterfaceException
573
+	 */
574
+	public function admin_init()
575
+	{
576
+		/**
577
+		 * our cpt models must be instantiated on WordPress post processing routes (wp-admin/post.php),
578
+		 * so any hooking into core WP routes is taken care of.  So in this next few lines of code:
579
+		 * - check if doing post processing.
580
+		 * - check if doing post processing of one of EE CPTs
581
+		 * - instantiate the corresponding EE CPT model for the post_type being processed.
582
+		 */
583
+		$action    = $this->request->getRequestParam('action');
584
+		$post_type = $this->request->getRequestParam('post_type');
585
+		if ($post_type && $action === 'editpost') {
586
+			/** @var CustomPostTypeDefinitions $custom_post_types */
587
+			$custom_post_types = $this->loader->getShared(CustomPostTypeDefinitions::class);
588
+			$custom_post_types->getCustomPostTypeModels($post_type);
589
+		}
590
+
591
+
592
+		/**
593
+		 * This code excludes EE critical pages anywhere `wp_dropdown_pages` is used to create a dropdown for selecting
594
+		 * critical pages.  The only place critical pages need included in a generated dropdown is on the "Critical
595
+		 * Pages" tab in the EE General Settings Admin page.
596
+		 * This is for user-proofing.
597
+		 */
598
+		add_filter('wp_dropdown_pages', [$this, 'modify_dropdown_pages']);
599
+		if (EE_Maintenance_Mode::instance()->models_can_query()) {
600
+			$this->adminInitModelsReady();
601
+		}
602
+	}
603
+
604
+
605
+	/**
606
+	 * Runs on admin_init but only if models are usable (ie, we're not in maintenance mode)
607
+	 */
608
+	protected function adminInitModelsReady()
609
+	{
610
+		if (function_exists('wp_add_privacy_policy_content')) {
611
+			$this->loader->getShared('EventEspresso\core\services\privacy\policy\PrivacyPolicyManager');
612
+		}
613
+	}
614
+
615
+
616
+	/**
617
+	 * Callback for wp_dropdown_pages hook to remove ee critical pages from the dropdown selection.
618
+	 *
619
+	 * @param string $output Current output.
620
+	 * @return string
621
+	 * @throws InvalidArgumentException
622
+	 * @throws InvalidDataTypeException
623
+	 * @throws InvalidInterfaceException
624
+	 */
625
+	public function modify_dropdown_pages($output)
626
+	{
627
+		// get critical pages
628
+		$critical_pages = EE_Registry::instance()->CFG->core->get_critical_pages_array();
629
+
630
+		// split current output by line break for easier parsing.
631
+		$split_output = explode("\n", $output);
632
+
633
+		// loop through to remove any critical pages from the array.
634
+		foreach ($critical_pages as $page_id) {
635
+			$needle = 'value="' . $page_id . '"';
636
+			foreach ($split_output as $key => $haystack) {
637
+				if (strpos($haystack, $needle) !== false) {
638
+					unset($split_output[ $key ]);
639
+				}
640
+			}
641
+		}
642
+		// replace output with the new contents
643
+		return implode("\n", $split_output);
644
+	}
645
+
646
+
647
+	/**
648
+	 * enqueue all admin scripts that need loaded for admin pages
649
+	 *
650
+	 * @return void
651
+	 */
652
+	public function enqueue_admin_scripts()
653
+	{
654
+		// this javascript is loaded on every admin page to catch any injections ee needs to add to wp run js.
655
+		// Note: the intention of this script is to only do TARGETED injections.  I.E, only injecting on certain script
656
+		// calls.
657
+		wp_enqueue_script(
658
+			'ee-inject-wp',
659
+			EE_ADMIN_URL . 'assets/ee-cpt-wp-injects.js',
660
+			['jquery'],
661
+			EVENT_ESPRESSO_VERSION,
662
+			true
663
+		);
664
+		// register cookie script for future dependencies
665
+		wp_register_script(
666
+			'jquery-cookie',
667
+			EE_THIRD_PARTY_URL . 'joyride/jquery.cookie.js',
668
+			['jquery'],
669
+			'2.1',
670
+			true
671
+		);
672
+	}
673
+
674
+
675
+	/**
676
+	 * display_admin_notices
677
+	 *
678
+	 * @return void
679
+	 */
680
+	public function display_admin_notices()
681
+	{
682
+		echo EE_Error::get_notices(); // already escaped
683
+	}
684
+
685
+
686
+	/**
687
+	 * @param array $elements
688
+	 * @return array
689
+	 * @throws EE_Error
690
+	 * @throws InvalidArgumentException
691
+	 * @throws InvalidDataTypeException
692
+	 * @throws InvalidInterfaceException
693
+	 */
694
+	public function dashboard_glance_items($elements)
695
+	{
696
+		$elements                        = is_array($elements) ? $elements : [$elements];
697
+		$events                          = EEM_Event::instance()->count();
698
+		$items['events']['url']          = EE_Admin_Page::add_query_args_and_nonce(
699
+			['page' => 'espresso_events'],
700
+			admin_url('admin.php')
701
+		);
702
+		$items['events']['text']         = sprintf(
703
+			esc_html(
704
+				_n('%s Event', '%s Events', $events, 'event_espresso')
705
+			),
706
+			number_format_i18n($events)
707
+		);
708
+		$items['events']['title']        = esc_html__('Click to view all Events', 'event_espresso');
709
+		$registrations                   = EEM_Registration::instance()->count(
710
+			[
711
+				[
712
+					'STS_ID' => ['!=', EEM_Registration::status_id_incomplete],
713
+				],
714
+			]
715
+		);
716
+		$items['registrations']['url']   = EE_Admin_Page::add_query_args_and_nonce(
717
+			['page' => 'espresso_registrations'],
718
+			admin_url('admin.php')
719
+		);
720
+		$items['registrations']['text']  = sprintf(
721
+			esc_html(
722
+				_n('%s Registration', '%s Registrations', $registrations, 'event_espresso')
723
+			),
724
+			number_format_i18n($registrations)
725
+		);
726
+		$items['registrations']['title'] = esc_html__('Click to view all registrations', 'event_espresso');
727
+
728
+		$items = (array) apply_filters('FHEE__EE_Admin__dashboard_glance_items__items', $items);
729
+
730
+		foreach ($items as $type => $item_properties) {
731
+			$elements[] = sprintf(
732
+				'<a class="ee-dashboard-link-' . $type . '" href="%s" title="%s">%s</a>',
733
+				$item_properties['url'],
734
+				$item_properties['title'],
735
+				$item_properties['text']
736
+			);
737
+		}
738
+		return $elements;
739
+	}
740
+
741
+
742
+	/**
743
+	 * check_for_invalid_datetime_formats
744
+	 * if an admin changes their date or time format settings on the WP General Settings admin page, verify that
745
+	 * their selected format can be parsed by PHP
746
+	 *
747
+	 * @param    $value
748
+	 * @param    $option
749
+	 * @return    string
750
+	 */
751
+	public function check_for_invalid_datetime_formats($value, $option)
752
+	{
753
+		// check for date_format or time_format
754
+		switch ($option) {
755
+			case 'date_format':
756
+				$date_time_format = $value . ' ' . get_option('time_format');
757
+				break;
758
+			case 'time_format':
759
+				$date_time_format = get_option('date_format') . ' ' . $value;
760
+				break;
761
+			default:
762
+				$date_time_format = false;
763
+		}
764
+		// do we have a date_time format to check ?
765
+		if ($date_time_format) {
766
+			$error_msg = EEH_DTT_Helper::validate_format_string($date_time_format);
767
+
768
+			if (is_array($error_msg)) {
769
+				$msg = '<p>'
770
+					   . sprintf(
771
+						   esc_html__(
772
+							   'The following date time "%s" ( %s ) is difficult to be properly parsed by PHP for the following reasons:',
773
+							   'event_espresso'
774
+						   ),
775
+						   date($date_time_format),
776
+						   $date_time_format
777
+					   )
778
+					   . '</p><p><ul>';
779
+
780
+
781
+				foreach ($error_msg as $error) {
782
+					$msg .= '<li>' . $error . '</li>';
783
+				}
784
+
785
+				$msg .= '</ul></p><p>'
786
+						. sprintf(
787
+							esc_html__(
788
+								'%sPlease note that your date and time formats have been reset to "F j, Y" and "g:i a" respectively.%s',
789
+								'event_espresso'
790
+							),
791
+							'<span style="color:#D54E21;">',
792
+							'</span>'
793
+						)
794
+						. '</p>';
795
+
796
+				// trigger WP settings error
797
+				add_settings_error(
798
+					'date_format',
799
+					'date_format',
800
+					$msg
801
+				);
802
+
803
+				// set format to something valid
804
+				switch ($option) {
805
+					case 'date_format':
806
+						$value = 'F j, Y';
807
+						break;
808
+					case 'time_format':
809
+						$value = 'g:i a';
810
+						break;
811
+				}
812
+			}
813
+		}
814
+		return $value;
815
+	}
816
+
817
+
818
+	/**
819
+	 * its_eSpresso - converts the less commonly used spelling of "Expresso" to "Espresso"
820
+	 *
821
+	 * @param $content
822
+	 * @return    string
823
+	 */
824
+	public function its_eSpresso($content)
825
+	{
826
+		return str_replace('[EXPRESSO_', '[ESPRESSO_', $content);
827
+	}
828
+
829
+
830
+	/**
831
+	 * espresso_admin_footer
832
+	 *
833
+	 * @return    string
834
+	 */
835
+	public function espresso_admin_footer()
836
+	{
837
+		return EEH_Template::powered_by_event_espresso('aln-cntr', '', ['utm_content' => 'admin_footer']);
838
+	}
839
+
840
+
841
+	/**
842
+	 * static method for registering ee admin page.
843
+	 * This method is deprecated in favor of the new location in EE_Register_Admin_Page::register.
844
+	 *
845
+	 * @param       $page_basename
846
+	 * @param       $page_path
847
+	 * @param array $config
848
+	 * @return void
849
+	 * @throws EE_Error
850
+	 * @see        EE_Register_Admin_Page::register()
851
+	 * @since      4.3.0
852
+	 * @deprecated 4.3.0    Use EE_Register_Admin_Page::register() instead
853
+	 */
854
+	public static function register_ee_admin_page($page_basename, $page_path, $config = [])
855
+	{
856
+		EE_Error::doing_it_wrong(
857
+			__METHOD__,
858
+			sprintf(
859
+				esc_html__(
860
+					'Usage is deprecated.  Use EE_Register_Admin_Page::register() for registering the %s admin page.',
861
+					'event_espresso'
862
+				),
863
+				$page_basename
864
+			),
865
+			'4.3'
866
+		);
867
+		if (class_exists('EE_Register_Admin_Page')) {
868
+			$config['page_path'] = $page_path;
869
+		}
870
+		EE_Register_Admin_Page::register($page_basename, $config);
871
+	}
872
+
873
+
874
+	/**
875
+	 * @param int     $post_ID
876
+	 * @param WP_Post $post
877
+	 * @return void
878
+	 * @deprecated 4.8.41
879
+	 */
880
+	public static function parse_post_content_on_save($post_ID, $post)
881
+	{
882
+		EE_Error::doing_it_wrong(
883
+			__METHOD__,
884
+			esc_html__('Usage is deprecated', 'event_espresso'),
885
+			'4.8.41'
886
+		);
887
+	}
888
+
889
+
890
+	/**
891
+	 * @param  $option
892
+	 * @param  $old_value
893
+	 * @param  $value
894
+	 * @return void
895
+	 * @deprecated 4.8.41
896
+	 */
897
+	public function reset_page_for_posts_on_change($option, $old_value, $value)
898
+	{
899
+		EE_Error::doing_it_wrong(
900
+			__METHOD__,
901
+			esc_html__('Usage is deprecated', 'event_espresso'),
902
+			'4.8.41'
903
+		);
904
+	}
905
+
906
+
907
+	/**
908
+	 * @return void
909
+	 * @deprecated 4.9.27
910
+	 */
911
+	public function get_persistent_admin_notices()
912
+	{
913
+		EE_Error::doing_it_wrong(
914
+			__METHOD__,
915
+			sprintf(
916
+				esc_html__('Usage is deprecated. Use "%1$s" instead.', 'event_espresso'),
917
+				'\EventEspresso\core\services\notifications\PersistentAdminNoticeManager'
918
+			),
919
+			'4.9.27'
920
+		);
921
+	}
922
+
923
+
924
+	/**
925
+	 * @throws InvalidInterfaceException
926
+	 * @throws InvalidDataTypeException
927
+	 * @throws DomainException
928
+	 * @deprecated 4.9.27
929
+	 */
930
+	public function dismiss_ee_nag_notice_callback()
931
+	{
932
+		EE_Error::doing_it_wrong(
933
+			__METHOD__,
934
+			sprintf(
935
+				esc_html__('Usage is deprecated. Use "%1$s" instead.', 'event_espresso'),
936
+				'\EventEspresso\core\services\notifications\PersistentAdminNoticeManager'
937
+			),
938
+			'4.9.27'
939
+		);
940
+		$this->persistent_admin_notice_manager->dismissNotice();
941
+	}
942
+
943
+
944
+	/**
945
+	 * Callback on load-plugins.php hook for setting up anything hooking into the wp plugins page.
946
+	 *
947
+	 * @throws InvalidArgumentException
948
+	 * @throws InvalidDataTypeException
949
+	 * @throws InvalidInterfaceException
950
+	 */
951
+	public function hookIntoWpPluginsPage()
952
+	{
953
+		$this->loader->getShared('EventEspresso\core\domain\services\admin\ExitModal');
954
+		$this->loader
955
+			 ->getShared('EventEspresso\core\domain\services\admin\PluginUpsells')
956
+			 ->decafUpsells();
957
+	}
958
+
959
+
960
+	/**
961
+	 * Hooks into the "post states" filter in a wp post type list table.
962
+	 *
963
+	 * @param array   $post_states
964
+	 * @param WP_Post $post
965
+	 * @return array
966
+	 * @throws InvalidArgumentException
967
+	 * @throws InvalidDataTypeException
968
+	 * @throws InvalidInterfaceException
969
+	 */
970
+	public function displayStateForCriticalPages($post_states, $post)
971
+	{
972
+		$post_states = (array) $post_states;
973
+		if (! $post instanceof WP_Post || $post->post_type !== 'page') {
974
+			return $post_states;
975
+		}
976
+		/** @var EE_Core_Config $config */
977
+		$config = $this->loader->getShared('EE_Config')->core;
978
+		if (in_array($post->ID, $config->get_critical_pages_array(), true)) {
979
+			$post_states[] = sprintf(
980
+			/* Translators: Using company name - Event Espresso Critical Page */
981
+				esc_html__('%s Critical Page', 'event_espresso'),
982
+				'Event Espresso'
983
+			);
984
+		}
985
+		return $post_states;
986
+	}
987
+
988
+
989
+	/**
990
+	 * Show documentation links on the plugins page
991
+	 *
992
+	 * @param mixed $meta Plugin Row Meta
993
+	 * @param mixed $file Plugin Base file
994
+	 * @return array
995
+	 */
996
+	public function addLinksToPluginRowMeta($meta, $file)
997
+	{
998
+		if (EE_PLUGIN_BASENAME === $file) {
999
+			$row_meta = [
1000
+				'docs' => '<a href="https://eventespresso.com/support/documentation/versioned-docs/?doc_ver=ee4"'
1001
+						  . ' aria-label="'
1002
+						  . esc_attr__('View Event Espresso documentation', 'event_espresso')
1003
+						  . '">'
1004
+						  . esc_html__('Docs', 'event_espresso')
1005
+						  . '</a>',
1006
+				'api'  => '<a href="https://github.com/eventespresso/event-espresso-core/tree/master/docs/C--REST-API"'
1007
+						  . ' aria-label="'
1008
+						  . esc_attr__('View Event Espresso API docs', 'event_espresso')
1009
+						  . '">'
1010
+						  . esc_html__('API docs', 'event_espresso')
1011
+						  . '</a>',
1012
+			];
1013
+			return array_merge($meta, $row_meta);
1014
+		}
1015
+		return (array) $meta;
1016
+	}
1017 1017
 }
Please login to merge, or discard this patch.
core/admin/EE_Admin_Hooks.core.php 2 patches
Spacing   +42 added lines, -42 removed lines patch added patch discarded remove patch
@@ -226,7 +226,7 @@  discard block
 block discarded – undo
226 226
         $this->_set_defaults();
227 227
         $this->_set_hooks_properties();
228 228
         // first let's verify we're on the right page
229
-        if (! isset($this->_req_data['page']) || $this->_req_data['page'] !== $this->_adminpage_obj->page_slug) {
229
+        if ( ! isset($this->_req_data['page']) || $this->_req_data['page'] !== $this->_adminpage_obj->page_slug) {
230 230
             return;
231 231
         }
232 232
         // get out nothing more to be done here.
@@ -274,9 +274,9 @@  discard block
 block discarded – undo
274 274
     public function enqueue_scripts_styles()
275 275
     {
276 276
 
277
-        if (! empty($this->_scripts_styles)) {
277
+        if ( ! empty($this->_scripts_styles)) {
278 278
             // first let's do all the registrations
279
-            if (! isset($this->_scripts_styles['registers'])) {
279
+            if ( ! isset($this->_scripts_styles['registers'])) {
280 280
                 $msg[] = esc_html__(
281 281
                     'There is no "registers" index in the <code>$this->_scripts_styles</code> property.',
282 282
                     'event_espresso'
@@ -286,7 +286,7 @@  discard block
 block discarded – undo
286 286
                         'Make sure you read the phpdoc comments above the definition of the $_scripts_styles property in the <code>EE_Admin_Hooks</code> class and modify according in the %s child',
287 287
                         'event_espresso'
288 288
                     ),
289
-                    '<strong>' . $this->caller . '</strong>'
289
+                    '<strong>'.$this->caller.'</strong>'
290 290
                 );
291 291
                 throw new EE_Error(implode('||', $msg));
292 292
             }
@@ -306,7 +306,7 @@  discard block
 block discarded – undo
306 306
                 $footer  = $details['footer'];
307 307
                 // let's make sure that we set the 'registers' type if it's not set!
308 308
                 // We need it later to determine which enqueue we do
309
-                $this->_scripts_styles['registers'][ $ref ]['type'] = $type;
309
+                $this->_scripts_styles['registers'][$ref]['type'] = $type;
310 310
                 // let's make sure we're not missing any REQUIRED parameters
311 311
                 if (empty($url)) {
312 312
                     $msg[] = sprintf(
@@ -318,7 +318,7 @@  discard block
 block discarded – undo
318 318
                             'Doublecheck your <code>$this->_scripts_styles</code> array in %s and make sure that there is a "url" set for the %s ref',
319 319
                             'event_espresso'
320 320
                         ),
321
-                        '<strong>' . $this->caller . '</strong>',
321
+                        '<strong>'.$this->caller.'</strong>',
322 322
                         $ref
323 323
                     );
324 324
                     throw new EE_Error(implode('||', $msg));
@@ -334,7 +334,7 @@  discard block
 block discarded – undo
334 334
                     );
335 335
             }
336 336
             // k now let's do the enqueues
337
-            if (! isset($this->_scripts_styles['enqueues'])) {
337
+            if ( ! isset($this->_scripts_styles['enqueues'])) {
338 338
                 return;
339 339
             }  //not sure if we should throw an error here or not.
340 340
 
@@ -342,22 +342,22 @@  discard block
 block discarded – undo
342 342
                 // make sure $routes is an array
343 343
                 $routes = (array) $routes;
344 344
                 if (in_array($this->_current_route, $routes)) {
345
-                    $this->_scripts_styles['registers'][ $ref ]['type'] == 'js' ? wp_enqueue_script($ref)
345
+                    $this->_scripts_styles['registers'][$ref]['type'] == 'js' ? wp_enqueue_script($ref)
346 346
                         : wp_enqueue_style($ref);
347 347
                     // if we have a localization for the script let's do that too.
348
-                    if (isset($this->_scripts_styles['localize'][ $ref ])) {
349
-                        foreach ($this->_scripts_styles['localize'][ $ref ] as $object_name => $indexes) {
348
+                    if (isset($this->_scripts_styles['localize'][$ref])) {
349
+                        foreach ($this->_scripts_styles['localize'][$ref] as $object_name => $indexes) {
350 350
                             wp_localize_script(
351 351
                                 $ref,
352 352
                                 $object_name,
353
-                                $this->_scripts_styles['localize'][ $ref ][ $object_name ]
353
+                                $this->_scripts_styles['localize'][$ref][$object_name]
354 354
                             );
355 355
                         }
356 356
                     }
357 357
                 }
358 358
             }
359 359
             // let's do the deregisters
360
-            if (! isset($this->_scripts_styles['deregisters'])) {
360
+            if ( ! isset($this->_scripts_styles['deregisters'])) {
361 361
                 return;
362 362
             }
363 363
             foreach ($this->_scripts_styles['deregisters'] as $ref => $details) {
@@ -424,20 +424,20 @@  discard block
 block discarded – undo
424 424
         // change "the_message" to "the message"
425 425
         $class_name = str_replace('_', ' ', $this->_name);
426 426
         // change "the message" to "The_Message_Admin_Page"
427
-        $class_name = str_replace(' ', '_', ucwords($class_name)) . '_Admin_Page';
427
+        $class_name = str_replace(' ', '_', ucwords($class_name)).'_Admin_Page';
428 428
         // first default file (if exists)
429
-        $decaf_file = EE_ADMIN_PAGES . $this->_name . '/' . $class_name . '.core.php';
429
+        $decaf_file = EE_ADMIN_PAGES.$this->_name.'/'.$class_name.'.core.php';
430 430
         if (is_readable($decaf_file)) {
431 431
             require_once($decaf_file);
432 432
         }
433 433
         // now we have to do require for extended file (if needed)
434 434
         if ($this->_extend) {
435
-            require_once(EE_CORE_CAF_ADMIN_EXTEND . $this->_name . '/Extend_' . $class_name . '.core.php');
435
+            require_once(EE_CORE_CAF_ADMIN_EXTEND.$this->_name.'/Extend_'.$class_name.'.core.php');
436 436
             // and extend the class name as well
437
-            $class_name = 'Extend_' . $class_name;
437
+            $class_name = 'Extend_'.$class_name;
438 438
         }
439 439
         // let's make sure the class exists
440
-        if (! class_exists($class_name)) {
440
+        if ( ! class_exists($class_name)) {
441 441
             $msg[] = esc_html__('We can\'t load the page object', 'event_espresso');
442 442
             $msg[] = sprintf(
443 443
                 esc_html__(
@@ -477,28 +477,28 @@  discard block
 block discarded – undo
477 477
         // first the actions
478 478
         // note that these action hooks will have the $query_args value available.
479 479
         $admin_class_name = get_class($this->_adminpage_obj);
480
-        if (method_exists($this, '_redirect_action_early_' . $this->_current_route)) {
480
+        if (method_exists($this, '_redirect_action_early_'.$this->_current_route)) {
481 481
             add_action(
482 482
                 'AHEE__'
483 483
                 . $admin_class_name
484 484
                 . '___redirect_after_action__before_redirect_modification_'
485 485
                 . $this->_current_route,
486
-                [$this, '_redirect_action_early_' . $this->_current_route],
486
+                [$this, '_redirect_action_early_'.$this->_current_route],
487 487
                 10
488 488
             );
489 489
         }
490
-        if (method_exists($this, '_redirect_action_' . $this->_current_route)) {
490
+        if (method_exists($this, '_redirect_action_'.$this->_current_route)) {
491 491
             add_action(
492
-                'AHEE_redirect_' . $admin_class_name . $this->_current_route,
493
-                [$this, '_redirect_action_' . $this->_current_route],
492
+                'AHEE_redirect_'.$admin_class_name.$this->_current_route,
493
+                [$this, '_redirect_action_'.$this->_current_route],
494 494
                 10
495 495
             );
496 496
         }
497 497
         // let's hook into the _redirect itself and allow for changing where the user goes after redirect.  This will have $query_args and $redirect_url available.
498
-        if (method_exists($this, '_redirect_filter_' . $this->_current_route)) {
498
+        if (method_exists($this, '_redirect_filter_'.$this->_current_route)) {
499 499
             add_filter(
500
-                'FHEE_redirect_' . $admin_class_name . $this->_current_route,
501
-                [$this, '_redirect_filter_' . $this->_current_route],
500
+                'FHEE_redirect_'.$admin_class_name.$this->_current_route,
501
+                [$this, '_redirect_filter_'.$this->_current_route],
502 502
                 10,
503 503
                 2
504 504
             );
@@ -523,12 +523,12 @@  discard block
 block discarded – undo
523 523
                 'argnum'   => 1,
524 524
                 'priority' => 10,
525 525
             ],
526
-            'FHEE_list_table_views_' . $this->_adminpage_obj->page_slug . '_' . $this->_current_route => [
526
+            'FHEE_list_table_views_'.$this->_adminpage_obj->page_slug.'_'.$this->_current_route => [
527 527
                 'type'     => 'filter',
528 528
                 'argnum'   => 1,
529 529
                 'priority' => 10,
530 530
             ],
531
-            'FHEE_list_table_views_' . $this->_adminpage_obj->page_slug                               => [
531
+            'FHEE_list_table_views_'.$this->_adminpage_obj->page_slug                               => [
532 532
                 'type'     => 'filter',
533 533
                 'argnum'   => 1,
534 534
                 'priority' => 10,
@@ -545,21 +545,21 @@  discard block
 block discarded – undo
545 545
             ],
546 546
         ];
547 547
         foreach ($hook_filter_array as $hook => $args) {
548
-            if (method_exists($this, $this->_current_route . '_' . $hook)) {
549
-                if (isset($this->_wp_action_filters_priority[ $hook ])) {
550
-                    $args['priority'] = $this->_wp_action_filters_priority[ $hook ];
548
+            if (method_exists($this, $this->_current_route.'_'.$hook)) {
549
+                if (isset($this->_wp_action_filters_priority[$hook])) {
550
+                    $args['priority'] = $this->_wp_action_filters_priority[$hook];
551 551
                 }
552 552
                 if ($args['type'] == 'action') {
553 553
                     add_action(
554 554
                         $hook,
555
-                        [$this, $this->_current_route . '_' . $hook],
555
+                        [$this, $this->_current_route.'_'.$hook],
556 556
                         $args['priority'],
557 557
                         $args['argnum']
558 558
                     );
559 559
                 } else {
560 560
                     add_filter(
561 561
                         $hook,
562
-                        [$this, $this->_current_route . '_' . $hook],
562
+                        [$this, $this->_current_route.'_'.$hook],
563 563
                         $args['priority'],
564 564
                         $args['argnum']
565 565
                     );
@@ -583,11 +583,11 @@  discard block
 block discarded – undo
583 583
         } //get out there's nothing to take care of.
584 584
         foreach ($this->_ajax_func as $action => $method) {
585 585
             // make sure method exists
586
-            if (! method_exists($this, $method)) {
586
+            if ( ! method_exists($this, $method)) {
587 587
                 $msg[] = esc_html__(
588 588
                     'There is no corresponding method for the hook labeled in the _ajax_func array',
589 589
                     'event_espresso'
590
-                ) . '<br />';
590
+                ).'<br />';
591 591
                 $msg[] = sprintf(
592 592
                     esc_html__(
593 593
                         'The method name given in the array is %s, check the spelling and make sure it exists in the %s class',
@@ -598,7 +598,7 @@  discard block
 block discarded – undo
598 598
                 );
599 599
                 throw new EE_Error(implode('||', $msg));
600 600
             }
601
-            add_action('wp_ajax_' . $action, [$this, $method]);
601
+            add_action('wp_ajax_'.$action, [$this, $method]);
602 602
         }
603 603
     }
604 604
 
@@ -618,11 +618,11 @@  discard block
 block discarded – undo
618 618
         // We need to determine what page_route we are on!
619 619
         foreach ($this->_init_func as $route => $method) {
620 620
             // make sure method exists
621
-            if (! method_exists($this, $method)) {
621
+            if ( ! method_exists($this, $method)) {
622 622
                 $msg[] = esc_html__(
623 623
                     'There is no corresponding method for the hook labeled in the _init_func array',
624 624
                     'event_espresso'
625
-                ) . '<br />';
625
+                ).'<br />';
626 626
                 $msg[] = sprintf(
627 627
                     esc_html__(
628 628
                         'The method name given in the array is %s, check the spelling and make sure it exists in the %s class',
@@ -665,7 +665,7 @@  discard block
 block discarded – undo
665 665
     {
666 666
 
667 667
         foreach ($boxes as $box) {
668
-            if (! isset($box['page_route'])) {
668
+            if ( ! isset($box['page_route'])) {
669 669
                 continue;
670 670
             }
671 671
             // we don't have a valid array
@@ -713,11 +713,11 @@  discard block
 block discarded – undo
713 713
         $screen_id      = is_object($current_screen) ? $current_screen->id : null;
714 714
         $func           = isset($args['func']) ? $args['func'] : 'some_invalid_callback';
715 715
         // set defaults
716
-        $defaults      = [
716
+        $defaults = [
717 717
             'callback_args' => [],
718 718
             'context'       => 'advanced',
719 719
             'func'          => $func,
720
-            'id'            => $this->caller . '_' . $func . '_metabox',
720
+            'id'            => $this->caller.'_'.$func.'_metabox',
721 721
             'label'         => $this->caller,
722 722
             'page'          => isset($args['page']) ? $args['page'] : $screen_id,
723 723
             'priority'      => 'default',
@@ -731,7 +731,7 @@  discard block
 block discarded – undo
731 731
         $page          = $args['page'];
732 732
         $priority      = $args['priority'];
733 733
         // make sure method exists
734
-        if (! method_exists($this, $func)) {
734
+        if ( ! method_exists($this, $func)) {
735 735
             $msg[] =
736 736
                 esc_html__('There is no corresponding method to display the metabox content', 'event_espresso')
737 737
                 . '<br />';
@@ -760,7 +760,7 @@  discard block
 block discarded – undo
760 760
             'context' => 'default',
761 761
             'id'      => isset($args['id'])
762 762
                 ? $args['id']
763
-                : $this->_current_route . '_' . $this->caller . '_' . $func . '_metabox',
763
+                : $this->_current_route.'_'.$this->caller.'_'.$func.'_metabox',
764 764
             'screen'  => isset($args['screen']) ? $args['screen'] : $screen_id,
765 765
         ];
766 766
         $args     = wp_parse_args($args, $defaults);
Please login to merge, or discard this patch.
Indentation   +754 added lines, -754 removed lines patch added patch discarded remove patch
@@ -14,758 +14,758 @@
 block discarded – undo
14 14
  */
15 15
 abstract class EE_Admin_Hooks extends EE_Base
16 16
 {
17
-    /**
18
-     * we're just going to use this to hold the name of the caller class (child class name)
19
-     *
20
-     * @var string
21
-     */
22
-    public $caller;
23
-
24
-
25
-    /**
26
-     * this is just a flag set automatically to indicate whether we've got an extended hook class running (i.e.
27
-     * espresso_events_Registration_Form_Hooks_Extend extends espresso_events_Registration_Form_Hooks).  This flag is
28
-     * used later to make sure we require the needed files.
29
-     *
30
-     * @var bool
31
-     */
32
-    protected $_extend;
33
-
34
-
35
-    /**
36
-     * child classes MUST set this property so that the page object can be loaded correctly
37
-     *
38
-     * @var string
39
-     */
40
-    protected $_name;
41
-
42
-
43
-    /**
44
-     * This is set by child classes and is an associative array of ajax hooks in the format:
45
-     * array(
46
-     *    'ajax_action_ref' => 'executing_method'; //must be public
47
-     * )
48
-     *
49
-     * @var array
50
-     */
51
-    protected $_ajax_func;
52
-
53
-
54
-    /**
55
-     * This is an array of methods that get executed on a page routes admin_init hook. Use the following format:
56
-     * array(
57
-     *    'page_route' => 'executing_method' //must be public
58
-     * )
59
-     *
60
-     * @var array
61
-     */
62
-    protected $_init_func;
63
-
64
-
65
-    /**
66
-     * This is an array of methods that output metabox content for the given page route.  Use the following format:
67
-     * [
68
-     *      0 => [
69
-     *          'page_route' => 'string_for_page_route',    must correspond to a page route in the class being connected
70
-     *                                                      with (i.e. "edit_event") If this is in an array then the
71
-     *                                                      same params below will be used but the metabox will be
72
-     *                                                      added to each route.
73
-     *          'func' =>  'executing_method',              must be public (i.e. public function executing_method
74
-     *                                                      ($post, $callback_args){} ).
75
-     *                                                      Note if you include callback args in the array then you
76
-     *                                                      need to declare them in the method arguments.
77
-     *          'id' => 'identifier_for_metabox',           so it can be removed by addons
78
-     *                                                      (optional, class will set it automatically)
79
-     *          'priority' => 'default',                    default 'default' (optional)
80
-     *          'label' => esc_html__('Localized Title', 'event_espresso'),
81
-     *          'context' => 'advanced'                     advanced is default (optional),
82
-     *      ]
83
-     *      'callback_args' => array() //any callback args to include (optional)
84
-     * ]
85
-     * Why are we indexing numerically?  Because it's possible there may be more than one metabox per page_route.
86
-     *
87
-     * @var array
88
-     */
89
-    protected $_metaboxes;
90
-
91
-
92
-    /**
93
-     * This is an array of values that indicate any metaboxes we want removed from a given page route.  Usually this is
94
-     * used when caffeinated functionality is replacing decaffeinated functionality.  Use the following format for the
95
-     * array: array(
96
-     *    0 => array(
97
-     *        'page_route' => 'string_for_page_route' //can be string or array of strings that match a page_route(s)
98
-     *        that are in the class being connected with (i.e. 'edit', or 'create_new').
99
-     *        'id' => 'identifier_for_metabox', //what the id is of the metabox being removed
100
-     *        'context' => 'normal', //the context for the metabox being removed (has to match)
101
-     *        'screen' => 'screen_id', //(optional), if not included then this class will attempt to remove the metabox
102
-     *        using the currently loaded screen object->id  however, there may be cases where you have to specify the
103
-     *        id for the screen the metabox is on.
104
-     *    )
105
-     * )
106
-     *
107
-     * @var array
108
-     */
109
-    protected $_remove_metaboxes;
110
-
111
-
112
-    /**
113
-     * This parent class takes care of loading the scripts and styles if the child class has set the properties for
114
-     * them in the following format.  Note, the first array index ('register') is for defining all the registers.  The
115
-     * second array index is for indicating what routes each script/style loads on. array(
116
-     * 'registers' => array(
117
-     *        'script_ref' => array( // if more than one script is to be loaded its best to use the 'dependency'
118
-     *        argument to link scripts together.
119
-     *            'type' => 'js' // 'js' or 'css' (defaults to js).  This tells us what type of wp_function to use
120
-     *            'url' => 'http://urltoscript.css.js',
121
-     *            'depends' => array('jquery'), //an array of dependencies for the scripts. REMEMBER, if a script has
122
-     *            already been registered elsewhere in the system.  You can just use the depends array to make sure it
123
-     *            gets loaded before the one you are setting here.
124
-     *            'footer' => TRUE //defaults to true (styles don't use this parameter)
125
-     *        ),
126
-     *    'enqueues' => array( //this time each key corresponds to the script ref followed by an array of page routes
127
-     *    the script gets enqueued on.
128
-     *        'script_ref' => array('route_one', 'route_two')
129
-     *    ),
130
-     *    'localize' => array( //this allows you to set a localized object.  Indicate which script the object is being
131
-     *    attached to and then include an array indexed by the name of the object and the array of key/value pairs for
132
-     *    the object.
133
-     *        'scrip_ref' => array(
134
-     *            'NAME_OF_JS_OBJECT' => array(
135
-     *                'translate_ref' => esc_html__('localized_string', 'event_espresso'),
136
-     *                'some_data' => 5
137
-     *            )
138
-     *        )
139
-     *    )
140
-     * )
141
-     *
142
-     * @var array
143
-     */
144
-    protected $_scripts_styles;
145
-
146
-
147
-    /**
148
-     * This is a property that will contain the current route.
149
-     *
150
-     * @var string;
151
-     */
152
-    protected $_current_route;
153
-
154
-
155
-    /**
156
-     * this optional property can be set by child classes to override the priority for the automatic action/filter hook
157
-     * loading in the `_load_routed_hooks()` method.  Please follow this format: array(
158
-     *    'wp_hook_reference' => 1
159
-     *    )
160
-     * )
161
-     *
162
-     * @var array
163
-     */
164
-    protected $_wp_action_filters_priority;
165
-
166
-
167
-    /**
168
-     * This just holds a merged array of the request vars
169
-     *
170
-     * @var array
171
-     */
172
-    protected $_req_data;
173
-
174
-    /**
175
-     * @var array
176
-     */
177
-    protected $_scripts;
178
-
179
-    /**
180
-     * @var array
181
-     */
182
-    protected $_styles;
183
-
184
-    /**
185
-     * This just holds an instance of the page object for this hook
186
-     *
187
-     * @var EE_Admin_Page
188
-     */
189
-    protected $_page_object;
190
-
191
-
192
-    /**
193
-     * This holds the EE_Admin_Page object from the calling admin page that this object hooks into.
194
-     *
195
-     * @var EE_Admin_Page|EE_Admin_Page_CPT
196
-     */
197
-    protected $_adminpage_obj;
198
-
199
-
200
-    /**
201
-     * Holds EE_Registry object
202
-     *
203
-     * @var EE_Registry
204
-     */
205
-    protected $EE = null;
206
-
207
-    /**
208
-     * @var RequestInterface
209
-     */
210
-    protected $request;
211
-
212
-
213
-    /**
214
-     * constructor
215
-     *
216
-     * @param EE_Admin_Page $admin_page
217
-     * @throws EE_Error
218
-     */
219
-    public function __construct(EE_Admin_Page $admin_page)
220
-    {
221
-        $this->_adminpage_obj = $admin_page;
222
-        $this->request        = LoaderFactory::getLoader()->getShared(RequestInterface::class);
223
-        $this->_req_data      = $this->request->requestParams();
224
-        $this->_set_defaults();
225
-        $this->_set_hooks_properties();
226
-        // first let's verify we're on the right page
227
-        if (! isset($this->_req_data['page']) || $this->_req_data['page'] !== $this->_adminpage_obj->page_slug) {
228
-            return;
229
-        }
230
-        // get out nothing more to be done here.
231
-        // allow for extends to modify properties
232
-        if (method_exists($this, '_extend_properties')) {
233
-            $this->_extend_properties();
234
-        }
235
-        $this->_set_page_object();
236
-        $this->_init_hooks();
237
-        $this->_load_custom_methods();
238
-        $this->_load_routed_hooks();
239
-        add_action('admin_enqueue_scripts', [$this, 'enqueue_scripts_styles']);
240
-        add_action('admin_enqueue_scripts', [$this, 'add_metaboxes'], 20);
241
-        add_action('admin_enqueue_scripts', [$this, 'remove_metaboxes'], 15);
242
-        $this->_ajax_hooks();
243
-    }
244
-
245
-
246
-    /**
247
-     * used by child classes to set the following properties:
248
-     * $_ajax_func (optional)
249
-     * $_init_func (optional)
250
-     * $_metaboxes (optional)
251
-     * $_scripts (optional)
252
-     * $_styles (optional)
253
-     * $_name (required)
254
-     * Also in this method will be registered any scripts or styles loaded on the targeted page (as indicated in the
255
-     * _scripts/_styles properties) Also children should place in this method any filters/actions that have to happen
256
-     * really early on page load (just after admin_init) if they want to have them registered for handling early.
257
-     *
258
-     * @abstract
259
-     * @return void
260
-     */
261
-    abstract protected function _set_hooks_properties();
262
-
263
-
264
-    /**
265
-     * The hooks for enqueue_scripts and enqueue_styles will be run in here.  Child classes need to define their
266
-     * scripts and styles in the relevant $_scripts and $_styles properties.  Child classes must have also already
267
-     * registered the scripts and styles using wp_register_script and wp_register_style functions.
268
-     *
269
-     * @return void
270
-     * @throws EE_Error
271
-     */
272
-    public function enqueue_scripts_styles()
273
-    {
274
-
275
-        if (! empty($this->_scripts_styles)) {
276
-            // first let's do all the registrations
277
-            if (! isset($this->_scripts_styles['registers'])) {
278
-                $msg[] = esc_html__(
279
-                    'There is no "registers" index in the <code>$this->_scripts_styles</code> property.',
280
-                    'event_espresso'
281
-                );
282
-                $msg[] = sprintf(
283
-                    esc_html__(
284
-                        'Make sure you read the phpdoc comments above the definition of the $_scripts_styles property in the <code>EE_Admin_Hooks</code> class and modify according in the %s child',
285
-                        'event_espresso'
286
-                    ),
287
-                    '<strong>' . $this->caller . '</strong>'
288
-                );
289
-                throw new EE_Error(implode('||', $msg));
290
-            }
291
-            $defaults = [
292
-                'type'    => 'js',
293
-                'url'     => '',
294
-                'depends' => [],
295
-                'version' => EVENT_ESPRESSO_VERSION,
296
-                'footer'  => true,
297
-            ];
298
-            foreach ($this->_scripts_styles['registers'] as $ref => $details) {
299
-                $details = wp_parse_args($details, $defaults);
300
-                $type    = $details['type'];
301
-                $url     = $details['url'];
302
-                $depends = $details['depends'];
303
-                $version = $details['version'];
304
-                $footer  = $details['footer'];
305
-                // let's make sure that we set the 'registers' type if it's not set!
306
-                // We need it later to determine which enqueue we do
307
-                $this->_scripts_styles['registers'][ $ref ]['type'] = $type;
308
-                // let's make sure we're not missing any REQUIRED parameters
309
-                if (empty($url)) {
310
-                    $msg[] = sprintf(
311
-                        esc_html__('Missing the url for the requested %s', 'event_espresso'),
312
-                        $type == 'js' ? 'script' : 'stylesheet'
313
-                    );
314
-                    $msg[] = sprintf(
315
-                        esc_html__(
316
-                            'Doublecheck your <code>$this->_scripts_styles</code> array in %s and make sure that there is a "url" set for the %s ref',
317
-                            'event_espresso'
318
-                        ),
319
-                        '<strong>' . $this->caller . '</strong>',
320
-                        $ref
321
-                    );
322
-                    throw new EE_Error(implode('||', $msg));
323
-                }
324
-                // made it here so let's do the appropriate registration
325
-                $type == 'js'
326
-                    ? wp_register_script($ref, $url, $depends, $version, $footer)
327
-                    : wp_register_style(
328
-                        $ref,
329
-                        $url,
330
-                        $depends,
331
-                        $version
332
-                    );
333
-            }
334
-            // k now let's do the enqueues
335
-            if (! isset($this->_scripts_styles['enqueues'])) {
336
-                return;
337
-            }  //not sure if we should throw an error here or not.
338
-
339
-            foreach ($this->_scripts_styles['enqueues'] as $ref => $routes) {
340
-                // make sure $routes is an array
341
-                $routes = (array) $routes;
342
-                if (in_array($this->_current_route, $routes)) {
343
-                    $this->_scripts_styles['registers'][ $ref ]['type'] == 'js' ? wp_enqueue_script($ref)
344
-                        : wp_enqueue_style($ref);
345
-                    // if we have a localization for the script let's do that too.
346
-                    if (isset($this->_scripts_styles['localize'][ $ref ])) {
347
-                        foreach ($this->_scripts_styles['localize'][ $ref ] as $object_name => $indexes) {
348
-                            wp_localize_script(
349
-                                $ref,
350
-                                $object_name,
351
-                                $this->_scripts_styles['localize'][ $ref ][ $object_name ]
352
-                            );
353
-                        }
354
-                    }
355
-                }
356
-            }
357
-            // let's do the deregisters
358
-            if (! isset($this->_scripts_styles['deregisters'])) {
359
-                return;
360
-            }
361
-            foreach ($this->_scripts_styles['deregisters'] as $ref => $details) {
362
-                $defaults = ['type' => 'js'];
363
-                $details  = wp_parse_args($details, $defaults);
364
-                $details['type'] === 'js' ? wp_deregister_script($ref) : wp_deregister_style($ref);
365
-            }
366
-        }
367
-    }
368
-
369
-
370
-    /**
371
-     * just set the defaults for the hooks properties.
372
-     *
373
-     * @return void
374
-     */
375
-    private function _set_defaults()
376
-    {
377
-        $this->_ajax_func                  = [];
378
-        $this->_init_func                  = [];
379
-        $this->_metaboxes                  = [];
380
-        $this->_scripts                    = [];
381
-        $this->_styles                     = [];
382
-        $this->_wp_action_filters_priority = [];
383
-        $this->_current_route              = $this->getCurrentRoute();
384
-        $this->caller                      = get_class($this);
385
-        $this->_extend                     = (bool) stripos($this->caller, 'Extend');
386
-    }
387
-
388
-
389
-    /**
390
-     * A helper for determining the current route.
391
-     *
392
-     * @return string
393
-     */
394
-    private function getCurrentRoute()
395
-    {
396
-        $action = $this->request->getRequestParam('action');
397
-        // list tables do something else with 'action' for bulk actions.
398
-        $action = $action !== '-1' && $action !== '' ? $action : 'default';
399
-        $route  = $this->request->getRequestParam('route');
400
-        // we set a 'route' variable in some cases where action is being used by something else.
401
-        return $action === 'default' && $route !== '' ? $route : $action;
402
-    }
403
-
404
-
405
-    /**
406
-     * this sets the _page_object property
407
-     *
408
-     * @return void
409
-     * @throws EE_Error
410
-     */
411
-    protected function _set_page_object()
412
-    {
413
-        // first make sure $this->_name is set
414
-        if (empty($this->_name)) {
415
-            $msg[] = esc_html__('We can\'t load the page object', 'event_espresso');
416
-            $msg[] = sprintf(
417
-                esc_html__("This is because the %s child class has not set the '_name' property", 'event_espresso'),
418
-                $this->caller
419
-            );
420
-            throw new EE_Error(implode('||', $msg));
421
-        }
422
-        // change "the_message" to "the message"
423
-        $class_name = str_replace('_', ' ', $this->_name);
424
-        // change "the message" to "The_Message_Admin_Page"
425
-        $class_name = str_replace(' ', '_', ucwords($class_name)) . '_Admin_Page';
426
-        // first default file (if exists)
427
-        $decaf_file = EE_ADMIN_PAGES . $this->_name . '/' . $class_name . '.core.php';
428
-        if (is_readable($decaf_file)) {
429
-            require_once($decaf_file);
430
-        }
431
-        // now we have to do require for extended file (if needed)
432
-        if ($this->_extend) {
433
-            require_once(EE_CORE_CAF_ADMIN_EXTEND . $this->_name . '/Extend_' . $class_name . '.core.php');
434
-            // and extend the class name as well
435
-            $class_name = 'Extend_' . $class_name;
436
-        }
437
-        // let's make sure the class exists
438
-        if (! class_exists($class_name)) {
439
-            $msg[] = esc_html__('We can\'t load the page object', 'event_espresso');
440
-            $msg[] = sprintf(
441
-                esc_html__(
442
-                    'The class name that was given is %s. Check the spelling and make sure its correct, also there needs to be an autoloader setup for the class',
443
-                    'event_espresso'
444
-                ),
445
-                $class_name
446
-            );
447
-            throw new EE_Error(implode('||', $msg));
448
-        }
449
-        $this->_page_object = LoaderFactory::getLoader()->getShared($class_name, [false]);
450
-    }
451
-
452
-
453
-    /**
454
-     * Child "hook" classes can declare any methods that they want executed when a specific page route is loaded.  The
455
-     * advantage of this is when doing things like running our own db interactions on saves etc.  Remember that
456
-     * $this->_req_data (all the _POST and _GET data) is available to your methods.
457
-     *
458
-     * @return void
459
-     */
460
-    private function _load_custom_methods()
461
-    {
462
-        /**
463
-         * method cannot be named 'default' (@see http://us3.php
464
-         * .net/manual/en/reserved.keywords.php) so need to
465
-         * handle routes that are "default"
466
-         *
467
-         * @since 4.3.0
468
-         */
469
-        $method_callback = $this->_current_route == 'default' ? 'default_callback' : $this->_current_route;
470
-        // these run before the Admin_Page route executes.
471
-        if (method_exists($this, $method_callback)) {
472
-            call_user_func([$this, $method_callback]);
473
-        }
474
-        // these run via the _redirect_after_action method in EE_Admin_Page which usually happens after non_UI methods in EE_Admin_Page classes.  There are two redirect actions, the first fires before $query_args might be manipulated by "save and close" actions and the seond fires right before the actual redirect happens.
475
-        // first the actions
476
-        // note that these action hooks will have the $query_args value available.
477
-        $admin_class_name = get_class($this->_adminpage_obj);
478
-        if (method_exists($this, '_redirect_action_early_' . $this->_current_route)) {
479
-            add_action(
480
-                'AHEE__'
481
-                . $admin_class_name
482
-                . '___redirect_after_action__before_redirect_modification_'
483
-                . $this->_current_route,
484
-                [$this, '_redirect_action_early_' . $this->_current_route],
485
-                10
486
-            );
487
-        }
488
-        if (method_exists($this, '_redirect_action_' . $this->_current_route)) {
489
-            add_action(
490
-                'AHEE_redirect_' . $admin_class_name . $this->_current_route,
491
-                [$this, '_redirect_action_' . $this->_current_route],
492
-                10
493
-            );
494
-        }
495
-        // let's hook into the _redirect itself and allow for changing where the user goes after redirect.  This will have $query_args and $redirect_url available.
496
-        if (method_exists($this, '_redirect_filter_' . $this->_current_route)) {
497
-            add_filter(
498
-                'FHEE_redirect_' . $admin_class_name . $this->_current_route,
499
-                [$this, '_redirect_filter_' . $this->_current_route],
500
-                10,
501
-                2
502
-            );
503
-        }
504
-    }
505
-
506
-
507
-    /**
508
-     * This method will search for a corresponding method with a name matching the route and the wp_hook to run.  This
509
-     * allows child hook classes to target hooking into a specific wp action or filter hook ONLY on a certain route.
510
-     * just remember, methods MUST be public Future hooks should be added in here to be access by child classes.
511
-     *
512
-     * @return void
513
-     */
514
-    private function _load_routed_hooks()
515
-    {
516
-
517
-        // this array provides the hook action names that will be referenced.  Key is the action. Value is an array with the type (action or filter) and the number of parameters for the hook.  We'll default all priorities for automatic hooks to 10.
518
-        $hook_filter_array = [
519
-            'admin_footer'                                                                            => [
520
-                'type'     => 'action',
521
-                'argnum'   => 1,
522
-                'priority' => 10,
523
-            ],
524
-            'FHEE_list_table_views_' . $this->_adminpage_obj->page_slug . '_' . $this->_current_route => [
525
-                'type'     => 'filter',
526
-                'argnum'   => 1,
527
-                'priority' => 10,
528
-            ],
529
-            'FHEE_list_table_views_' . $this->_adminpage_obj->page_slug                               => [
530
-                'type'     => 'filter',
531
-                'argnum'   => 1,
532
-                'priority' => 10,
533
-            ],
534
-            'FHEE_list_table_views'                                                                   => [
535
-                'type'     => 'filter',
536
-                'argnum'   => 1,
537
-                'priority' => 10,
538
-            ],
539
-            'AHEE__EE_Admin_Page___display_admin_page__modify_metaboxes'                              => [
540
-                'type'     => 'action',
541
-                'argnum'   => 1,
542
-                'priority' => 10,
543
-            ],
544
-        ];
545
-        foreach ($hook_filter_array as $hook => $args) {
546
-            if (method_exists($this, $this->_current_route . '_' . $hook)) {
547
-                if (isset($this->_wp_action_filters_priority[ $hook ])) {
548
-                    $args['priority'] = $this->_wp_action_filters_priority[ $hook ];
549
-                }
550
-                if ($args['type'] == 'action') {
551
-                    add_action(
552
-                        $hook,
553
-                        [$this, $this->_current_route . '_' . $hook],
554
-                        $args['priority'],
555
-                        $args['argnum']
556
-                    );
557
-                } else {
558
-                    add_filter(
559
-                        $hook,
560
-                        [$this, $this->_current_route . '_' . $hook],
561
-                        $args['priority'],
562
-                        $args['argnum']
563
-                    );
564
-                }
565
-            }
566
-        }
567
-    }
568
-
569
-
570
-    /**
571
-     * Loop throught the $_ajax_func array and add_actions for the array.
572
-     *
573
-     * @return void
574
-     * @throws EE_Error
575
-     */
576
-    private function _ajax_hooks()
577
-    {
578
-
579
-        if (empty($this->_ajax_func)) {
580
-            return;
581
-        } //get out there's nothing to take care of.
582
-        foreach ($this->_ajax_func as $action => $method) {
583
-            // make sure method exists
584
-            if (! method_exists($this, $method)) {
585
-                $msg[] = esc_html__(
586
-                    'There is no corresponding method for the hook labeled in the _ajax_func array',
587
-                    'event_espresso'
588
-                ) . '<br />';
589
-                $msg[] = sprintf(
590
-                    esc_html__(
591
-                        'The method name given in the array is %s, check the spelling and make sure it exists in the %s class',
592
-                        'event_espresso'
593
-                    ),
594
-                    $method,
595
-                    $this->caller
596
-                );
597
-                throw new EE_Error(implode('||', $msg));
598
-            }
599
-            add_action('wp_ajax_' . $action, [$this, $method]);
600
-        }
601
-    }
602
-
603
-
604
-    /**
605
-     * Loop throught the $_init_func array and add_actions for the array.
606
-     *
607
-     * @return void
608
-     * @throws EE_Error
609
-     */
610
-    protected function _init_hooks()
611
-    {
612
-        if (empty($this->_init_func)) {
613
-            return;
614
-        }
615
-        // get out there's nothing to take care of.
616
-        // We need to determine what page_route we are on!
617
-        foreach ($this->_init_func as $route => $method) {
618
-            // make sure method exists
619
-            if (! method_exists($this, $method)) {
620
-                $msg[] = esc_html__(
621
-                    'There is no corresponding method for the hook labeled in the _init_func array',
622
-                    'event_espresso'
623
-                ) . '<br />';
624
-                $msg[] = sprintf(
625
-                    esc_html__(
626
-                        'The method name given in the array is %s, check the spelling and make sure it exists in the %s class',
627
-                        'event_espresso'
628
-                    ),
629
-                    $method,
630
-                    $this->caller
631
-                );
632
-                throw new EE_Error(implode('||', $msg));
633
-            }
634
-            if ($route == $this->_current_route) {
635
-                add_action('admin_init', [$this, $method]);
636
-            }
637
-        }
638
-    }
639
-
640
-
641
-    /**
642
-     * Loop through the _metaboxes property and add_metaboxes accordingly
643
-     * //todo we could eventually make this a config component class (i.e. new EE_Metabox);
644
-     *
645
-     * @return void
646
-     * @throws EE_Error
647
-     */
648
-    public function add_metaboxes()
649
-    {
650
-        if (empty($this->_metaboxes)) {
651
-            return;
652
-        } //get out we don't have any metaboxes to set for this connection
653
-        $this->_handle_metabox_array($this->_metaboxes);
654
-    }
655
-
656
-
657
-    /**
658
-     * @param array $boxes
659
-     * @param bool  $add
660
-     * @throws EE_Error
661
-     */
662
-    private function _handle_metabox_array(array $boxes, $add = true)
663
-    {
664
-
665
-        foreach ($boxes as $box) {
666
-            if (! isset($box['page_route'])) {
667
-                continue;
668
-            }
669
-            // we don't have a valid array
670
-            // let's make sure $box['page_route'] is an array so the "foreach" will work.
671
-            $box['page_route'] = (array) $box['page_route'];
672
-            foreach ($box['page_route'] as $route) {
673
-                if ($route != $this->_current_route) {
674
-                    continue;
675
-                } //get out we only add metaboxes for set route.
676
-                if ($add) {
677
-                    $this->_add_metabox($box);
678
-                } else {
679
-                    $this->_remove_metabox($box);
680
-                }
681
-            }
682
-        }
683
-    }
684
-
685
-
686
-    /**
687
-     * Loop through the _remove_metaboxes property and remove metaboxes accordingly.
688
-     *
689
-     * @return void
690
-     * @throws EE_Error
691
-     */
692
-    public function remove_metaboxes()
693
-    {
694
-
695
-        if (empty($this->_remove_metaboxes)) {
696
-            return;
697
-        } //get out there are no metaboxes to remove
698
-        $this->_handle_metabox_array($this->_remove_metaboxes, false);
699
-    }
700
-
701
-
702
-    /**
703
-     * This just handles adding a metabox
704
-     *
705
-     * @param array $args an array of args that have been set for this metabox by the child class
706
-     * @throws EE_Error
707
-     */
708
-    private function _add_metabox($args)
709
-    {
710
-        $current_screen = get_current_screen();
711
-        $screen_id      = is_object($current_screen) ? $current_screen->id : null;
712
-        $func           = isset($args['func']) ? $args['func'] : 'some_invalid_callback';
713
-        // set defaults
714
-        $defaults      = [
715
-            'callback_args' => [],
716
-            'context'       => 'advanced',
717
-            'func'          => $func,
718
-            'id'            => $this->caller . '_' . $func . '_metabox',
719
-            'label'         => $this->caller,
720
-            'page'          => isset($args['page']) ? $args['page'] : $screen_id,
721
-            'priority'      => 'default',
722
-        ];
723
-        $args          = wp_parse_args($args, $defaults);
724
-        $callback_args = $args['callback_args'];
725
-        $context       = $args['context'];
726
-        $func          = $args['func'];
727
-        $id            = $args['id'];
728
-        $label         = $args['label'];
729
-        $page          = $args['page'];
730
-        $priority      = $args['priority'];
731
-        // make sure method exists
732
-        if (! method_exists($this, $func)) {
733
-            $msg[] =
734
-                esc_html__('There is no corresponding method to display the metabox content', 'event_espresso')
735
-                . '<br />';
736
-            $msg[] = sprintf(
737
-                esc_html__(
738
-                    'The method name given in the array is %s, check the spelling and make sure it exists in the %s class',
739
-                    'event_espresso'
740
-                ),
741
-                $func,
742
-                $this->caller
743
-            );
744
-            throw new EE_Error(implode('||', $msg));
745
-        }
746
-        // everything checks out so let's add the metabox
747
-        add_meta_box($id, $label, [$this, $func], $page, $context, $priority, $callback_args);
748
-    }
749
-
750
-
751
-    private function _remove_metabox($args)
752
-    {
753
-        $current_screen = get_current_screen();
754
-        $screen_id      = is_object($current_screen) ? $current_screen->id : null;
755
-        $func           = isset($args['func']) ? $args['func'] : 'some_invalid_callback';
756
-        // set defaults
757
-        $defaults = [
758
-            'context' => 'default',
759
-            'id'      => isset($args['id'])
760
-                ? $args['id']
761
-                : $this->_current_route . '_' . $this->caller . '_' . $func . '_metabox',
762
-            'screen'  => isset($args['screen']) ? $args['screen'] : $screen_id,
763
-        ];
764
-        $args     = wp_parse_args($args, $defaults);
765
-        $context  = $args['context'];
766
-        $id       = $args['id'];
767
-        $screen   = $args['screen'];
768
-        // everything checks out so lets remove the box!
769
-        remove_meta_box($id, $screen, $context);
770
-    }
17
+	/**
18
+	 * we're just going to use this to hold the name of the caller class (child class name)
19
+	 *
20
+	 * @var string
21
+	 */
22
+	public $caller;
23
+
24
+
25
+	/**
26
+	 * this is just a flag set automatically to indicate whether we've got an extended hook class running (i.e.
27
+	 * espresso_events_Registration_Form_Hooks_Extend extends espresso_events_Registration_Form_Hooks).  This flag is
28
+	 * used later to make sure we require the needed files.
29
+	 *
30
+	 * @var bool
31
+	 */
32
+	protected $_extend;
33
+
34
+
35
+	/**
36
+	 * child classes MUST set this property so that the page object can be loaded correctly
37
+	 *
38
+	 * @var string
39
+	 */
40
+	protected $_name;
41
+
42
+
43
+	/**
44
+	 * This is set by child classes and is an associative array of ajax hooks in the format:
45
+	 * array(
46
+	 *    'ajax_action_ref' => 'executing_method'; //must be public
47
+	 * )
48
+	 *
49
+	 * @var array
50
+	 */
51
+	protected $_ajax_func;
52
+
53
+
54
+	/**
55
+	 * This is an array of methods that get executed on a page routes admin_init hook. Use the following format:
56
+	 * array(
57
+	 *    'page_route' => 'executing_method' //must be public
58
+	 * )
59
+	 *
60
+	 * @var array
61
+	 */
62
+	protected $_init_func;
63
+
64
+
65
+	/**
66
+	 * This is an array of methods that output metabox content for the given page route.  Use the following format:
67
+	 * [
68
+	 *      0 => [
69
+	 *          'page_route' => 'string_for_page_route',    must correspond to a page route in the class being connected
70
+	 *                                                      with (i.e. "edit_event") If this is in an array then the
71
+	 *                                                      same params below will be used but the metabox will be
72
+	 *                                                      added to each route.
73
+	 *          'func' =>  'executing_method',              must be public (i.e. public function executing_method
74
+	 *                                                      ($post, $callback_args){} ).
75
+	 *                                                      Note if you include callback args in the array then you
76
+	 *                                                      need to declare them in the method arguments.
77
+	 *          'id' => 'identifier_for_metabox',           so it can be removed by addons
78
+	 *                                                      (optional, class will set it automatically)
79
+	 *          'priority' => 'default',                    default 'default' (optional)
80
+	 *          'label' => esc_html__('Localized Title', 'event_espresso'),
81
+	 *          'context' => 'advanced'                     advanced is default (optional),
82
+	 *      ]
83
+	 *      'callback_args' => array() //any callback args to include (optional)
84
+	 * ]
85
+	 * Why are we indexing numerically?  Because it's possible there may be more than one metabox per page_route.
86
+	 *
87
+	 * @var array
88
+	 */
89
+	protected $_metaboxes;
90
+
91
+
92
+	/**
93
+	 * This is an array of values that indicate any metaboxes we want removed from a given page route.  Usually this is
94
+	 * used when caffeinated functionality is replacing decaffeinated functionality.  Use the following format for the
95
+	 * array: array(
96
+	 *    0 => array(
97
+	 *        'page_route' => 'string_for_page_route' //can be string or array of strings that match a page_route(s)
98
+	 *        that are in the class being connected with (i.e. 'edit', or 'create_new').
99
+	 *        'id' => 'identifier_for_metabox', //what the id is of the metabox being removed
100
+	 *        'context' => 'normal', //the context for the metabox being removed (has to match)
101
+	 *        'screen' => 'screen_id', //(optional), if not included then this class will attempt to remove the metabox
102
+	 *        using the currently loaded screen object->id  however, there may be cases where you have to specify the
103
+	 *        id for the screen the metabox is on.
104
+	 *    )
105
+	 * )
106
+	 *
107
+	 * @var array
108
+	 */
109
+	protected $_remove_metaboxes;
110
+
111
+
112
+	/**
113
+	 * This parent class takes care of loading the scripts and styles if the child class has set the properties for
114
+	 * them in the following format.  Note, the first array index ('register') is for defining all the registers.  The
115
+	 * second array index is for indicating what routes each script/style loads on. array(
116
+	 * 'registers' => array(
117
+	 *        'script_ref' => array( // if more than one script is to be loaded its best to use the 'dependency'
118
+	 *        argument to link scripts together.
119
+	 *            'type' => 'js' // 'js' or 'css' (defaults to js).  This tells us what type of wp_function to use
120
+	 *            'url' => 'http://urltoscript.css.js',
121
+	 *            'depends' => array('jquery'), //an array of dependencies for the scripts. REMEMBER, if a script has
122
+	 *            already been registered elsewhere in the system.  You can just use the depends array to make sure it
123
+	 *            gets loaded before the one you are setting here.
124
+	 *            'footer' => TRUE //defaults to true (styles don't use this parameter)
125
+	 *        ),
126
+	 *    'enqueues' => array( //this time each key corresponds to the script ref followed by an array of page routes
127
+	 *    the script gets enqueued on.
128
+	 *        'script_ref' => array('route_one', 'route_two')
129
+	 *    ),
130
+	 *    'localize' => array( //this allows you to set a localized object.  Indicate which script the object is being
131
+	 *    attached to and then include an array indexed by the name of the object and the array of key/value pairs for
132
+	 *    the object.
133
+	 *        'scrip_ref' => array(
134
+	 *            'NAME_OF_JS_OBJECT' => array(
135
+	 *                'translate_ref' => esc_html__('localized_string', 'event_espresso'),
136
+	 *                'some_data' => 5
137
+	 *            )
138
+	 *        )
139
+	 *    )
140
+	 * )
141
+	 *
142
+	 * @var array
143
+	 */
144
+	protected $_scripts_styles;
145
+
146
+
147
+	/**
148
+	 * This is a property that will contain the current route.
149
+	 *
150
+	 * @var string;
151
+	 */
152
+	protected $_current_route;
153
+
154
+
155
+	/**
156
+	 * this optional property can be set by child classes to override the priority for the automatic action/filter hook
157
+	 * loading in the `_load_routed_hooks()` method.  Please follow this format: array(
158
+	 *    'wp_hook_reference' => 1
159
+	 *    )
160
+	 * )
161
+	 *
162
+	 * @var array
163
+	 */
164
+	protected $_wp_action_filters_priority;
165
+
166
+
167
+	/**
168
+	 * This just holds a merged array of the request vars
169
+	 *
170
+	 * @var array
171
+	 */
172
+	protected $_req_data;
173
+
174
+	/**
175
+	 * @var array
176
+	 */
177
+	protected $_scripts;
178
+
179
+	/**
180
+	 * @var array
181
+	 */
182
+	protected $_styles;
183
+
184
+	/**
185
+	 * This just holds an instance of the page object for this hook
186
+	 *
187
+	 * @var EE_Admin_Page
188
+	 */
189
+	protected $_page_object;
190
+
191
+
192
+	/**
193
+	 * This holds the EE_Admin_Page object from the calling admin page that this object hooks into.
194
+	 *
195
+	 * @var EE_Admin_Page|EE_Admin_Page_CPT
196
+	 */
197
+	protected $_adminpage_obj;
198
+
199
+
200
+	/**
201
+	 * Holds EE_Registry object
202
+	 *
203
+	 * @var EE_Registry
204
+	 */
205
+	protected $EE = null;
206
+
207
+	/**
208
+	 * @var RequestInterface
209
+	 */
210
+	protected $request;
211
+
212
+
213
+	/**
214
+	 * constructor
215
+	 *
216
+	 * @param EE_Admin_Page $admin_page
217
+	 * @throws EE_Error
218
+	 */
219
+	public function __construct(EE_Admin_Page $admin_page)
220
+	{
221
+		$this->_adminpage_obj = $admin_page;
222
+		$this->request        = LoaderFactory::getLoader()->getShared(RequestInterface::class);
223
+		$this->_req_data      = $this->request->requestParams();
224
+		$this->_set_defaults();
225
+		$this->_set_hooks_properties();
226
+		// first let's verify we're on the right page
227
+		if (! isset($this->_req_data['page']) || $this->_req_data['page'] !== $this->_adminpage_obj->page_slug) {
228
+			return;
229
+		}
230
+		// get out nothing more to be done here.
231
+		// allow for extends to modify properties
232
+		if (method_exists($this, '_extend_properties')) {
233
+			$this->_extend_properties();
234
+		}
235
+		$this->_set_page_object();
236
+		$this->_init_hooks();
237
+		$this->_load_custom_methods();
238
+		$this->_load_routed_hooks();
239
+		add_action('admin_enqueue_scripts', [$this, 'enqueue_scripts_styles']);
240
+		add_action('admin_enqueue_scripts', [$this, 'add_metaboxes'], 20);
241
+		add_action('admin_enqueue_scripts', [$this, 'remove_metaboxes'], 15);
242
+		$this->_ajax_hooks();
243
+	}
244
+
245
+
246
+	/**
247
+	 * used by child classes to set the following properties:
248
+	 * $_ajax_func (optional)
249
+	 * $_init_func (optional)
250
+	 * $_metaboxes (optional)
251
+	 * $_scripts (optional)
252
+	 * $_styles (optional)
253
+	 * $_name (required)
254
+	 * Also in this method will be registered any scripts or styles loaded on the targeted page (as indicated in the
255
+	 * _scripts/_styles properties) Also children should place in this method any filters/actions that have to happen
256
+	 * really early on page load (just after admin_init) if they want to have them registered for handling early.
257
+	 *
258
+	 * @abstract
259
+	 * @return void
260
+	 */
261
+	abstract protected function _set_hooks_properties();
262
+
263
+
264
+	/**
265
+	 * The hooks for enqueue_scripts and enqueue_styles will be run in here.  Child classes need to define their
266
+	 * scripts and styles in the relevant $_scripts and $_styles properties.  Child classes must have also already
267
+	 * registered the scripts and styles using wp_register_script and wp_register_style functions.
268
+	 *
269
+	 * @return void
270
+	 * @throws EE_Error
271
+	 */
272
+	public function enqueue_scripts_styles()
273
+	{
274
+
275
+		if (! empty($this->_scripts_styles)) {
276
+			// first let's do all the registrations
277
+			if (! isset($this->_scripts_styles['registers'])) {
278
+				$msg[] = esc_html__(
279
+					'There is no "registers" index in the <code>$this->_scripts_styles</code> property.',
280
+					'event_espresso'
281
+				);
282
+				$msg[] = sprintf(
283
+					esc_html__(
284
+						'Make sure you read the phpdoc comments above the definition of the $_scripts_styles property in the <code>EE_Admin_Hooks</code> class and modify according in the %s child',
285
+						'event_espresso'
286
+					),
287
+					'<strong>' . $this->caller . '</strong>'
288
+				);
289
+				throw new EE_Error(implode('||', $msg));
290
+			}
291
+			$defaults = [
292
+				'type'    => 'js',
293
+				'url'     => '',
294
+				'depends' => [],
295
+				'version' => EVENT_ESPRESSO_VERSION,
296
+				'footer'  => true,
297
+			];
298
+			foreach ($this->_scripts_styles['registers'] as $ref => $details) {
299
+				$details = wp_parse_args($details, $defaults);
300
+				$type    = $details['type'];
301
+				$url     = $details['url'];
302
+				$depends = $details['depends'];
303
+				$version = $details['version'];
304
+				$footer  = $details['footer'];
305
+				// let's make sure that we set the 'registers' type if it's not set!
306
+				// We need it later to determine which enqueue we do
307
+				$this->_scripts_styles['registers'][ $ref ]['type'] = $type;
308
+				// let's make sure we're not missing any REQUIRED parameters
309
+				if (empty($url)) {
310
+					$msg[] = sprintf(
311
+						esc_html__('Missing the url for the requested %s', 'event_espresso'),
312
+						$type == 'js' ? 'script' : 'stylesheet'
313
+					);
314
+					$msg[] = sprintf(
315
+						esc_html__(
316
+							'Doublecheck your <code>$this->_scripts_styles</code> array in %s and make sure that there is a "url" set for the %s ref',
317
+							'event_espresso'
318
+						),
319
+						'<strong>' . $this->caller . '</strong>',
320
+						$ref
321
+					);
322
+					throw new EE_Error(implode('||', $msg));
323
+				}
324
+				// made it here so let's do the appropriate registration
325
+				$type == 'js'
326
+					? wp_register_script($ref, $url, $depends, $version, $footer)
327
+					: wp_register_style(
328
+						$ref,
329
+						$url,
330
+						$depends,
331
+						$version
332
+					);
333
+			}
334
+			// k now let's do the enqueues
335
+			if (! isset($this->_scripts_styles['enqueues'])) {
336
+				return;
337
+			}  //not sure if we should throw an error here or not.
338
+
339
+			foreach ($this->_scripts_styles['enqueues'] as $ref => $routes) {
340
+				// make sure $routes is an array
341
+				$routes = (array) $routes;
342
+				if (in_array($this->_current_route, $routes)) {
343
+					$this->_scripts_styles['registers'][ $ref ]['type'] == 'js' ? wp_enqueue_script($ref)
344
+						: wp_enqueue_style($ref);
345
+					// if we have a localization for the script let's do that too.
346
+					if (isset($this->_scripts_styles['localize'][ $ref ])) {
347
+						foreach ($this->_scripts_styles['localize'][ $ref ] as $object_name => $indexes) {
348
+							wp_localize_script(
349
+								$ref,
350
+								$object_name,
351
+								$this->_scripts_styles['localize'][ $ref ][ $object_name ]
352
+							);
353
+						}
354
+					}
355
+				}
356
+			}
357
+			// let's do the deregisters
358
+			if (! isset($this->_scripts_styles['deregisters'])) {
359
+				return;
360
+			}
361
+			foreach ($this->_scripts_styles['deregisters'] as $ref => $details) {
362
+				$defaults = ['type' => 'js'];
363
+				$details  = wp_parse_args($details, $defaults);
364
+				$details['type'] === 'js' ? wp_deregister_script($ref) : wp_deregister_style($ref);
365
+			}
366
+		}
367
+	}
368
+
369
+
370
+	/**
371
+	 * just set the defaults for the hooks properties.
372
+	 *
373
+	 * @return void
374
+	 */
375
+	private function _set_defaults()
376
+	{
377
+		$this->_ajax_func                  = [];
378
+		$this->_init_func                  = [];
379
+		$this->_metaboxes                  = [];
380
+		$this->_scripts                    = [];
381
+		$this->_styles                     = [];
382
+		$this->_wp_action_filters_priority = [];
383
+		$this->_current_route              = $this->getCurrentRoute();
384
+		$this->caller                      = get_class($this);
385
+		$this->_extend                     = (bool) stripos($this->caller, 'Extend');
386
+	}
387
+
388
+
389
+	/**
390
+	 * A helper for determining the current route.
391
+	 *
392
+	 * @return string
393
+	 */
394
+	private function getCurrentRoute()
395
+	{
396
+		$action = $this->request->getRequestParam('action');
397
+		// list tables do something else with 'action' for bulk actions.
398
+		$action = $action !== '-1' && $action !== '' ? $action : 'default';
399
+		$route  = $this->request->getRequestParam('route');
400
+		// we set a 'route' variable in some cases where action is being used by something else.
401
+		return $action === 'default' && $route !== '' ? $route : $action;
402
+	}
403
+
404
+
405
+	/**
406
+	 * this sets the _page_object property
407
+	 *
408
+	 * @return void
409
+	 * @throws EE_Error
410
+	 */
411
+	protected function _set_page_object()
412
+	{
413
+		// first make sure $this->_name is set
414
+		if (empty($this->_name)) {
415
+			$msg[] = esc_html__('We can\'t load the page object', 'event_espresso');
416
+			$msg[] = sprintf(
417
+				esc_html__("This is because the %s child class has not set the '_name' property", 'event_espresso'),
418
+				$this->caller
419
+			);
420
+			throw new EE_Error(implode('||', $msg));
421
+		}
422
+		// change "the_message" to "the message"
423
+		$class_name = str_replace('_', ' ', $this->_name);
424
+		// change "the message" to "The_Message_Admin_Page"
425
+		$class_name = str_replace(' ', '_', ucwords($class_name)) . '_Admin_Page';
426
+		// first default file (if exists)
427
+		$decaf_file = EE_ADMIN_PAGES . $this->_name . '/' . $class_name . '.core.php';
428
+		if (is_readable($decaf_file)) {
429
+			require_once($decaf_file);
430
+		}
431
+		// now we have to do require for extended file (if needed)
432
+		if ($this->_extend) {
433
+			require_once(EE_CORE_CAF_ADMIN_EXTEND . $this->_name . '/Extend_' . $class_name . '.core.php');
434
+			// and extend the class name as well
435
+			$class_name = 'Extend_' . $class_name;
436
+		}
437
+		// let's make sure the class exists
438
+		if (! class_exists($class_name)) {
439
+			$msg[] = esc_html__('We can\'t load the page object', 'event_espresso');
440
+			$msg[] = sprintf(
441
+				esc_html__(
442
+					'The class name that was given is %s. Check the spelling and make sure its correct, also there needs to be an autoloader setup for the class',
443
+					'event_espresso'
444
+				),
445
+				$class_name
446
+			);
447
+			throw new EE_Error(implode('||', $msg));
448
+		}
449
+		$this->_page_object = LoaderFactory::getLoader()->getShared($class_name, [false]);
450
+	}
451
+
452
+
453
+	/**
454
+	 * Child "hook" classes can declare any methods that they want executed when a specific page route is loaded.  The
455
+	 * advantage of this is when doing things like running our own db interactions on saves etc.  Remember that
456
+	 * $this->_req_data (all the _POST and _GET data) is available to your methods.
457
+	 *
458
+	 * @return void
459
+	 */
460
+	private function _load_custom_methods()
461
+	{
462
+		/**
463
+		 * method cannot be named 'default' (@see http://us3.php
464
+		 * .net/manual/en/reserved.keywords.php) so need to
465
+		 * handle routes that are "default"
466
+		 *
467
+		 * @since 4.3.0
468
+		 */
469
+		$method_callback = $this->_current_route == 'default' ? 'default_callback' : $this->_current_route;
470
+		// these run before the Admin_Page route executes.
471
+		if (method_exists($this, $method_callback)) {
472
+			call_user_func([$this, $method_callback]);
473
+		}
474
+		// these run via the _redirect_after_action method in EE_Admin_Page which usually happens after non_UI methods in EE_Admin_Page classes.  There are two redirect actions, the first fires before $query_args might be manipulated by "save and close" actions and the seond fires right before the actual redirect happens.
475
+		// first the actions
476
+		// note that these action hooks will have the $query_args value available.
477
+		$admin_class_name = get_class($this->_adminpage_obj);
478
+		if (method_exists($this, '_redirect_action_early_' . $this->_current_route)) {
479
+			add_action(
480
+				'AHEE__'
481
+				. $admin_class_name
482
+				. '___redirect_after_action__before_redirect_modification_'
483
+				. $this->_current_route,
484
+				[$this, '_redirect_action_early_' . $this->_current_route],
485
+				10
486
+			);
487
+		}
488
+		if (method_exists($this, '_redirect_action_' . $this->_current_route)) {
489
+			add_action(
490
+				'AHEE_redirect_' . $admin_class_name . $this->_current_route,
491
+				[$this, '_redirect_action_' . $this->_current_route],
492
+				10
493
+			);
494
+		}
495
+		// let's hook into the _redirect itself and allow for changing where the user goes after redirect.  This will have $query_args and $redirect_url available.
496
+		if (method_exists($this, '_redirect_filter_' . $this->_current_route)) {
497
+			add_filter(
498
+				'FHEE_redirect_' . $admin_class_name . $this->_current_route,
499
+				[$this, '_redirect_filter_' . $this->_current_route],
500
+				10,
501
+				2
502
+			);
503
+		}
504
+	}
505
+
506
+
507
+	/**
508
+	 * This method will search for a corresponding method with a name matching the route and the wp_hook to run.  This
509
+	 * allows child hook classes to target hooking into a specific wp action or filter hook ONLY on a certain route.
510
+	 * just remember, methods MUST be public Future hooks should be added in here to be access by child classes.
511
+	 *
512
+	 * @return void
513
+	 */
514
+	private function _load_routed_hooks()
515
+	{
516
+
517
+		// this array provides the hook action names that will be referenced.  Key is the action. Value is an array with the type (action or filter) and the number of parameters for the hook.  We'll default all priorities for automatic hooks to 10.
518
+		$hook_filter_array = [
519
+			'admin_footer'                                                                            => [
520
+				'type'     => 'action',
521
+				'argnum'   => 1,
522
+				'priority' => 10,
523
+			],
524
+			'FHEE_list_table_views_' . $this->_adminpage_obj->page_slug . '_' . $this->_current_route => [
525
+				'type'     => 'filter',
526
+				'argnum'   => 1,
527
+				'priority' => 10,
528
+			],
529
+			'FHEE_list_table_views_' . $this->_adminpage_obj->page_slug                               => [
530
+				'type'     => 'filter',
531
+				'argnum'   => 1,
532
+				'priority' => 10,
533
+			],
534
+			'FHEE_list_table_views'                                                                   => [
535
+				'type'     => 'filter',
536
+				'argnum'   => 1,
537
+				'priority' => 10,
538
+			],
539
+			'AHEE__EE_Admin_Page___display_admin_page__modify_metaboxes'                              => [
540
+				'type'     => 'action',
541
+				'argnum'   => 1,
542
+				'priority' => 10,
543
+			],
544
+		];
545
+		foreach ($hook_filter_array as $hook => $args) {
546
+			if (method_exists($this, $this->_current_route . '_' . $hook)) {
547
+				if (isset($this->_wp_action_filters_priority[ $hook ])) {
548
+					$args['priority'] = $this->_wp_action_filters_priority[ $hook ];
549
+				}
550
+				if ($args['type'] == 'action') {
551
+					add_action(
552
+						$hook,
553
+						[$this, $this->_current_route . '_' . $hook],
554
+						$args['priority'],
555
+						$args['argnum']
556
+					);
557
+				} else {
558
+					add_filter(
559
+						$hook,
560
+						[$this, $this->_current_route . '_' . $hook],
561
+						$args['priority'],
562
+						$args['argnum']
563
+					);
564
+				}
565
+			}
566
+		}
567
+	}
568
+
569
+
570
+	/**
571
+	 * Loop throught the $_ajax_func array and add_actions for the array.
572
+	 *
573
+	 * @return void
574
+	 * @throws EE_Error
575
+	 */
576
+	private function _ajax_hooks()
577
+	{
578
+
579
+		if (empty($this->_ajax_func)) {
580
+			return;
581
+		} //get out there's nothing to take care of.
582
+		foreach ($this->_ajax_func as $action => $method) {
583
+			// make sure method exists
584
+			if (! method_exists($this, $method)) {
585
+				$msg[] = esc_html__(
586
+					'There is no corresponding method for the hook labeled in the _ajax_func array',
587
+					'event_espresso'
588
+				) . '<br />';
589
+				$msg[] = sprintf(
590
+					esc_html__(
591
+						'The method name given in the array is %s, check the spelling and make sure it exists in the %s class',
592
+						'event_espresso'
593
+					),
594
+					$method,
595
+					$this->caller
596
+				);
597
+				throw new EE_Error(implode('||', $msg));
598
+			}
599
+			add_action('wp_ajax_' . $action, [$this, $method]);
600
+		}
601
+	}
602
+
603
+
604
+	/**
605
+	 * Loop throught the $_init_func array and add_actions for the array.
606
+	 *
607
+	 * @return void
608
+	 * @throws EE_Error
609
+	 */
610
+	protected function _init_hooks()
611
+	{
612
+		if (empty($this->_init_func)) {
613
+			return;
614
+		}
615
+		// get out there's nothing to take care of.
616
+		// We need to determine what page_route we are on!
617
+		foreach ($this->_init_func as $route => $method) {
618
+			// make sure method exists
619
+			if (! method_exists($this, $method)) {
620
+				$msg[] = esc_html__(
621
+					'There is no corresponding method for the hook labeled in the _init_func array',
622
+					'event_espresso'
623
+				) . '<br />';
624
+				$msg[] = sprintf(
625
+					esc_html__(
626
+						'The method name given in the array is %s, check the spelling and make sure it exists in the %s class',
627
+						'event_espresso'
628
+					),
629
+					$method,
630
+					$this->caller
631
+				);
632
+				throw new EE_Error(implode('||', $msg));
633
+			}
634
+			if ($route == $this->_current_route) {
635
+				add_action('admin_init', [$this, $method]);
636
+			}
637
+		}
638
+	}
639
+
640
+
641
+	/**
642
+	 * Loop through the _metaboxes property and add_metaboxes accordingly
643
+	 * //todo we could eventually make this a config component class (i.e. new EE_Metabox);
644
+	 *
645
+	 * @return void
646
+	 * @throws EE_Error
647
+	 */
648
+	public function add_metaboxes()
649
+	{
650
+		if (empty($this->_metaboxes)) {
651
+			return;
652
+		} //get out we don't have any metaboxes to set for this connection
653
+		$this->_handle_metabox_array($this->_metaboxes);
654
+	}
655
+
656
+
657
+	/**
658
+	 * @param array $boxes
659
+	 * @param bool  $add
660
+	 * @throws EE_Error
661
+	 */
662
+	private function _handle_metabox_array(array $boxes, $add = true)
663
+	{
664
+
665
+		foreach ($boxes as $box) {
666
+			if (! isset($box['page_route'])) {
667
+				continue;
668
+			}
669
+			// we don't have a valid array
670
+			// let's make sure $box['page_route'] is an array so the "foreach" will work.
671
+			$box['page_route'] = (array) $box['page_route'];
672
+			foreach ($box['page_route'] as $route) {
673
+				if ($route != $this->_current_route) {
674
+					continue;
675
+				} //get out we only add metaboxes for set route.
676
+				if ($add) {
677
+					$this->_add_metabox($box);
678
+				} else {
679
+					$this->_remove_metabox($box);
680
+				}
681
+			}
682
+		}
683
+	}
684
+
685
+
686
+	/**
687
+	 * Loop through the _remove_metaboxes property and remove metaboxes accordingly.
688
+	 *
689
+	 * @return void
690
+	 * @throws EE_Error
691
+	 */
692
+	public function remove_metaboxes()
693
+	{
694
+
695
+		if (empty($this->_remove_metaboxes)) {
696
+			return;
697
+		} //get out there are no metaboxes to remove
698
+		$this->_handle_metabox_array($this->_remove_metaboxes, false);
699
+	}
700
+
701
+
702
+	/**
703
+	 * This just handles adding a metabox
704
+	 *
705
+	 * @param array $args an array of args that have been set for this metabox by the child class
706
+	 * @throws EE_Error
707
+	 */
708
+	private function _add_metabox($args)
709
+	{
710
+		$current_screen = get_current_screen();
711
+		$screen_id      = is_object($current_screen) ? $current_screen->id : null;
712
+		$func           = isset($args['func']) ? $args['func'] : 'some_invalid_callback';
713
+		// set defaults
714
+		$defaults      = [
715
+			'callback_args' => [],
716
+			'context'       => 'advanced',
717
+			'func'          => $func,
718
+			'id'            => $this->caller . '_' . $func . '_metabox',
719
+			'label'         => $this->caller,
720
+			'page'          => isset($args['page']) ? $args['page'] : $screen_id,
721
+			'priority'      => 'default',
722
+		];
723
+		$args          = wp_parse_args($args, $defaults);
724
+		$callback_args = $args['callback_args'];
725
+		$context       = $args['context'];
726
+		$func          = $args['func'];
727
+		$id            = $args['id'];
728
+		$label         = $args['label'];
729
+		$page          = $args['page'];
730
+		$priority      = $args['priority'];
731
+		// make sure method exists
732
+		if (! method_exists($this, $func)) {
733
+			$msg[] =
734
+				esc_html__('There is no corresponding method to display the metabox content', 'event_espresso')
735
+				. '<br />';
736
+			$msg[] = sprintf(
737
+				esc_html__(
738
+					'The method name given in the array is %s, check the spelling and make sure it exists in the %s class',
739
+					'event_espresso'
740
+				),
741
+				$func,
742
+				$this->caller
743
+			);
744
+			throw new EE_Error(implode('||', $msg));
745
+		}
746
+		// everything checks out so let's add the metabox
747
+		add_meta_box($id, $label, [$this, $func], $page, $context, $priority, $callback_args);
748
+	}
749
+
750
+
751
+	private function _remove_metabox($args)
752
+	{
753
+		$current_screen = get_current_screen();
754
+		$screen_id      = is_object($current_screen) ? $current_screen->id : null;
755
+		$func           = isset($args['func']) ? $args['func'] : 'some_invalid_callback';
756
+		// set defaults
757
+		$defaults = [
758
+			'context' => 'default',
759
+			'id'      => isset($args['id'])
760
+				? $args['id']
761
+				: $this->_current_route . '_' . $this->caller . '_' . $func . '_metabox',
762
+			'screen'  => isset($args['screen']) ? $args['screen'] : $screen_id,
763
+		];
764
+		$args     = wp_parse_args($args, $defaults);
765
+		$context  = $args['context'];
766
+		$id       = $args['id'];
767
+		$screen   = $args['screen'];
768
+		// everything checks out so lets remove the box!
769
+		remove_meta_box($id, $screen, $context);
770
+	}
771 771
 }
Please login to merge, or discard this patch.
core/admin/EE_Admin_Page_Loader.core.php 2 patches
Spacing   +46 added lines, -46 removed lines patch added patch discarded remove patch
@@ -100,13 +100,13 @@  discard block
 block discarded – undo
100 100
      */
101 101
     private function _define_caffeinated_constants()
102 102
     {
103
-        if (! defined('EE_CORE_CAF_ADMIN')) {
104
-            define('EE_CORE_CAF_ADMIN', EE_PLUGIN_DIR_PATH . 'caffeinated/admin/');
105
-            define('EE_CORE_CAF_ADMIN_URL', EE_PLUGIN_DIR_URL . 'caffeinated/admin/');
106
-            define('EE_CORE_CAF_ADMIN_NEW', EE_CORE_CAF_ADMIN . 'new/');
107
-            define('EE_CORE_CAF_ADMIN_EXTEND', EE_CORE_CAF_ADMIN . 'extend/');
108
-            define('EE_CORE_CAF_ADMIN_EXTEND_URL', EE_CORE_CAF_ADMIN_URL . 'extend/');
109
-            define('EE_CORE_CAF_ADMIN_HOOKS', EE_CORE_CAF_ADMIN . 'hooks/');
103
+        if ( ! defined('EE_CORE_CAF_ADMIN')) {
104
+            define('EE_CORE_CAF_ADMIN', EE_PLUGIN_DIR_PATH.'caffeinated/admin/');
105
+            define('EE_CORE_CAF_ADMIN_URL', EE_PLUGIN_DIR_URL.'caffeinated/admin/');
106
+            define('EE_CORE_CAF_ADMIN_NEW', EE_CORE_CAF_ADMIN.'new/');
107
+            define('EE_CORE_CAF_ADMIN_EXTEND', EE_CORE_CAF_ADMIN.'extend/');
108
+            define('EE_CORE_CAF_ADMIN_EXTEND_URL', EE_CORE_CAF_ADMIN_URL.'extend/');
109
+            define('EE_CORE_CAF_ADMIN_HOOKS', EE_CORE_CAF_ADMIN.'hooks/');
110 110
         }
111 111
     }
112 112
 
@@ -222,7 +222,7 @@  discard block
 block discarded – undo
222 222
         // first let's order the menu groups by their internal menu order (note usort type hinting to ensure the incoming array is EE_Admin_Page_Menu_Map objects )
223 223
         usort($this->_admin_menu_groups, [$this, '_sort_menu_maps']);
224 224
         foreach ($this->_admin_menu_groups as $group) {
225
-            if (! $group instanceof EE_Admin_Page_Menu_Group) {
225
+            if ( ! $group instanceof EE_Admin_Page_Menu_Group) {
226 226
                 throw new EE_Error(
227 227
                     sprintf(
228 228
                         esc_html__(
@@ -233,7 +233,7 @@  discard block
 block discarded – undo
233 233
                     )
234 234
                 );
235 235
             }
236
-            $groups[ $group->menu_slug ] = $group;
236
+            $groups[$group->menu_slug] = $group;
237 237
         }
238 238
         return $groups;
239 239
     }
@@ -252,13 +252,13 @@  discard block
 block discarded – undo
252 252
         $installed_refs = [];
253 253
         $exclude        = ['assets', 'templates'];
254 254
         // grab everything in the  admin core directory
255
-        $admin_screens = glob(EE_ADMIN_PAGES . '*', GLOB_ONLYDIR);
255
+        $admin_screens = glob(EE_ADMIN_PAGES.'*', GLOB_ONLYDIR);
256 256
         if ($admin_screens) {
257 257
             foreach ($admin_screens as $admin_screen) {
258 258
                 // files and anything in the exclude array need not apply
259 259
                 if (is_dir($admin_screen) && ! in_array(basename($admin_screen), $exclude)) {
260 260
                     // these folders represent the different EE admin pages
261
-                    $installed_refs[ basename($admin_screen) ] = $admin_screen;
261
+                    $installed_refs[basename($admin_screen)] = $admin_screen;
262 262
                 }
263 263
             }
264 264
         }
@@ -267,7 +267,7 @@  discard block
 block discarded – undo
267 267
                 'There are no EE_Admin pages detected, it looks like EE did not install properly',
268 268
                 'event_espresso'
269 269
             );
270
-            $error_msg[] = $error_msg[0] . "\r\n"
270
+            $error_msg[] = $error_msg[0]."\r\n"
271 271
                            . sprintf(
272 272
                                esc_html__(
273 273
                                    'Check that the %s folder exists and is writable. Maybe try deactivating, then reactivating Event Espresso again.',
@@ -280,7 +280,7 @@  discard block
 block discarded – undo
280 280
         // this just checks the caffeinated folder and takes care of setting up any caffeinated stuff.
281 281
         $installed_refs = $this->_set_caffeinated($installed_refs);
282 282
         // allow plugins to add in their own pages (note at this point they will need to have an autoloader defined for their class) OR hook into EEH_Autoloader::load_admin_page() to add their path.;
283
-        $installed_refs             = apply_filters(
283
+        $installed_refs = apply_filters(
284 284
             'FHEE__EE_Admin_Page_Loader___get_installed_pages__installed_refs',
285 285
             $installed_refs
286 286
         );
@@ -297,8 +297,8 @@  discard block
 block discarded – undo
297 297
             $admin_init_page = $this->_load_admin_page($page);
298 298
             // verify returned object
299 299
             if ($admin_init_page instanceof EE_Admin_Page_Init) {
300
-                $this->_installed_pages[ $page ] = $admin_init_page;
301
-                if (! $admin_init_page->get_menu_map() instanceof EE_Admin_Page_Menu_Map) {
300
+                $this->_installed_pages[$page] = $admin_init_page;
301
+                if ( ! $admin_init_page->get_menu_map() instanceof EE_Admin_Page_Menu_Map) {
302 302
                     continue;
303 303
                 }
304 304
                 // skip if in full maintenance mode and maintenance_mode_parent is set
@@ -307,27 +307,27 @@  discard block
 block discarded – undo
307 307
                     empty($maintenance_mode_parent)
308 308
                     && EE_Maintenance_Mode::instance()->level() === EE_Maintenance_Mode::level_2_complete_maintenance
309 309
                 ) {
310
-                    unset($installed_refs[ $page ]);
310
+                    unset($installed_refs[$page]);
311 311
                     continue;
312 312
                 }
313 313
                 $menu_slug                       = $admin_init_page->get_menu_map()->menu_slug;
314
-                $this->_menu_slugs[ $menu_slug ] = $page;
314
+                $this->_menu_slugs[$menu_slug] = $page;
315 315
                 // flag for register hooks on extended pages b/c extended pages use the default INIT.
316 316
                 $extend = false;
317 317
                 // now that we've got the admin_init objects... lets see if there are any caffeinated pages extending the originals.  If there are then let's hook into the init admin filter and load our extend instead.
318
-                if (isset($this->_caffeinated_extends[ $page ])) {
318
+                if (isset($this->_caffeinated_extends[$page])) {
319 319
                     $admin_page_name = $admin_init_page->get_admin_page_name();
320
-                    $caf_path        = $this->_caffeinated_extends[ $page ]['path'];
321
-                    $caf_admin_page  = $this->_caffeinated_extends[ $page ]['admin_page'];
320
+                    $caf_path        = $this->_caffeinated_extends[$page]['path'];
321
+                    $caf_admin_page  = $this->_caffeinated_extends[$page]['admin_page'];
322 322
                     add_filter(
323 323
                         "FHEE__EE_Admin_Page_Init___initialize_admin_page__path_to_file__{$menu_slug}_{$admin_page_name}",
324
-                        function ($path_to_file) use ($caf_path) {
324
+                        function($path_to_file) use ($caf_path) {
325 325
                             return $caf_path;
326 326
                         }
327 327
                     );
328 328
                     add_filter(
329 329
                         "FHEE__EE_Admin_Page_Init___initialize_admin_page__admin_page__{$menu_slug}_{$admin_page_name}",
330
-                        function ($admin_page) use ($caf_admin_page) {
330
+                        function($admin_page) use ($caf_admin_page) {
331 331
                             return $caf_admin_page;
332 332
                         }
333 333
                     );
@@ -352,7 +352,7 @@  discard block
 block discarded – undo
352 352
         $ee_menu_slugs = $this->_menu_slugs;
353 353
         // we need to loop again to run any early code
354 354
         foreach ($installed_refs as $page => $path) {
355
-            $this->_installed_pages[ $page ]->do_initial_loads();
355
+            $this->_installed_pages[$page]->do_initial_loads();
356 356
         }
357 357
         do_action('AHEE__EE_Admin_Page_Loader___get_installed_pages_loaded', $this->_installed_pages);
358 358
     }
@@ -366,8 +366,8 @@  discard block
 block discarded – undo
366 366
      */
367 367
     public function get_admin_page_object($page_slug = '')
368 368
     {
369
-        if (isset($this->_installed_pages[ $page_slug ])) {
370
-            return $this->_installed_pages[ $page_slug ]->loaded_page_object();
369
+        if (isset($this->_installed_pages[$page_slug])) {
370
+            return $this->_installed_pages[$page_slug]->loaded_page_object();
371 371
         }
372 372
         return null;
373 373
     }
@@ -383,7 +383,7 @@  discard block
 block discarded – undo
383 383
     private function _get_classname_for_admin_page($dir_name = '')
384 384
     {
385 385
         $class_name = str_replace('_', ' ', strtolower($dir_name));
386
-        return str_replace(' ', '_', ucwords($class_name)) . '_Admin_Page';
386
+        return str_replace(' ', '_', ucwords($class_name)).'_Admin_Page';
387 387
     }
388 388
 
389 389
 
@@ -397,7 +397,7 @@  discard block
 block discarded – undo
397 397
     private function _get_classname_for_admin_init_page($dir_name = '')
398 398
     {
399 399
         $class_name = str_replace('_', ' ', strtolower($dir_name));
400
-        return str_replace(' ', '_', ucwords($class_name)) . '_Admin_Page_Init';
400
+        return str_replace(' ', '_', ucwords($class_name)).'_Admin_Page_Init';
401 401
     }
402 402
 
403 403
 
@@ -431,7 +431,7 @@  discard block
 block discarded – undo
431 431
                 'Make sure you have %1$s defined. If this is a non-EE-core admin page then you also must have an autoloader in place for your class',
432 432
                 'event_espresso'
433 433
             ),
434
-            '<strong>' . $class_name . '</strong>'
434
+            '<strong>'.$class_name.'</strong>'
435 435
         );
436 436
         throw new EE_Error($error_msg);
437 437
     }
@@ -491,7 +491,7 @@  discard block
 block discarded – undo
491 491
                 // if we've got an array then the menu map is in the old format so let's throw a persistent notice that the admin system isn't setup correctly for this item.
492 492
                 if (is_array($page_map) || empty($page_map)) {
493 493
                     new PersistentAdminNotice(
494
-                        'menu_map_warning_' . str_replace(' ', '_', $page->label) . '_' . EVENT_ESPRESSO_VERSION,
494
+                        'menu_map_warning_'.str_replace(' ', '_', $page->label).'_'.EVENT_ESPRESSO_VERSION,
495 495
                         sprintf(
496 496
                             esc_html__(
497 497
                                 'The admin page for %s was not correctly setup because it is using an older method for integrating with Event Espresso Core.  This means that full functionality for this component is not available.  This error message usually appears with an Add-on that is out of date.  Make sure you update all your Event Espresso 4 add-ons to the latest version to ensure they have necessary compatibility updates in place.',
@@ -503,7 +503,7 @@  discard block
 block discarded – undo
503 503
                     continue;
504 504
                 }
505 505
                 // if page map is NOT a EE_Admin_Page_Menu_Map object then throw error.
506
-                if (! $page_map instanceof EE_Admin_Page_Menu_Map) {
506
+                if ( ! $page_map instanceof EE_Admin_Page_Menu_Map) {
507 507
                     throw new EE_Error(
508 508
                         sprintf(
509 509
                             esc_html__(
@@ -523,7 +523,7 @@  discard block
 block discarded – undo
523 523
                     continue;
524 524
                 }
525 525
                 // assign to group (remember $page_map has the admin page stored in it).
526
-                $pages_array[ $page_map->menu_group ][] = $page_map;
526
+                $pages_array[$page_map->menu_group][] = $page_map;
527 527
             }
528 528
         }
529 529
         if (empty($pages_array)) {
@@ -532,20 +532,20 @@  discard block
 block discarded – undo
532 532
         // let's sort the groups, make sure it's a valid group, add header (if to show).
533 533
         foreach ($pages_array as $group => $menu_maps) {
534 534
             // valid_group?
535
-            if (! array_key_exists($group, $menu_groups)) {
535
+            if ( ! array_key_exists($group, $menu_groups)) {
536 536
                 continue;
537 537
             }
538 538
             // sort pages.
539 539
             usort($menu_maps, [$this, '_sort_menu_maps']);
540 540
             // prepend header
541
-            array_unshift($menu_maps, $menu_groups[ $group ]);
541
+            array_unshift($menu_maps, $menu_groups[$group]);
542 542
             // reset $pages_array with prepped data
543
-            $pages_array[ $group ] = $menu_maps;
543
+            $pages_array[$group] = $menu_maps;
544 544
         }
545 545
         // now let's setup the _prepped_menu_maps property
546 546
         foreach ($menu_groups as $group => $group_objs) {
547
-            if (isset($pages_array[ $group ])) {
548
-                $this->_prepped_menu_maps = array_merge($this->_prepped_menu_maps, $pages_array[ $group ]);
547
+            if (isset($pages_array[$group])) {
548
+                $this->_prepped_menu_maps = array_merge($this->_prepped_menu_maps, $pages_array[$group]);
549 549
             }
550 550
         }/**/
551 551
     }
@@ -575,32 +575,32 @@  discard block
 block discarded – undo
575 575
     {
576 576
 
577 577
         // first let's check if there IS a caffeinated folder. If there is not then lets get out.
578
-        if (! is_dir(EE_PLUGIN_DIR_PATH . 'caffeinated/admin') || (defined('EE_DECAF') && EE_DECAF)) {
578
+        if ( ! is_dir(EE_PLUGIN_DIR_PATH.'caffeinated/admin') || (defined('EE_DECAF') && EE_DECAF)) {
579 579
             return $installed_refs;
580 580
         }
581 581
         $this->_define_caffeinated_constants();
582 582
         $exclude = ['tickets'];
583 583
         // okay let's setup an "New" pages first (we'll return installed refs later)
584
-        $new_admin_screens = glob(EE_CORE_CAF_ADMIN . 'new/*', GLOB_ONLYDIR);
584
+        $new_admin_screens = glob(EE_CORE_CAF_ADMIN.'new/*', GLOB_ONLYDIR);
585 585
         if ($new_admin_screens) {
586 586
             foreach ($new_admin_screens as $admin_screen) {
587 587
                 // files and anything in the exclude array need not apply
588 588
                 if (is_dir($admin_screen) && ! in_array(basename($admin_screen), $exclude)) {
589 589
                     // these folders represent the different NEW EE admin pages
590
-                    $installed_refs[ basename($admin_screen) ] = $admin_screen;
590
+                    $installed_refs[basename($admin_screen)] = $admin_screen;
591 591
                     // set autoloaders for our admin page classes based on included path information
592 592
                     EEH_Autoloader::instance()->register_autoloaders_for_each_file_in_folder($admin_screen);
593 593
                 }
594 594
             }
595 595
         }
596 596
         // let's see if there are any EXTENDS to setup in the $_caffeinated_extends array (that will be used later for hooking into the _initialize_admin_age in the related core_init admin page)
597
-        $extends = glob(EE_CORE_CAF_ADMIN . 'extend/*', GLOB_ONLYDIR);
597
+        $extends = glob(EE_CORE_CAF_ADMIN.'extend/*', GLOB_ONLYDIR);
598 598
         if ($extends) {
599 599
             foreach ($extends as $extend) {
600 600
                 if (is_dir($extend)) {
601 601
                     $extend_ref = basename($extend);
602 602
                     // now let's make sure there is a file that matches the expected format
603
-                    $filename                                                = str_replace(
603
+                    $filename = str_replace(
604 604
                         ' ',
605 605
                         '_',
606 606
                         ucwords(
@@ -611,8 +611,8 @@  discard block
 block discarded – undo
611 611
                             )
612 612
                         )
613 613
                     );
614
-                    $filename                                                = 'Extend_' . $filename . '_Admin_Page';
615
-                    $this->_caffeinated_extends[ $extend_ref ]['path']       = str_replace(
614
+                    $filename                                                = 'Extend_'.$filename.'_Admin_Page';
615
+                    $this->_caffeinated_extends[$extend_ref]['path']       = str_replace(
616 616
                         ['\\', '/'],
617 617
                         '/',
618 618
                         EE_CORE_CAF_ADMIN
@@ -622,7 +622,7 @@  discard block
 block discarded – undo
622 622
                         . $filename
623 623
                         . '.core.php'
624 624
                     );
625
-                    $this->_caffeinated_extends[ $extend_ref ]['admin_page'] = $filename;
625
+                    $this->_caffeinated_extends[$extend_ref]['admin_page'] = $filename;
626 626
                     // set autoloaders for our admin page classes based on included path information
627 627
                     EEH_Autoloader::instance()->register_autoloaders_for_each_file_in_folder($extend);
628 628
                 }
@@ -630,12 +630,12 @@  discard block
 block discarded – undo
630 630
         }
631 631
         // let's see if there are any HOOK files and instantiate them if there are (so that hooks are loaded early!).
632 632
         $ee_admin_hooks = [];
633
-        $hooks          = glob(EE_CORE_CAF_ADMIN . 'hooks/*.class.php');
633
+        $hooks          = glob(EE_CORE_CAF_ADMIN.'hooks/*.class.php');
634 634
         if ($hooks) {
635 635
             foreach ($hooks as $hook) {
636 636
                 if (is_readable($hook)) {
637 637
                     require_once $hook;
638
-                    $classname = str_replace(EE_CORE_CAF_ADMIN . 'hooks/', '', $hook);
638
+                    $classname = str_replace(EE_CORE_CAF_ADMIN.'hooks/', '', $hook);
639 639
                     $classname = str_replace('.class.php', '', $classname);
640 640
                     if (class_exists($classname)) {
641 641
                         $ee_admin_hooks[] = $this->loader->getShared($classname);
Please login to merge, or discard this patch.
Indentation   +661 added lines, -661 removed lines patch added patch discarded remove patch
@@ -13,665 +13,665 @@
 block discarded – undo
13 13
  */
14 14
 class EE_Admin_Page_Loader
15 15
 {
16
-    /**
17
-     * _installed_pages
18
-     * objects for page_init objects detected and loaded
19
-     *
20
-     * @access private
21
-     * @var EE_Admin_Page_Init[]
22
-     */
23
-    private $_installed_pages = [];
24
-
25
-
26
-    /**
27
-     * this is used to hold the registry of menu slugs for all the installed admin pages
28
-     *
29
-     * @var array
30
-     */
31
-    private $_menu_slugs = [];
32
-
33
-
34
-    /**
35
-     * _caffeinated_extends
36
-     * This array is the generated configuration array for which core EE_Admin pages are extended (and the bits and
37
-     * pieces needed to do so).  This property is defined in the _set_caffeinated method.
38
-     *
39
-     * @var array
40
-     */
41
-    private $_caffeinated_extends = [];
42
-
43
-    /**
44
-     * _prepped_menu_maps
45
-     * This is the prepared array of EE_Admin_Page_Menu_Maps for adding to the admin_menu.
46
-     *
47
-     * @since  4.4.0
48
-     * @var EE_Admin_Page_Menu_Map[]
49
-     */
50
-    private $_prepped_menu_maps = [];
51
-
52
-
53
-    /**
54
-     * _admin_menu_groups
55
-     * array that holds the group headings and details for
56
-     *
57
-     * @access private
58
-     * @var array
59
-     */
60
-    private $_admin_menu_groups = [];
61
-
62
-
63
-    /**
64
-     * This property will hold the hook file for setting up the filter that does all the connections between admin
65
-     * pages.
66
-     *
67
-     * @var string
68
-     */
69
-    public $hook_file;
70
-
71
-    /**
72
-     * @var LoaderInterface
73
-     */
74
-    protected $loader;
75
-
76
-
77
-    /**
78
-     * @throws EE_Error
79
-     */
80
-    public function __construct(LoaderInterface $loader)
81
-    {
82
-        $this->loader = $loader;
83
-        // define the default "groups" for the admin_pages
84
-        $this->_set_menu_groups();
85
-        // let's do a scan and see what installed pages we have
86
-        $this->_get_installed_pages();
87
-        // set menus (has to be done on every load - we're not actually loading the page just setting the menus and where they point to).
88
-        add_action('admin_menu', [$this, 'set_menus']);
89
-        add_action('network_admin_menu', [$this, 'set_network_menus']);
90
-    }
91
-
92
-
93
-    /**
94
-     * When caffeinated system is detected, this method is called to setup the caffeinated directory constants used by
95
-     * files in the caffeinated folder.
96
-     *
97
-     * @access private
98
-     * @return void
99
-     */
100
-    private function _define_caffeinated_constants()
101
-    {
102
-        if (! defined('EE_CORE_CAF_ADMIN')) {
103
-            define('EE_CORE_CAF_ADMIN', EE_PLUGIN_DIR_PATH . 'caffeinated/admin/');
104
-            define('EE_CORE_CAF_ADMIN_URL', EE_PLUGIN_DIR_URL . 'caffeinated/admin/');
105
-            define('EE_CORE_CAF_ADMIN_NEW', EE_CORE_CAF_ADMIN . 'new/');
106
-            define('EE_CORE_CAF_ADMIN_EXTEND', EE_CORE_CAF_ADMIN . 'extend/');
107
-            define('EE_CORE_CAF_ADMIN_EXTEND_URL', EE_CORE_CAF_ADMIN_URL . 'extend/');
108
-            define('EE_CORE_CAF_ADMIN_HOOKS', EE_CORE_CAF_ADMIN . 'hooks/');
109
-        }
110
-    }
111
-
112
-
113
-    /**
114
-     * _set_menu_groups
115
-     * sets the filterable _admin_menu_groups property (list of various "groupings" within the EE admin menu array)
116
-     *
117
-     * @access private
118
-     * @return void
119
-     */
120
-    private function _set_menu_groups()
121
-    {
122
-        // set array of EE_Admin_Page_Menu_Group objects
123
-        $this->_admin_menu_groups = apply_filters(
124
-            'FHEE__EE_Admin_Page_Loader___set_menu_groups__admin_menu_groups',
125
-            [
126
-                'main'       => $this->loader->getNew(
127
-                    'EE_Admin_Page_Menu_Group',
128
-                    [
129
-                        'menu_label'   => esc_html__('Main', 'event_espresso'),
130
-                        'show_on_menu' => EE_Admin_Page_Menu_Map::NONE,
131
-                        'menu_slug'    => 'main',
132
-                        'capability'   => 'ee_read_ee',
133
-                        'menu_order'   => 0,
134
-                        'parent_slug'  => 'espresso_events',
135
-                    ]
136
-                ),
137
-                'management' => $this->loader->getNew(
138
-                    'EE_Admin_Page_Menu_Group',
139
-                    [
140
-                        'menu_label'   => esc_html__('Management', 'event_espresso'),
141
-                        'show_on_menu' => EE_Admin_Page_Menu_Map::BLOG_ADMIN_ONLY,
142
-                        'menu_slug'    => 'management',
143
-                        'capability'   => 'ee_read_ee',
144
-                        'menu_order'   => 10,
145
-                        'parent_slug'  => 'espresso_events',
146
-                    ]
147
-                ),
148
-                'settings'   => $this->loader->getNew(
149
-                    'EE_Admin_Page_Menu_Group',
150
-                    [
151
-                        'menu_label'   => esc_html__('Settings', 'event_espresso'),
152
-                        'show_on_menu' => EE_Admin_Page_Menu_Map::BLOG_ADMIN_ONLY,
153
-                        'menu_slug'    => 'settings',
154
-                        'capability'   => 'ee_read_ee',
155
-                        'menu_order'   => 30,
156
-                        'parent_slug'  => 'espresso_events',
157
-                    ]
158
-                ),
159
-                'templates'  => $this->loader->getNew(
160
-                    'EE_Admin_Page_Menu_Group',
161
-                    [
162
-                        'menu_label'   => esc_html__('Templates', 'event_espresso'),
163
-                        'show_on_menu' => EE_Admin_Page_Menu_Map::BLOG_ADMIN_ONLY,
164
-                        'menu_slug'    => 'templates',
165
-                        'capability'   => 'ee_read_ee',
166
-                        'menu_order'   => 40,
167
-                        'parent_slug'  => 'espresso_events',
168
-                    ]
169
-                ),
170
-                'extras'     => $this->loader->getNew(
171
-                    'EE_Admin_Page_Menu_Group',
172
-                    [
173
-                        'menu_label'              => esc_html__('Extras', 'event_espresso'),
174
-                        'show_on_menu'            => EE_Admin_Page_Menu_Map::BLOG_AND_NETWORK_ADMIN,
175
-                        'menu_slug'               => 'extras',
176
-                        'capability'              => 'ee_read_ee',
177
-                        'menu_order'              => 50,
178
-                        'parent_slug'             => 'espresso_events',
179
-                        'maintenance_mode_parent' => 'espresso_maintenance_settings',
180
-                    ]
181
-                ),
182
-                'tools'      => $this->loader->getNew(
183
-                    'EE_Admin_Page_Menu_Group',
184
-                    [
185
-                        'menu_label'   => esc_html__('Tools', 'event_espresso'),
186
-                        'show_on_menu' => EE_Admin_Page_Menu_Map::BLOG_ADMIN_ONLY,
187
-                        'menu_slug'    => 'tools',
188
-                        'capability'   => 'ee_read_ee',
189
-                        'menu_order'   => 60,
190
-                        'parent_slug'  => 'espresso_events',
191
-                    ]
192
-                ),
193
-                'addons'     => $this->loader->getNew(
194
-                    'EE_Admin_Page_Menu_Group',
195
-                    [
196
-                        'show_on_menu' => EE_Admin_Page_Menu_Map::BLOG_AND_NETWORK_ADMIN,
197
-                        'menu_label'   => esc_html__('Add-ons', 'event_espresso'),
198
-                        'menu_slug'    => 'addons',
199
-                        'capability'   => 'ee_read_ee',
200
-                        'menu_order'   => 20,
201
-                        'parent_slug'  => 'espresso_events',
202
-                    ]
203
-                ),
204
-            ]
205
-        );
206
-    }
207
-
208
-
209
-    /**
210
-     * This takes all the groups in the _admin_menu_groups array and returns the array indexed by group
211
-     * slug.  The other utility with this function is it validates that all the groups are instances of
212
-     * EE_Admin_Page_Menu_Group (cause some invalid things might have slipped in via addons).
213
-     *
214
-     * @return EE_Admin_Page_Menu_Group[]
215
-     * @throws EE_Error
216
-     * @since  4.4.0
217
-     */
218
-    private function _rearrange_menu_groups()
219
-    {
220
-        $groups = [];
221
-        // first let's order the menu groups by their internal menu order (note usort type hinting to ensure the incoming array is EE_Admin_Page_Menu_Map objects )
222
-        usort($this->_admin_menu_groups, [$this, '_sort_menu_maps']);
223
-        foreach ($this->_admin_menu_groups as $group) {
224
-            if (! $group instanceof EE_Admin_Page_Menu_Group) {
225
-                throw new EE_Error(
226
-                    sprintf(
227
-                        esc_html__(
228
-                            'Unable to continue sorting the menu groups array because there is an invalid value for the menu groups.  All values in this array are required to be a EE_Admin_Page_Menu_Group object.  Instead there was: %s',
229
-                            'event_espresso'
230
-                        ),
231
-                        print_r($group, true)
232
-                    )
233
-                );
234
-            }
235
-            $groups[ $group->menu_slug ] = $group;
236
-        }
237
-        return $groups;
238
-    }
239
-
240
-
241
-    /**
242
-     * _get_installed_pages
243
-     * This just gets the list of installed EE_Admin_pages.
244
-     *
245
-     * @access private
246
-     * @return void
247
-     * @throws EE_Error
248
-     */
249
-    private function _get_installed_pages()
250
-    {
251
-        $installed_refs = [];
252
-        $exclude        = ['assets', 'templates'];
253
-        // grab everything in the  admin core directory
254
-        $admin_screens = glob(EE_ADMIN_PAGES . '*', GLOB_ONLYDIR);
255
-        if ($admin_screens) {
256
-            foreach ($admin_screens as $admin_screen) {
257
-                // files and anything in the exclude array need not apply
258
-                if (is_dir($admin_screen) && ! in_array(basename($admin_screen), $exclude)) {
259
-                    // these folders represent the different EE admin pages
260
-                    $installed_refs[ basename($admin_screen) ] = $admin_screen;
261
-                }
262
-            }
263
-        }
264
-        if (empty($installed_refs)) {
265
-            $error_msg[] = esc_html__(
266
-                'There are no EE_Admin pages detected, it looks like EE did not install properly',
267
-                'event_espresso'
268
-            );
269
-            $error_msg[] = $error_msg[0] . "\r\n"
270
-                           . sprintf(
271
-                               esc_html__(
272
-                                   'Check that the %s folder exists and is writable. Maybe try deactivating, then reactivating Event Espresso again.',
273
-                                   'event_espresso'
274
-                               ),
275
-                               EE_ADMIN_PAGES
276
-                           );
277
-            throw new EE_Error(implode('||', $error_msg));
278
-        }
279
-        // this just checks the caffeinated folder and takes care of setting up any caffeinated stuff.
280
-        $installed_refs = $this->_set_caffeinated($installed_refs);
281
-        // allow plugins to add in their own pages (note at this point they will need to have an autoloader defined for their class) OR hook into EEH_Autoloader::load_admin_page() to add their path.;
282
-        $installed_refs             = apply_filters(
283
-            'FHEE__EE_Admin_Page_Loader___get_installed_pages__installed_refs',
284
-            $installed_refs
285
-        );
286
-        $this->_caffeinated_extends = apply_filters(
287
-            'FHEE__EE_Admin_Page_Loader___get_installed_pages__caffeinated_extends',
288
-            $this->_caffeinated_extends
289
-        );
290
-        // loop through admin pages and setup the $_installed_pages array.
291
-        $hooks_ref = [];
292
-        foreach ($installed_refs as $page => $path) {
293
-            // set autoloaders for our admin page classes based on included path information
294
-            EEH_Autoloader::instance()->register_autoloaders_for_each_file_in_folder($path);
295
-            // build list of installed pages
296
-            $admin_init_page = $this->_load_admin_page($page);
297
-            // verify returned object
298
-            if ($admin_init_page instanceof EE_Admin_Page_Init) {
299
-                $this->_installed_pages[ $page ] = $admin_init_page;
300
-                if (! $admin_init_page->get_menu_map() instanceof EE_Admin_Page_Menu_Map) {
301
-                    continue;
302
-                }
303
-                // skip if in full maintenance mode and maintenance_mode_parent is set
304
-                $maintenance_mode_parent = $admin_init_page->get_menu_map()->maintenance_mode_parent;
305
-                if (
306
-                    empty($maintenance_mode_parent)
307
-                    && EE_Maintenance_Mode::instance()->level() === EE_Maintenance_Mode::level_2_complete_maintenance
308
-                ) {
309
-                    unset($installed_refs[ $page ]);
310
-                    continue;
311
-                }
312
-                $menu_slug                       = $admin_init_page->get_menu_map()->menu_slug;
313
-                $this->_menu_slugs[ $menu_slug ] = $page;
314
-                // flag for register hooks on extended pages b/c extended pages use the default INIT.
315
-                $extend = false;
316
-                // now that we've got the admin_init objects... lets see if there are any caffeinated pages extending the originals.  If there are then let's hook into the init admin filter and load our extend instead.
317
-                if (isset($this->_caffeinated_extends[ $page ])) {
318
-                    $admin_page_name = $admin_init_page->get_admin_page_name();
319
-                    $caf_path        = $this->_caffeinated_extends[ $page ]['path'];
320
-                    $caf_admin_page  = $this->_caffeinated_extends[ $page ]['admin_page'];
321
-                    add_filter(
322
-                        "FHEE__EE_Admin_Page_Init___initialize_admin_page__path_to_file__{$menu_slug}_{$admin_page_name}",
323
-                        function ($path_to_file) use ($caf_path) {
324
-                            return $caf_path;
325
-                        }
326
-                    );
327
-                    add_filter(
328
-                        "FHEE__EE_Admin_Page_Init___initialize_admin_page__admin_page__{$menu_slug}_{$admin_page_name}",
329
-                        function ($admin_page) use ($caf_admin_page) {
330
-                            return $caf_admin_page;
331
-                        }
332
-                    );
333
-                    $extend = true;
334
-                }
335
-                // let's do the registered hooks
336
-                $extended_hooks = $admin_init_page->register_hooks($extend);
337
-                $hooks_ref      = array_merge($hooks_ref, $extended_hooks);
338
-            }
339
-        }
340
-        // the hooks_ref is all the pages where we have $extended _Hooks files
341
-        // that will extend a class in a different folder.
342
-        // So we want to make sure we load the file for the parent.
343
-        // first make sure we've got unique values
344
-        $hooks_ref = array_unique($hooks_ref);
345
-        // now let's loop and require!
346
-        foreach ($hooks_ref as $path) {
347
-            require_once($path);
348
-        }
349
-        // make sure we have menu slugs global setup. Used in EE_Admin_Page->page_setup() to ensure we don't do a full class load for an admin page that isn't requested.
350
-        global $ee_menu_slugs;
351
-        $ee_menu_slugs = $this->_menu_slugs;
352
-        // we need to loop again to run any early code
353
-        foreach ($installed_refs as $page => $path) {
354
-            $this->_installed_pages[ $page ]->do_initial_loads();
355
-        }
356
-        do_action('AHEE__EE_Admin_Page_Loader___get_installed_pages_loaded', $this->_installed_pages);
357
-    }
358
-
359
-
360
-    /**
361
-     * get_admin_page_object
362
-     *
363
-     * @param string $page_slug
364
-     * @return EE_Admin_Page
365
-     */
366
-    public function get_admin_page_object($page_slug = '')
367
-    {
368
-        if (isset($this->_installed_pages[ $page_slug ])) {
369
-            return $this->_installed_pages[ $page_slug ]->loaded_page_object();
370
-        }
371
-        return null;
372
-    }
373
-
374
-
375
-    /**
376
-     * _get_classname_for_admin_page
377
-     * generates an "Admin Page" class based on the directory  name
378
-     *
379
-     * @param $dir_name
380
-     * @return string
381
-     */
382
-    private function _get_classname_for_admin_page($dir_name = '')
383
-    {
384
-        $class_name = str_replace('_', ' ', strtolower($dir_name));
385
-        return str_replace(' ', '_', ucwords($class_name)) . '_Admin_Page';
386
-    }
387
-
388
-
389
-    /**
390
-     * _get_classname_for_admin_init_page
391
-     * generates an "Admin Page Init" class based on the directory  name
392
-     *
393
-     * @param $dir_name
394
-     * @return string
395
-     */
396
-    private function _get_classname_for_admin_init_page($dir_name = '')
397
-    {
398
-        $class_name = str_replace('_', ' ', strtolower($dir_name));
399
-        return str_replace(' ', '_', ucwords($class_name)) . '_Admin_Page_Init';
400
-    }
401
-
402
-
403
-    /**
404
-     * _load_admin_page
405
-     * Loads and instantiates page_init object for a single EE_admin page.
406
-     *
407
-     * @param string $page page_reference
408
-     * @return object|bool  return page object if valid, bool false if not.
409
-     * @throws EE_Error
410
-     */
411
-    private function _load_admin_page($page = '')
412
-    {
413
-        $class_name = $this->_get_classname_for_admin_init_page($page);
414
-        if (class_exists($class_name)) {
415
-            return $this->loader->getShared($class_name);
416
-        }
417
-        $error_msg = sprintf(
418
-            esc_html__('Something went wrong with loading the %s admin page.', 'event_espresso'),
419
-            $page
420
-        );
421
-        $error_msg .= '||'; // separates public from developer messages
422
-        $error_msg .= "\r\n";
423
-        $error_msg .= sprintf(
424
-            esc_html__('There is no Init class in place for the %s admin page.', 'event_espresso'),
425
-            $page
426
-        );
427
-        $error_msg .= '<br />';
428
-        $error_msg .= sprintf(
429
-            esc_html__(
430
-                'Make sure you have %1$s defined. If this is a non-EE-core admin page then you also must have an autoloader in place for your class',
431
-                'event_espresso'
432
-            ),
433
-            '<strong>' . $class_name . '</strong>'
434
-        );
435
-        throw new EE_Error($error_msg);
436
-    }
437
-
438
-
439
-    /**
440
-     * set_menus
441
-     * This method sets up the menus for EE Admin Pages
442
-     *
443
-     * @access private
444
-     * @return void
445
-     * @throws EE_Error
446
-     */
447
-    public function set_menus($network_admin = false)
448
-    {
449
-        // prep the menu pages (sort, group.)
450
-        $this->_prep_pages();
451
-        foreach ($this->_prepped_menu_maps as $menu_map) {
452
-            if (EE_Registry::instance()->CAP->current_user_can($menu_map->capability, $menu_map->menu_slug)) {
453
-                $menu_map->add_menu_page($network_admin);
454
-            }
455
-        }
456
-    }
457
-
458
-
459
-    /**
460
-     * set_network_menus
461
-     * This method sets up the menus for network EE Admin Pages.
462
-     * Almost identical to EE_Admin_Page_Loader::set_menus() except pages
463
-     * are only added to the menu map if they are intended for the admin menu
464
-     *
465
-     * @return void
466
-     * @throws EE_Error
467
-     */
468
-    public function set_network_menus()
469
-    {
470
-        $this->set_menus(true);
471
-    }
472
-
473
-
474
-    /**
475
-     * _prep_pages
476
-     * sets the _prepped_menu_maps property
477
-     *
478
-     * @access private
479
-     * @return void
480
-     * @throws EE_Error
481
-     */
482
-    private function _prep_pages()
483
-    {
484
-        $pages_array = [];
485
-        // rearrange _admin_menu_groups to be indexed by group slug.
486
-        $menu_groups = $this->_rearrange_menu_groups();
487
-        foreach ($this->_installed_pages as $page) {
488
-            if ($page instanceof EE_Admin_page_Init) {
489
-                $page_map = $page->get_menu_map();
490
-                // if we've got an array then the menu map is in the old format so let's throw a persistent notice that the admin system isn't setup correctly for this item.
491
-                if (is_array($page_map) || empty($page_map)) {
492
-                    new PersistentAdminNotice(
493
-                        'menu_map_warning_' . str_replace(' ', '_', $page->label) . '_' . EVENT_ESPRESSO_VERSION,
494
-                        sprintf(
495
-                            esc_html__(
496
-                                'The admin page for %s was not correctly setup because it is using an older method for integrating with Event Espresso Core.  This means that full functionality for this component is not available.  This error message usually appears with an Add-on that is out of date.  Make sure you update all your Event Espresso 4 add-ons to the latest version to ensure they have necessary compatibility updates in place.',
497
-                                'event_espresso'
498
-                            ),
499
-                            $page->label
500
-                        )
501
-                    );
502
-                    continue;
503
-                }
504
-                // if page map is NOT a EE_Admin_Page_Menu_Map object then throw error.
505
-                if (! $page_map instanceof EE_Admin_Page_Menu_Map) {
506
-                    throw new EE_Error(
507
-                        sprintf(
508
-                            esc_html__(
509
-                                'The menu map for %s must be an EE_Admin_Page_Menu_Map object.  Instead it is %s.  Please double check that the menu map has been configured correctly.',
510
-                                'event_espresso'
511
-                            ),
512
-                            $page->label,
513
-                            $page_map
514
-                        )
515
-                    );
516
-                }
517
-                // use the maintenance_mode_parent property and maintenance mode status to determine if this page even gets added to array.
518
-                if (
519
-                    empty($page_map->maintenance_mode_parent)
520
-                    && EE_Maintenance_Mode::instance()->level() == EE_Maintenance_Mode::level_2_complete_maintenance
521
-                ) {
522
-                    continue;
523
-                }
524
-                // assign to group (remember $page_map has the admin page stored in it).
525
-                $pages_array[ $page_map->menu_group ][] = $page_map;
526
-            }
527
-        }
528
-        if (empty($pages_array)) {
529
-            throw new EE_Error(esc_html__('Something went wrong when prepping the admin pages', 'event_espresso'));
530
-        }
531
-        // let's sort the groups, make sure it's a valid group, add header (if to show).
532
-        foreach ($pages_array as $group => $menu_maps) {
533
-            // valid_group?
534
-            if (! array_key_exists($group, $menu_groups)) {
535
-                continue;
536
-            }
537
-            // sort pages.
538
-            usort($menu_maps, [$this, '_sort_menu_maps']);
539
-            // prepend header
540
-            array_unshift($menu_maps, $menu_groups[ $group ]);
541
-            // reset $pages_array with prepped data
542
-            $pages_array[ $group ] = $menu_maps;
543
-        }
544
-        // now let's setup the _prepped_menu_maps property
545
-        foreach ($menu_groups as $group => $group_objs) {
546
-            if (isset($pages_array[ $group ])) {
547
-                $this->_prepped_menu_maps = array_merge($this->_prepped_menu_maps, $pages_array[ $group ]);
548
-            }
549
-        }/**/
550
-    }
551
-
552
-
553
-    /**
554
-     * This method is the "workhorse" for detecting and setting up caffeinated functionality.
555
-     * In this method there are three checks being done:
556
-     * 1. Do we have any NEW admin page sets.  If we do, lets add them into the menu setup (via the $installed_refs
557
-     * array) etc.  (new page sets are found in caffeinated/new/{page})
558
-     * 2. Do we have any EXTENDED page sets.  Basically an extended EE_Admin Page extends the core {child}_Admin_Page
559
-     * class.  eg. would be caffeinated/extend/events/Extend_Events_Admin_Page.core.php and in there would be a class:
560
-     * Extend_Events_Admin_Page extends Events_Admin_Page.
561
-     * 3. Do we have any files just for setting up hooks into other core pages.  The files can be any name in
562
-     * "caffeinated/hooks" EXCEPT they need a ".class.php" extension and the file name must correspond with the
563
-     * classname inside.  These classes are instantiated really early so that any hooks in them are run before the
564
-     * corresponding apply_filters/do_actions that are found in any future loaded EE_Admin pages (INCLUDING caffeinated
565
-     * admin_pages)
566
-     *
567
-     * @param array $installed_refs the original installed_refs array that may contain our NEW EE_Admin_Pages to be
568
-     *                              loaded.
569
-     * @return array
570
-     * @throws EE_Error
571
-     * @throws EE_Error
572
-     */
573
-    private function _set_caffeinated($installed_refs)
574
-    {
575
-
576
-        // first let's check if there IS a caffeinated folder. If there is not then lets get out.
577
-        if (! is_dir(EE_PLUGIN_DIR_PATH . 'caffeinated/admin') || (defined('EE_DECAF') && EE_DECAF)) {
578
-            return $installed_refs;
579
-        }
580
-        $this->_define_caffeinated_constants();
581
-        $exclude = ['tickets'];
582
-        // okay let's setup an "New" pages first (we'll return installed refs later)
583
-        $new_admin_screens = glob(EE_CORE_CAF_ADMIN . 'new/*', GLOB_ONLYDIR);
584
-        if ($new_admin_screens) {
585
-            foreach ($new_admin_screens as $admin_screen) {
586
-                // files and anything in the exclude array need not apply
587
-                if (is_dir($admin_screen) && ! in_array(basename($admin_screen), $exclude)) {
588
-                    // these folders represent the different NEW EE admin pages
589
-                    $installed_refs[ basename($admin_screen) ] = $admin_screen;
590
-                    // set autoloaders for our admin page classes based on included path information
591
-                    EEH_Autoloader::instance()->register_autoloaders_for_each_file_in_folder($admin_screen);
592
-                }
593
-            }
594
-        }
595
-        // let's see if there are any EXTENDS to setup in the $_caffeinated_extends array (that will be used later for hooking into the _initialize_admin_age in the related core_init admin page)
596
-        $extends = glob(EE_CORE_CAF_ADMIN . 'extend/*', GLOB_ONLYDIR);
597
-        if ($extends) {
598
-            foreach ($extends as $extend) {
599
-                if (is_dir($extend)) {
600
-                    $extend_ref = basename($extend);
601
-                    // now let's make sure there is a file that matches the expected format
602
-                    $filename                                                = str_replace(
603
-                        ' ',
604
-                        '_',
605
-                        ucwords(
606
-                            str_replace(
607
-                                '_',
608
-                                ' ',
609
-                                $extend_ref
610
-                            )
611
-                        )
612
-                    );
613
-                    $filename                                                = 'Extend_' . $filename . '_Admin_Page';
614
-                    $this->_caffeinated_extends[ $extend_ref ]['path']       = str_replace(
615
-                        ['\\', '/'],
616
-                        '/',
617
-                        EE_CORE_CAF_ADMIN
618
-                        . 'extend/'
619
-                        . $extend_ref
620
-                        . '/'
621
-                        . $filename
622
-                        . '.core.php'
623
-                    );
624
-                    $this->_caffeinated_extends[ $extend_ref ]['admin_page'] = $filename;
625
-                    // set autoloaders for our admin page classes based on included path information
626
-                    EEH_Autoloader::instance()->register_autoloaders_for_each_file_in_folder($extend);
627
-                }
628
-            }
629
-        }
630
-        // let's see if there are any HOOK files and instantiate them if there are (so that hooks are loaded early!).
631
-        $ee_admin_hooks = [];
632
-        $hooks          = glob(EE_CORE_CAF_ADMIN . 'hooks/*.class.php');
633
-        if ($hooks) {
634
-            foreach ($hooks as $hook) {
635
-                if (is_readable($hook)) {
636
-                    require_once $hook;
637
-                    $classname = str_replace(EE_CORE_CAF_ADMIN . 'hooks/', '', $hook);
638
-                    $classname = str_replace('.class.php', '', $classname);
639
-                    if (class_exists($classname)) {
640
-                        $ee_admin_hooks[] = $this->loader->getShared($classname);
641
-                    }
642
-                }
643
-            }
644
-        }
645
-        apply_filters('FHEE__EE_Admin_Page_Loader__set_caffeinated__ee_admin_hooks', $ee_admin_hooks);
646
-        return $installed_refs;
647
-    }
648
-
649
-
650
-    /**
651
-     * Utility method for sorting the _menu_maps (callback for usort php function)
652
-     *
653
-     * @param EE_Admin_Page_Menu_Map $a menu_map object
654
-     * @param EE_Admin_Page_Menu_Map $b being compared to
655
-     * @return int    sort order
656
-     * @since  4.4.0
657
-     */
658
-    private function _sort_menu_maps(EE_Admin_Page_Menu_Map $a, EE_Admin_Page_Menu_Map $b)
659
-    {
660
-        if ($a->menu_order == $b->menu_order) {
661
-            return 0;
662
-        }
663
-        return ($a->menu_order < $b->menu_order) ? -1 : 1;
664
-    }
665
-
666
-
667
-    /**
668
-     * _default_header_link
669
-     * This is just a dummy method to use with header submenu items
670
-     *
671
-     * @return bool false
672
-     */
673
-    public function _default_header_link()
674
-    {
675
-        return false;
676
-    }
16
+	/**
17
+	 * _installed_pages
18
+	 * objects for page_init objects detected and loaded
19
+	 *
20
+	 * @access private
21
+	 * @var EE_Admin_Page_Init[]
22
+	 */
23
+	private $_installed_pages = [];
24
+
25
+
26
+	/**
27
+	 * this is used to hold the registry of menu slugs for all the installed admin pages
28
+	 *
29
+	 * @var array
30
+	 */
31
+	private $_menu_slugs = [];
32
+
33
+
34
+	/**
35
+	 * _caffeinated_extends
36
+	 * This array is the generated configuration array for which core EE_Admin pages are extended (and the bits and
37
+	 * pieces needed to do so).  This property is defined in the _set_caffeinated method.
38
+	 *
39
+	 * @var array
40
+	 */
41
+	private $_caffeinated_extends = [];
42
+
43
+	/**
44
+	 * _prepped_menu_maps
45
+	 * This is the prepared array of EE_Admin_Page_Menu_Maps for adding to the admin_menu.
46
+	 *
47
+	 * @since  4.4.0
48
+	 * @var EE_Admin_Page_Menu_Map[]
49
+	 */
50
+	private $_prepped_menu_maps = [];
51
+
52
+
53
+	/**
54
+	 * _admin_menu_groups
55
+	 * array that holds the group headings and details for
56
+	 *
57
+	 * @access private
58
+	 * @var array
59
+	 */
60
+	private $_admin_menu_groups = [];
61
+
62
+
63
+	/**
64
+	 * This property will hold the hook file for setting up the filter that does all the connections between admin
65
+	 * pages.
66
+	 *
67
+	 * @var string
68
+	 */
69
+	public $hook_file;
70
+
71
+	/**
72
+	 * @var LoaderInterface
73
+	 */
74
+	protected $loader;
75
+
76
+
77
+	/**
78
+	 * @throws EE_Error
79
+	 */
80
+	public function __construct(LoaderInterface $loader)
81
+	{
82
+		$this->loader = $loader;
83
+		// define the default "groups" for the admin_pages
84
+		$this->_set_menu_groups();
85
+		// let's do a scan and see what installed pages we have
86
+		$this->_get_installed_pages();
87
+		// set menus (has to be done on every load - we're not actually loading the page just setting the menus and where they point to).
88
+		add_action('admin_menu', [$this, 'set_menus']);
89
+		add_action('network_admin_menu', [$this, 'set_network_menus']);
90
+	}
91
+
92
+
93
+	/**
94
+	 * When caffeinated system is detected, this method is called to setup the caffeinated directory constants used by
95
+	 * files in the caffeinated folder.
96
+	 *
97
+	 * @access private
98
+	 * @return void
99
+	 */
100
+	private function _define_caffeinated_constants()
101
+	{
102
+		if (! defined('EE_CORE_CAF_ADMIN')) {
103
+			define('EE_CORE_CAF_ADMIN', EE_PLUGIN_DIR_PATH . 'caffeinated/admin/');
104
+			define('EE_CORE_CAF_ADMIN_URL', EE_PLUGIN_DIR_URL . 'caffeinated/admin/');
105
+			define('EE_CORE_CAF_ADMIN_NEW', EE_CORE_CAF_ADMIN . 'new/');
106
+			define('EE_CORE_CAF_ADMIN_EXTEND', EE_CORE_CAF_ADMIN . 'extend/');
107
+			define('EE_CORE_CAF_ADMIN_EXTEND_URL', EE_CORE_CAF_ADMIN_URL . 'extend/');
108
+			define('EE_CORE_CAF_ADMIN_HOOKS', EE_CORE_CAF_ADMIN . 'hooks/');
109
+		}
110
+	}
111
+
112
+
113
+	/**
114
+	 * _set_menu_groups
115
+	 * sets the filterable _admin_menu_groups property (list of various "groupings" within the EE admin menu array)
116
+	 *
117
+	 * @access private
118
+	 * @return void
119
+	 */
120
+	private function _set_menu_groups()
121
+	{
122
+		// set array of EE_Admin_Page_Menu_Group objects
123
+		$this->_admin_menu_groups = apply_filters(
124
+			'FHEE__EE_Admin_Page_Loader___set_menu_groups__admin_menu_groups',
125
+			[
126
+				'main'       => $this->loader->getNew(
127
+					'EE_Admin_Page_Menu_Group',
128
+					[
129
+						'menu_label'   => esc_html__('Main', 'event_espresso'),
130
+						'show_on_menu' => EE_Admin_Page_Menu_Map::NONE,
131
+						'menu_slug'    => 'main',
132
+						'capability'   => 'ee_read_ee',
133
+						'menu_order'   => 0,
134
+						'parent_slug'  => 'espresso_events',
135
+					]
136
+				),
137
+				'management' => $this->loader->getNew(
138
+					'EE_Admin_Page_Menu_Group',
139
+					[
140
+						'menu_label'   => esc_html__('Management', 'event_espresso'),
141
+						'show_on_menu' => EE_Admin_Page_Menu_Map::BLOG_ADMIN_ONLY,
142
+						'menu_slug'    => 'management',
143
+						'capability'   => 'ee_read_ee',
144
+						'menu_order'   => 10,
145
+						'parent_slug'  => 'espresso_events',
146
+					]
147
+				),
148
+				'settings'   => $this->loader->getNew(
149
+					'EE_Admin_Page_Menu_Group',
150
+					[
151
+						'menu_label'   => esc_html__('Settings', 'event_espresso'),
152
+						'show_on_menu' => EE_Admin_Page_Menu_Map::BLOG_ADMIN_ONLY,
153
+						'menu_slug'    => 'settings',
154
+						'capability'   => 'ee_read_ee',
155
+						'menu_order'   => 30,
156
+						'parent_slug'  => 'espresso_events',
157
+					]
158
+				),
159
+				'templates'  => $this->loader->getNew(
160
+					'EE_Admin_Page_Menu_Group',
161
+					[
162
+						'menu_label'   => esc_html__('Templates', 'event_espresso'),
163
+						'show_on_menu' => EE_Admin_Page_Menu_Map::BLOG_ADMIN_ONLY,
164
+						'menu_slug'    => 'templates',
165
+						'capability'   => 'ee_read_ee',
166
+						'menu_order'   => 40,
167
+						'parent_slug'  => 'espresso_events',
168
+					]
169
+				),
170
+				'extras'     => $this->loader->getNew(
171
+					'EE_Admin_Page_Menu_Group',
172
+					[
173
+						'menu_label'              => esc_html__('Extras', 'event_espresso'),
174
+						'show_on_menu'            => EE_Admin_Page_Menu_Map::BLOG_AND_NETWORK_ADMIN,
175
+						'menu_slug'               => 'extras',
176
+						'capability'              => 'ee_read_ee',
177
+						'menu_order'              => 50,
178
+						'parent_slug'             => 'espresso_events',
179
+						'maintenance_mode_parent' => 'espresso_maintenance_settings',
180
+					]
181
+				),
182
+				'tools'      => $this->loader->getNew(
183
+					'EE_Admin_Page_Menu_Group',
184
+					[
185
+						'menu_label'   => esc_html__('Tools', 'event_espresso'),
186
+						'show_on_menu' => EE_Admin_Page_Menu_Map::BLOG_ADMIN_ONLY,
187
+						'menu_slug'    => 'tools',
188
+						'capability'   => 'ee_read_ee',
189
+						'menu_order'   => 60,
190
+						'parent_slug'  => 'espresso_events',
191
+					]
192
+				),
193
+				'addons'     => $this->loader->getNew(
194
+					'EE_Admin_Page_Menu_Group',
195
+					[
196
+						'show_on_menu' => EE_Admin_Page_Menu_Map::BLOG_AND_NETWORK_ADMIN,
197
+						'menu_label'   => esc_html__('Add-ons', 'event_espresso'),
198
+						'menu_slug'    => 'addons',
199
+						'capability'   => 'ee_read_ee',
200
+						'menu_order'   => 20,
201
+						'parent_slug'  => 'espresso_events',
202
+					]
203
+				),
204
+			]
205
+		);
206
+	}
207
+
208
+
209
+	/**
210
+	 * This takes all the groups in the _admin_menu_groups array and returns the array indexed by group
211
+	 * slug.  The other utility with this function is it validates that all the groups are instances of
212
+	 * EE_Admin_Page_Menu_Group (cause some invalid things might have slipped in via addons).
213
+	 *
214
+	 * @return EE_Admin_Page_Menu_Group[]
215
+	 * @throws EE_Error
216
+	 * @since  4.4.0
217
+	 */
218
+	private function _rearrange_menu_groups()
219
+	{
220
+		$groups = [];
221
+		// first let's order the menu groups by their internal menu order (note usort type hinting to ensure the incoming array is EE_Admin_Page_Menu_Map objects )
222
+		usort($this->_admin_menu_groups, [$this, '_sort_menu_maps']);
223
+		foreach ($this->_admin_menu_groups as $group) {
224
+			if (! $group instanceof EE_Admin_Page_Menu_Group) {
225
+				throw new EE_Error(
226
+					sprintf(
227
+						esc_html__(
228
+							'Unable to continue sorting the menu groups array because there is an invalid value for the menu groups.  All values in this array are required to be a EE_Admin_Page_Menu_Group object.  Instead there was: %s',
229
+							'event_espresso'
230
+						),
231
+						print_r($group, true)
232
+					)
233
+				);
234
+			}
235
+			$groups[ $group->menu_slug ] = $group;
236
+		}
237
+		return $groups;
238
+	}
239
+
240
+
241
+	/**
242
+	 * _get_installed_pages
243
+	 * This just gets the list of installed EE_Admin_pages.
244
+	 *
245
+	 * @access private
246
+	 * @return void
247
+	 * @throws EE_Error
248
+	 */
249
+	private function _get_installed_pages()
250
+	{
251
+		$installed_refs = [];
252
+		$exclude        = ['assets', 'templates'];
253
+		// grab everything in the  admin core directory
254
+		$admin_screens = glob(EE_ADMIN_PAGES . '*', GLOB_ONLYDIR);
255
+		if ($admin_screens) {
256
+			foreach ($admin_screens as $admin_screen) {
257
+				// files and anything in the exclude array need not apply
258
+				if (is_dir($admin_screen) && ! in_array(basename($admin_screen), $exclude)) {
259
+					// these folders represent the different EE admin pages
260
+					$installed_refs[ basename($admin_screen) ] = $admin_screen;
261
+				}
262
+			}
263
+		}
264
+		if (empty($installed_refs)) {
265
+			$error_msg[] = esc_html__(
266
+				'There are no EE_Admin pages detected, it looks like EE did not install properly',
267
+				'event_espresso'
268
+			);
269
+			$error_msg[] = $error_msg[0] . "\r\n"
270
+						   . sprintf(
271
+							   esc_html__(
272
+								   'Check that the %s folder exists and is writable. Maybe try deactivating, then reactivating Event Espresso again.',
273
+								   'event_espresso'
274
+							   ),
275
+							   EE_ADMIN_PAGES
276
+						   );
277
+			throw new EE_Error(implode('||', $error_msg));
278
+		}
279
+		// this just checks the caffeinated folder and takes care of setting up any caffeinated stuff.
280
+		$installed_refs = $this->_set_caffeinated($installed_refs);
281
+		// allow plugins to add in their own pages (note at this point they will need to have an autoloader defined for their class) OR hook into EEH_Autoloader::load_admin_page() to add their path.;
282
+		$installed_refs             = apply_filters(
283
+			'FHEE__EE_Admin_Page_Loader___get_installed_pages__installed_refs',
284
+			$installed_refs
285
+		);
286
+		$this->_caffeinated_extends = apply_filters(
287
+			'FHEE__EE_Admin_Page_Loader___get_installed_pages__caffeinated_extends',
288
+			$this->_caffeinated_extends
289
+		);
290
+		// loop through admin pages and setup the $_installed_pages array.
291
+		$hooks_ref = [];
292
+		foreach ($installed_refs as $page => $path) {
293
+			// set autoloaders for our admin page classes based on included path information
294
+			EEH_Autoloader::instance()->register_autoloaders_for_each_file_in_folder($path);
295
+			// build list of installed pages
296
+			$admin_init_page = $this->_load_admin_page($page);
297
+			// verify returned object
298
+			if ($admin_init_page instanceof EE_Admin_Page_Init) {
299
+				$this->_installed_pages[ $page ] = $admin_init_page;
300
+				if (! $admin_init_page->get_menu_map() instanceof EE_Admin_Page_Menu_Map) {
301
+					continue;
302
+				}
303
+				// skip if in full maintenance mode and maintenance_mode_parent is set
304
+				$maintenance_mode_parent = $admin_init_page->get_menu_map()->maintenance_mode_parent;
305
+				if (
306
+					empty($maintenance_mode_parent)
307
+					&& EE_Maintenance_Mode::instance()->level() === EE_Maintenance_Mode::level_2_complete_maintenance
308
+				) {
309
+					unset($installed_refs[ $page ]);
310
+					continue;
311
+				}
312
+				$menu_slug                       = $admin_init_page->get_menu_map()->menu_slug;
313
+				$this->_menu_slugs[ $menu_slug ] = $page;
314
+				// flag for register hooks on extended pages b/c extended pages use the default INIT.
315
+				$extend = false;
316
+				// now that we've got the admin_init objects... lets see if there are any caffeinated pages extending the originals.  If there are then let's hook into the init admin filter and load our extend instead.
317
+				if (isset($this->_caffeinated_extends[ $page ])) {
318
+					$admin_page_name = $admin_init_page->get_admin_page_name();
319
+					$caf_path        = $this->_caffeinated_extends[ $page ]['path'];
320
+					$caf_admin_page  = $this->_caffeinated_extends[ $page ]['admin_page'];
321
+					add_filter(
322
+						"FHEE__EE_Admin_Page_Init___initialize_admin_page__path_to_file__{$menu_slug}_{$admin_page_name}",
323
+						function ($path_to_file) use ($caf_path) {
324
+							return $caf_path;
325
+						}
326
+					);
327
+					add_filter(
328
+						"FHEE__EE_Admin_Page_Init___initialize_admin_page__admin_page__{$menu_slug}_{$admin_page_name}",
329
+						function ($admin_page) use ($caf_admin_page) {
330
+							return $caf_admin_page;
331
+						}
332
+					);
333
+					$extend = true;
334
+				}
335
+				// let's do the registered hooks
336
+				$extended_hooks = $admin_init_page->register_hooks($extend);
337
+				$hooks_ref      = array_merge($hooks_ref, $extended_hooks);
338
+			}
339
+		}
340
+		// the hooks_ref is all the pages where we have $extended _Hooks files
341
+		// that will extend a class in a different folder.
342
+		// So we want to make sure we load the file for the parent.
343
+		// first make sure we've got unique values
344
+		$hooks_ref = array_unique($hooks_ref);
345
+		// now let's loop and require!
346
+		foreach ($hooks_ref as $path) {
347
+			require_once($path);
348
+		}
349
+		// make sure we have menu slugs global setup. Used in EE_Admin_Page->page_setup() to ensure we don't do a full class load for an admin page that isn't requested.
350
+		global $ee_menu_slugs;
351
+		$ee_menu_slugs = $this->_menu_slugs;
352
+		// we need to loop again to run any early code
353
+		foreach ($installed_refs as $page => $path) {
354
+			$this->_installed_pages[ $page ]->do_initial_loads();
355
+		}
356
+		do_action('AHEE__EE_Admin_Page_Loader___get_installed_pages_loaded', $this->_installed_pages);
357
+	}
358
+
359
+
360
+	/**
361
+	 * get_admin_page_object
362
+	 *
363
+	 * @param string $page_slug
364
+	 * @return EE_Admin_Page
365
+	 */
366
+	public function get_admin_page_object($page_slug = '')
367
+	{
368
+		if (isset($this->_installed_pages[ $page_slug ])) {
369
+			return $this->_installed_pages[ $page_slug ]->loaded_page_object();
370
+		}
371
+		return null;
372
+	}
373
+
374
+
375
+	/**
376
+	 * _get_classname_for_admin_page
377
+	 * generates an "Admin Page" class based on the directory  name
378
+	 *
379
+	 * @param $dir_name
380
+	 * @return string
381
+	 */
382
+	private function _get_classname_for_admin_page($dir_name = '')
383
+	{
384
+		$class_name = str_replace('_', ' ', strtolower($dir_name));
385
+		return str_replace(' ', '_', ucwords($class_name)) . '_Admin_Page';
386
+	}
387
+
388
+
389
+	/**
390
+	 * _get_classname_for_admin_init_page
391
+	 * generates an "Admin Page Init" class based on the directory  name
392
+	 *
393
+	 * @param $dir_name
394
+	 * @return string
395
+	 */
396
+	private function _get_classname_for_admin_init_page($dir_name = '')
397
+	{
398
+		$class_name = str_replace('_', ' ', strtolower($dir_name));
399
+		return str_replace(' ', '_', ucwords($class_name)) . '_Admin_Page_Init';
400
+	}
401
+
402
+
403
+	/**
404
+	 * _load_admin_page
405
+	 * Loads and instantiates page_init object for a single EE_admin page.
406
+	 *
407
+	 * @param string $page page_reference
408
+	 * @return object|bool  return page object if valid, bool false if not.
409
+	 * @throws EE_Error
410
+	 */
411
+	private function _load_admin_page($page = '')
412
+	{
413
+		$class_name = $this->_get_classname_for_admin_init_page($page);
414
+		if (class_exists($class_name)) {
415
+			return $this->loader->getShared($class_name);
416
+		}
417
+		$error_msg = sprintf(
418
+			esc_html__('Something went wrong with loading the %s admin page.', 'event_espresso'),
419
+			$page
420
+		);
421
+		$error_msg .= '||'; // separates public from developer messages
422
+		$error_msg .= "\r\n";
423
+		$error_msg .= sprintf(
424
+			esc_html__('There is no Init class in place for the %s admin page.', 'event_espresso'),
425
+			$page
426
+		);
427
+		$error_msg .= '<br />';
428
+		$error_msg .= sprintf(
429
+			esc_html__(
430
+				'Make sure you have %1$s defined. If this is a non-EE-core admin page then you also must have an autoloader in place for your class',
431
+				'event_espresso'
432
+			),
433
+			'<strong>' . $class_name . '</strong>'
434
+		);
435
+		throw new EE_Error($error_msg);
436
+	}
437
+
438
+
439
+	/**
440
+	 * set_menus
441
+	 * This method sets up the menus for EE Admin Pages
442
+	 *
443
+	 * @access private
444
+	 * @return void
445
+	 * @throws EE_Error
446
+	 */
447
+	public function set_menus($network_admin = false)
448
+	{
449
+		// prep the menu pages (sort, group.)
450
+		$this->_prep_pages();
451
+		foreach ($this->_prepped_menu_maps as $menu_map) {
452
+			if (EE_Registry::instance()->CAP->current_user_can($menu_map->capability, $menu_map->menu_slug)) {
453
+				$menu_map->add_menu_page($network_admin);
454
+			}
455
+		}
456
+	}
457
+
458
+
459
+	/**
460
+	 * set_network_menus
461
+	 * This method sets up the menus for network EE Admin Pages.
462
+	 * Almost identical to EE_Admin_Page_Loader::set_menus() except pages
463
+	 * are only added to the menu map if they are intended for the admin menu
464
+	 *
465
+	 * @return void
466
+	 * @throws EE_Error
467
+	 */
468
+	public function set_network_menus()
469
+	{
470
+		$this->set_menus(true);
471
+	}
472
+
473
+
474
+	/**
475
+	 * _prep_pages
476
+	 * sets the _prepped_menu_maps property
477
+	 *
478
+	 * @access private
479
+	 * @return void
480
+	 * @throws EE_Error
481
+	 */
482
+	private function _prep_pages()
483
+	{
484
+		$pages_array = [];
485
+		// rearrange _admin_menu_groups to be indexed by group slug.
486
+		$menu_groups = $this->_rearrange_menu_groups();
487
+		foreach ($this->_installed_pages as $page) {
488
+			if ($page instanceof EE_Admin_page_Init) {
489
+				$page_map = $page->get_menu_map();
490
+				// if we've got an array then the menu map is in the old format so let's throw a persistent notice that the admin system isn't setup correctly for this item.
491
+				if (is_array($page_map) || empty($page_map)) {
492
+					new PersistentAdminNotice(
493
+						'menu_map_warning_' . str_replace(' ', '_', $page->label) . '_' . EVENT_ESPRESSO_VERSION,
494
+						sprintf(
495
+							esc_html__(
496
+								'The admin page for %s was not correctly setup because it is using an older method for integrating with Event Espresso Core.  This means that full functionality for this component is not available.  This error message usually appears with an Add-on that is out of date.  Make sure you update all your Event Espresso 4 add-ons to the latest version to ensure they have necessary compatibility updates in place.',
497
+								'event_espresso'
498
+							),
499
+							$page->label
500
+						)
501
+					);
502
+					continue;
503
+				}
504
+				// if page map is NOT a EE_Admin_Page_Menu_Map object then throw error.
505
+				if (! $page_map instanceof EE_Admin_Page_Menu_Map) {
506
+					throw new EE_Error(
507
+						sprintf(
508
+							esc_html__(
509
+								'The menu map for %s must be an EE_Admin_Page_Menu_Map object.  Instead it is %s.  Please double check that the menu map has been configured correctly.',
510
+								'event_espresso'
511
+							),
512
+							$page->label,
513
+							$page_map
514
+						)
515
+					);
516
+				}
517
+				// use the maintenance_mode_parent property and maintenance mode status to determine if this page even gets added to array.
518
+				if (
519
+					empty($page_map->maintenance_mode_parent)
520
+					&& EE_Maintenance_Mode::instance()->level() == EE_Maintenance_Mode::level_2_complete_maintenance
521
+				) {
522
+					continue;
523
+				}
524
+				// assign to group (remember $page_map has the admin page stored in it).
525
+				$pages_array[ $page_map->menu_group ][] = $page_map;
526
+			}
527
+		}
528
+		if (empty($pages_array)) {
529
+			throw new EE_Error(esc_html__('Something went wrong when prepping the admin pages', 'event_espresso'));
530
+		}
531
+		// let's sort the groups, make sure it's a valid group, add header (if to show).
532
+		foreach ($pages_array as $group => $menu_maps) {
533
+			// valid_group?
534
+			if (! array_key_exists($group, $menu_groups)) {
535
+				continue;
536
+			}
537
+			// sort pages.
538
+			usort($menu_maps, [$this, '_sort_menu_maps']);
539
+			// prepend header
540
+			array_unshift($menu_maps, $menu_groups[ $group ]);
541
+			// reset $pages_array with prepped data
542
+			$pages_array[ $group ] = $menu_maps;
543
+		}
544
+		// now let's setup the _prepped_menu_maps property
545
+		foreach ($menu_groups as $group => $group_objs) {
546
+			if (isset($pages_array[ $group ])) {
547
+				$this->_prepped_menu_maps = array_merge($this->_prepped_menu_maps, $pages_array[ $group ]);
548
+			}
549
+		}/**/
550
+	}
551
+
552
+
553
+	/**
554
+	 * This method is the "workhorse" for detecting and setting up caffeinated functionality.
555
+	 * In this method there are three checks being done:
556
+	 * 1. Do we have any NEW admin page sets.  If we do, lets add them into the menu setup (via the $installed_refs
557
+	 * array) etc.  (new page sets are found in caffeinated/new/{page})
558
+	 * 2. Do we have any EXTENDED page sets.  Basically an extended EE_Admin Page extends the core {child}_Admin_Page
559
+	 * class.  eg. would be caffeinated/extend/events/Extend_Events_Admin_Page.core.php and in there would be a class:
560
+	 * Extend_Events_Admin_Page extends Events_Admin_Page.
561
+	 * 3. Do we have any files just for setting up hooks into other core pages.  The files can be any name in
562
+	 * "caffeinated/hooks" EXCEPT they need a ".class.php" extension and the file name must correspond with the
563
+	 * classname inside.  These classes are instantiated really early so that any hooks in them are run before the
564
+	 * corresponding apply_filters/do_actions that are found in any future loaded EE_Admin pages (INCLUDING caffeinated
565
+	 * admin_pages)
566
+	 *
567
+	 * @param array $installed_refs the original installed_refs array that may contain our NEW EE_Admin_Pages to be
568
+	 *                              loaded.
569
+	 * @return array
570
+	 * @throws EE_Error
571
+	 * @throws EE_Error
572
+	 */
573
+	private function _set_caffeinated($installed_refs)
574
+	{
575
+
576
+		// first let's check if there IS a caffeinated folder. If there is not then lets get out.
577
+		if (! is_dir(EE_PLUGIN_DIR_PATH . 'caffeinated/admin') || (defined('EE_DECAF') && EE_DECAF)) {
578
+			return $installed_refs;
579
+		}
580
+		$this->_define_caffeinated_constants();
581
+		$exclude = ['tickets'];
582
+		// okay let's setup an "New" pages first (we'll return installed refs later)
583
+		$new_admin_screens = glob(EE_CORE_CAF_ADMIN . 'new/*', GLOB_ONLYDIR);
584
+		if ($new_admin_screens) {
585
+			foreach ($new_admin_screens as $admin_screen) {
586
+				// files and anything in the exclude array need not apply
587
+				if (is_dir($admin_screen) && ! in_array(basename($admin_screen), $exclude)) {
588
+					// these folders represent the different NEW EE admin pages
589
+					$installed_refs[ basename($admin_screen) ] = $admin_screen;
590
+					// set autoloaders for our admin page classes based on included path information
591
+					EEH_Autoloader::instance()->register_autoloaders_for_each_file_in_folder($admin_screen);
592
+				}
593
+			}
594
+		}
595
+		// let's see if there are any EXTENDS to setup in the $_caffeinated_extends array (that will be used later for hooking into the _initialize_admin_age in the related core_init admin page)
596
+		$extends = glob(EE_CORE_CAF_ADMIN . 'extend/*', GLOB_ONLYDIR);
597
+		if ($extends) {
598
+			foreach ($extends as $extend) {
599
+				if (is_dir($extend)) {
600
+					$extend_ref = basename($extend);
601
+					// now let's make sure there is a file that matches the expected format
602
+					$filename                                                = str_replace(
603
+						' ',
604
+						'_',
605
+						ucwords(
606
+							str_replace(
607
+								'_',
608
+								' ',
609
+								$extend_ref
610
+							)
611
+						)
612
+					);
613
+					$filename                                                = 'Extend_' . $filename . '_Admin_Page';
614
+					$this->_caffeinated_extends[ $extend_ref ]['path']       = str_replace(
615
+						['\\', '/'],
616
+						'/',
617
+						EE_CORE_CAF_ADMIN
618
+						. 'extend/'
619
+						. $extend_ref
620
+						. '/'
621
+						. $filename
622
+						. '.core.php'
623
+					);
624
+					$this->_caffeinated_extends[ $extend_ref ]['admin_page'] = $filename;
625
+					// set autoloaders for our admin page classes based on included path information
626
+					EEH_Autoloader::instance()->register_autoloaders_for_each_file_in_folder($extend);
627
+				}
628
+			}
629
+		}
630
+		// let's see if there are any HOOK files and instantiate them if there are (so that hooks are loaded early!).
631
+		$ee_admin_hooks = [];
632
+		$hooks          = glob(EE_CORE_CAF_ADMIN . 'hooks/*.class.php');
633
+		if ($hooks) {
634
+			foreach ($hooks as $hook) {
635
+				if (is_readable($hook)) {
636
+					require_once $hook;
637
+					$classname = str_replace(EE_CORE_CAF_ADMIN . 'hooks/', '', $hook);
638
+					$classname = str_replace('.class.php', '', $classname);
639
+					if (class_exists($classname)) {
640
+						$ee_admin_hooks[] = $this->loader->getShared($classname);
641
+					}
642
+				}
643
+			}
644
+		}
645
+		apply_filters('FHEE__EE_Admin_Page_Loader__set_caffeinated__ee_admin_hooks', $ee_admin_hooks);
646
+		return $installed_refs;
647
+	}
648
+
649
+
650
+	/**
651
+	 * Utility method for sorting the _menu_maps (callback for usort php function)
652
+	 *
653
+	 * @param EE_Admin_Page_Menu_Map $a menu_map object
654
+	 * @param EE_Admin_Page_Menu_Map $b being compared to
655
+	 * @return int    sort order
656
+	 * @since  4.4.0
657
+	 */
658
+	private function _sort_menu_maps(EE_Admin_Page_Menu_Map $a, EE_Admin_Page_Menu_Map $b)
659
+	{
660
+		if ($a->menu_order == $b->menu_order) {
661
+			return 0;
662
+		}
663
+		return ($a->menu_order < $b->menu_order) ? -1 : 1;
664
+	}
665
+
666
+
667
+	/**
668
+	 * _default_header_link
669
+	 * This is just a dummy method to use with header submenu items
670
+	 *
671
+	 * @return bool false
672
+	 */
673
+	public function _default_header_link()
674
+	{
675
+		return false;
676
+	}
677 677
 }
Please login to merge, or discard this patch.
core/admin/EE_Admin_Page_Menu_Map.core.php 2 patches
Spacing   +5 added lines, -5 removed lines patch added patch discarded remove patch
@@ -145,7 +145,7 @@  discard block
 block discarded – undo
145 145
         // verify that required keys are present in the incoming array.
146 146
         $missing = array_diff((array) $required, array_keys((array) $menu_args));
147 147
 
148
-        if (! empty($missing)) {
148
+        if ( ! empty($missing)) {
149 149
             throw new EE_Error(
150 150
                 sprintf(
151 151
                     esc_html__(
@@ -184,7 +184,7 @@  discard block
 block discarded – undo
184 184
                     $value = (string) $value;
185 185
                     break;
186 186
             }
187
-            if (! EEH_Class_Tools::has_property($this, $prop)) {
187
+            if ( ! EEH_Class_Tools::has_property($this, $prop)) {
188 188
                 throw new EE_Error(
189 189
                     sprintf(
190 190
                         esc_html__(
@@ -201,7 +201,7 @@  discard block
 block discarded – undo
201 201
 
202 202
         // filter capabilities (both static and dynamic)
203 203
         $this->capability = apply_filters('FHEE_management_capability', $this->capability, null);
204
-        $this->capability = apply_filters('FHEE_' . $this->menu_slug . '_capability', $this->capability, null);
204
+        $this->capability = apply_filters('FHEE_'.$this->menu_slug.'_capability', $this->capability, null);
205 205
 
206 206
         // Might need to change parent slug depending on maintenance mode.
207 207
         if (
@@ -247,7 +247,7 @@  discard block
 block discarded – undo
247 247
                  [self::BLOG_AND_NETWORK_ADMIN, self::NETWORK_ADMIN_ONLY],
248 248
                  true
249 249
              ))
250
-            || (! $network_admin
250
+            || ( ! $network_admin
251 251
                 && in_array(
252 252
                     $show_on_menu_int,
253 253
                     [self::BLOG_AND_NETWORK_ADMIN, self::BLOG_ADMIN_ONLY],
@@ -259,7 +259,7 @@  discard block
 block discarded – undo
259 259
             $wp_page_slug = '';
260 260
         }
261 261
 
262
-        if (! empty($wp_page_slug) && $this->admin_init_page instanceof EE_Admin_Page_Init) {
262
+        if ( ! empty($wp_page_slug) && $this->admin_init_page instanceof EE_Admin_Page_Init) {
263 263
             try {
264 264
                 $this->admin_init_page->set_page_dependencies($wp_page_slug);
265 265
             } catch (EE_Error $e) {
Please login to merge, or discard this patch.
Indentation   +255 added lines, -255 removed lines patch added patch discarded remove patch
@@ -9,260 +9,260 @@
 block discarded – undo
9 9
  */
10 10
 abstract class EE_Admin_Page_Menu_Map
11 11
 {
12
-    /**
13
-     * The title for the menu page. (the page the menu links to)
14
-     *
15
-     * @since  4.4.0
16
-     * @var string
17
-     */
18
-    public $title;
19
-
12
+	/**
13
+	 * The title for the menu page. (the page the menu links to)
14
+	 *
15
+	 * @since  4.4.0
16
+	 * @var string
17
+	 */
18
+	public $title;
19
+
20 20
 
21
-    /**
22
-     * The label for the menu item. (What shows up in the actual menu).
23
-     *
24
-     * @since 4.4.0
25
-     * @var string
26
-     */
27
-    public $menu_label;
28
-
29
-
30
-    /**
31
-     * What menu item is the parent of this menu item.
32
-     *
33
-     * @since 4.4.0
34
-     * @var string
35
-     */
36
-    public $parent_slug;
37
-
38
-
39
-    /**
40
-     * What capability is required to access this page.
41
-     *
42
-     * @since 4.4.0
43
-     * @var string
44
-     */
45
-    public $capability = 'administrator';
46
-
47
-
48
-    /**
49
-     * What slug should be used to reference this menu item.
50
-     *
51
-     * @since 4.4.0
52
-     * @var string
53
-     */
54
-    public $menu_slug;
55
-
56
-
57
-    /**
58
-     * The callback for displaying the page that the menu references.
59
-     *
60
-     * @since 4.4.0
61
-     * @var string
62
-     */
63
-    public $menu_callback;
64
-
65
-
66
-    /**
67
-     * The EE_Admin_Page_Init attached to this map.
68
-     *
69
-     * @var EE_Admin_Page_Init
70
-     */
71
-    public $admin_init_page;
72
-
73
-
74
-    /**
75
-     * The EE specific group this menu item belongs in (group slug).
76
-     *
77
-     * @since 4.4.0
78
-     * @var string
79
-     */
80
-    public $menu_group;
81
-
82
-
83
-    /**
84
-     * What order this item should be in the menu.
85
-     *
86
-     * @since 4.4.0
87
-     * @var int
88
-     */
89
-    public $menu_order;
90
-
91
-
92
-    const NONE                   = 0;
93
-
94
-    const BLOG_ADMIN_ONLY        = 1;
95
-
96
-    const BLOG_AND_NETWORK_ADMIN = 2;
97
-
98
-    const NETWORK_ADMIN_ONLY     = 3;
99
-
100
-
101
-    /**
102
-     * Whether this item is displayed in the menu or not.
103
-     * Sometimes an EE Admin Page needs to register itself but is not accessible via the WordPress
104
-     * admin menu.
105
-     *
106
-     * @since 4.4.0
107
-     * @var int
108
-     */
109
-    public $show_on_menu = self::BLOG_ADMIN_ONLY;
110
-
111
-
112
-    /**
113
-     * Menu maps can define a parent slug that gets used instead of the main parent slug for the menu when
114
-     * EE_Maintenance_Mode::level_2_complete_maintenance is active.
115
-     *
116
-     * @var bool
117
-     */
118
-    public $maintenance_mode_parent = '';
119
-
120
-
121
-    /**
122
-     * @param array $menu_args            An array of arguments used to setup the menu
123
-     *                                    properties on construct.
124
-     * @param array $required             An array of keys that should be in the $menu_args, this
125
-     *                                    is used to validate that the items that should be defined
126
-     *                                    are present.
127
-     * @return void
128
-     * @throws EE_Error
129
-     * @since 4.4.0
130
-     *
131
-     */
132
-    public function __construct($menu_args, $required)
133
-    {
134
-        // filter all args before processing so plugins can manipulate various settings for menus.
135
-        $menu_args = apply_filters(
136
-            'FHEE__EE_Admin_Page_Menu_Map__construct__menu_args',
137
-            $menu_args,
138
-            $required,
139
-            get_class($this)
140
-        );
141
-
142
-
143
-        // verify that required keys are present in the incoming array.
144
-        $missing = array_diff((array) $required, array_keys((array) $menu_args));
145
-
146
-        if (! empty($missing)) {
147
-            throw new EE_Error(
148
-                sprintf(
149
-                    esc_html__(
150
-                        '%s is missing some expected keys in the argument array.  The following keys are missing: %s',
151
-                        'event_espresso'
152
-                    ),
153
-                    get_class($this),
154
-                    implode(', ', $missing)
155
-                )
156
-            );
157
-        }
158
-
159
-        // made it here okay, so let's set the properties!
160
-        foreach ($menu_args as $prop => $value) {
161
-            switch ($prop) {
162
-                case 'show_on_menu':
163
-                    $value = (int) $value;
164
-                    break;
165
-                case 'admin_init_page':
166
-                    if (in_array('admin_init_page', $required) && ! $value instanceof EE_Admin_Page_Init) {
167
-                        throw new EE_Error(
168
-                            sprintf(
169
-                                esc_html__(
170
-                                    'The value for the "admin_init_page" argument must be an instance of an EE_Admin_Page_Init object.  Instead %s was given as the value.',
171
-                                    'event_espresso'
172
-                                ),
173
-                                print_r($value, true)
174
-                            )
175
-                        );
176
-                    }
177
-                    break;
178
-                case 'menu_callback':
179
-                    break;
180
-
181
-                default:
182
-                    $value = (string) $value;
183
-                    break;
184
-            }
185
-            if (! EEH_Class_Tools::has_property($this, $prop)) {
186
-                throw new EE_Error(
187
-                    sprintf(
188
-                        esc_html__(
189
-                            'The $menu_args coming into %s has a index key (%s) representing a property that is not defined by the class.  Perhaps there is a typo?',
190
-                            'event_espresso'
191
-                        ),
192
-                        get_class($this),
193
-                        $prop
194
-                    )
195
-                );
196
-            }
197
-            $this->{$prop} = $value;
198
-        }
199
-
200
-        // filter capabilities (both static and dynamic)
201
-        $this->capability = apply_filters('FHEE_management_capability', $this->capability, null);
202
-        $this->capability = apply_filters('FHEE_' . $this->menu_slug . '_capability', $this->capability, null);
203
-
204
-        // Might need to change parent slug depending on maintenance mode.
205
-        if (
206
-            ! empty($this->maintenance_mode_parent)
207
-            && EE_Maintenance_Mode::instance()->level() == EE_Maintenance_Mode::level_2_complete_maintenance
208
-        ) {
209
-            $this->parent_slug = $this->maintenance_mode_parent;
210
-        }
211
-
212
-        // if empty menu_callback let's set default (but only if we have admin page init object)
213
-        if (empty($this->menu_callback) && $this->admin_init_page instanceof EE_Admin_Page_Init) {
214
-            $this->menu_callback = [$this->admin_init_page, 'initialize_admin_page'];
215
-        }
216
-    }
217
-
218
-
219
-    /**
220
-     * This method should define how the menu page gets added for this particular item
221
-     * and go ahead and define it.  Note that child classes MUST also return the result of
222
-     * the function used to register the WordPress admin page (the wp_page_slug string)
223
-     *
224
-     * @return string wp_page_slug.
225
-     * @since  4.4.0
226
-     */
227
-    abstract protected function _add_menu_page();
228
-
229
-
230
-    /**
231
-     * Called by client code to use this menu map for registering a WordPress admin page
232
-     *
233
-     * @param boolean $network_admin whether this is being added to the network admin page or not
234
-     * @throws EE_Error
235
-     * @throws ReflectionException
236
-     * @since  4.4.0
237
-     */
238
-    public function add_menu_page($network_admin = false)
239
-    {
240
-        $show_on_menu_int = (int) $this->show_on_menu;
241
-        if (
242
-            ($network_admin
243
-             && in_array(
244
-                 $show_on_menu_int,
245
-                 [self::BLOG_AND_NETWORK_ADMIN, self::NETWORK_ADMIN_ONLY],
246
-                 true
247
-             ))
248
-            || (! $network_admin
249
-                && in_array(
250
-                    $show_on_menu_int,
251
-                    [self::BLOG_AND_NETWORK_ADMIN, self::BLOG_ADMIN_ONLY],
252
-                    true
253
-                ))
254
-        ) {
255
-            $wp_page_slug = $this->_add_menu_page();
256
-        } else {
257
-            $wp_page_slug = '';
258
-        }
259
-
260
-        if (! empty($wp_page_slug) && $this->admin_init_page instanceof EE_Admin_Page_Init) {
261
-            try {
262
-                $this->admin_init_page->set_page_dependencies($wp_page_slug);
263
-            } catch (EE_Error $e) {
264
-                $e->get_error();
265
-            }
266
-        }
267
-    }
21
+	/**
22
+	 * The label for the menu item. (What shows up in the actual menu).
23
+	 *
24
+	 * @since 4.4.0
25
+	 * @var string
26
+	 */
27
+	public $menu_label;
28
+
29
+
30
+	/**
31
+	 * What menu item is the parent of this menu item.
32
+	 *
33
+	 * @since 4.4.0
34
+	 * @var string
35
+	 */
36
+	public $parent_slug;
37
+
38
+
39
+	/**
40
+	 * What capability is required to access this page.
41
+	 *
42
+	 * @since 4.4.0
43
+	 * @var string
44
+	 */
45
+	public $capability = 'administrator';
46
+
47
+
48
+	/**
49
+	 * What slug should be used to reference this menu item.
50
+	 *
51
+	 * @since 4.4.0
52
+	 * @var string
53
+	 */
54
+	public $menu_slug;
55
+
56
+
57
+	/**
58
+	 * The callback for displaying the page that the menu references.
59
+	 *
60
+	 * @since 4.4.0
61
+	 * @var string
62
+	 */
63
+	public $menu_callback;
64
+
65
+
66
+	/**
67
+	 * The EE_Admin_Page_Init attached to this map.
68
+	 *
69
+	 * @var EE_Admin_Page_Init
70
+	 */
71
+	public $admin_init_page;
72
+
73
+
74
+	/**
75
+	 * The EE specific group this menu item belongs in (group slug).
76
+	 *
77
+	 * @since 4.4.0
78
+	 * @var string
79
+	 */
80
+	public $menu_group;
81
+
82
+
83
+	/**
84
+	 * What order this item should be in the menu.
85
+	 *
86
+	 * @since 4.4.0
87
+	 * @var int
88
+	 */
89
+	public $menu_order;
90
+
91
+
92
+	const NONE                   = 0;
93
+
94
+	const BLOG_ADMIN_ONLY        = 1;
95
+
96
+	const BLOG_AND_NETWORK_ADMIN = 2;
97
+
98
+	const NETWORK_ADMIN_ONLY     = 3;
99
+
100
+
101
+	/**
102
+	 * Whether this item is displayed in the menu or not.
103
+	 * Sometimes an EE Admin Page needs to register itself but is not accessible via the WordPress
104
+	 * admin menu.
105
+	 *
106
+	 * @since 4.4.0
107
+	 * @var int
108
+	 */
109
+	public $show_on_menu = self::BLOG_ADMIN_ONLY;
110
+
111
+
112
+	/**
113
+	 * Menu maps can define a parent slug that gets used instead of the main parent slug for the menu when
114
+	 * EE_Maintenance_Mode::level_2_complete_maintenance is active.
115
+	 *
116
+	 * @var bool
117
+	 */
118
+	public $maintenance_mode_parent = '';
119
+
120
+
121
+	/**
122
+	 * @param array $menu_args            An array of arguments used to setup the menu
123
+	 *                                    properties on construct.
124
+	 * @param array $required             An array of keys that should be in the $menu_args, this
125
+	 *                                    is used to validate that the items that should be defined
126
+	 *                                    are present.
127
+	 * @return void
128
+	 * @throws EE_Error
129
+	 * @since 4.4.0
130
+	 *
131
+	 */
132
+	public function __construct($menu_args, $required)
133
+	{
134
+		// filter all args before processing so plugins can manipulate various settings for menus.
135
+		$menu_args = apply_filters(
136
+			'FHEE__EE_Admin_Page_Menu_Map__construct__menu_args',
137
+			$menu_args,
138
+			$required,
139
+			get_class($this)
140
+		);
141
+
142
+
143
+		// verify that required keys are present in the incoming array.
144
+		$missing = array_diff((array) $required, array_keys((array) $menu_args));
145
+
146
+		if (! empty($missing)) {
147
+			throw new EE_Error(
148
+				sprintf(
149
+					esc_html__(
150
+						'%s is missing some expected keys in the argument array.  The following keys are missing: %s',
151
+						'event_espresso'
152
+					),
153
+					get_class($this),
154
+					implode(', ', $missing)
155
+				)
156
+			);
157
+		}
158
+
159
+		// made it here okay, so let's set the properties!
160
+		foreach ($menu_args as $prop => $value) {
161
+			switch ($prop) {
162
+				case 'show_on_menu':
163
+					$value = (int) $value;
164
+					break;
165
+				case 'admin_init_page':
166
+					if (in_array('admin_init_page', $required) && ! $value instanceof EE_Admin_Page_Init) {
167
+						throw new EE_Error(
168
+							sprintf(
169
+								esc_html__(
170
+									'The value for the "admin_init_page" argument must be an instance of an EE_Admin_Page_Init object.  Instead %s was given as the value.',
171
+									'event_espresso'
172
+								),
173
+								print_r($value, true)
174
+							)
175
+						);
176
+					}
177
+					break;
178
+				case 'menu_callback':
179
+					break;
180
+
181
+				default:
182
+					$value = (string) $value;
183
+					break;
184
+			}
185
+			if (! EEH_Class_Tools::has_property($this, $prop)) {
186
+				throw new EE_Error(
187
+					sprintf(
188
+						esc_html__(
189
+							'The $menu_args coming into %s has a index key (%s) representing a property that is not defined by the class.  Perhaps there is a typo?',
190
+							'event_espresso'
191
+						),
192
+						get_class($this),
193
+						$prop
194
+					)
195
+				);
196
+			}
197
+			$this->{$prop} = $value;
198
+		}
199
+
200
+		// filter capabilities (both static and dynamic)
201
+		$this->capability = apply_filters('FHEE_management_capability', $this->capability, null);
202
+		$this->capability = apply_filters('FHEE_' . $this->menu_slug . '_capability', $this->capability, null);
203
+
204
+		// Might need to change parent slug depending on maintenance mode.
205
+		if (
206
+			! empty($this->maintenance_mode_parent)
207
+			&& EE_Maintenance_Mode::instance()->level() == EE_Maintenance_Mode::level_2_complete_maintenance
208
+		) {
209
+			$this->parent_slug = $this->maintenance_mode_parent;
210
+		}
211
+
212
+		// if empty menu_callback let's set default (but only if we have admin page init object)
213
+		if (empty($this->menu_callback) && $this->admin_init_page instanceof EE_Admin_Page_Init) {
214
+			$this->menu_callback = [$this->admin_init_page, 'initialize_admin_page'];
215
+		}
216
+	}
217
+
218
+
219
+	/**
220
+	 * This method should define how the menu page gets added for this particular item
221
+	 * and go ahead and define it.  Note that child classes MUST also return the result of
222
+	 * the function used to register the WordPress admin page (the wp_page_slug string)
223
+	 *
224
+	 * @return string wp_page_slug.
225
+	 * @since  4.4.0
226
+	 */
227
+	abstract protected function _add_menu_page();
228
+
229
+
230
+	/**
231
+	 * Called by client code to use this menu map for registering a WordPress admin page
232
+	 *
233
+	 * @param boolean $network_admin whether this is being added to the network admin page or not
234
+	 * @throws EE_Error
235
+	 * @throws ReflectionException
236
+	 * @since  4.4.0
237
+	 */
238
+	public function add_menu_page($network_admin = false)
239
+	{
240
+		$show_on_menu_int = (int) $this->show_on_menu;
241
+		if (
242
+			($network_admin
243
+			 && in_array(
244
+				 $show_on_menu_int,
245
+				 [self::BLOG_AND_NETWORK_ADMIN, self::NETWORK_ADMIN_ONLY],
246
+				 true
247
+			 ))
248
+			|| (! $network_admin
249
+				&& in_array(
250
+					$show_on_menu_int,
251
+					[self::BLOG_AND_NETWORK_ADMIN, self::BLOG_ADMIN_ONLY],
252
+					true
253
+				))
254
+		) {
255
+			$wp_page_slug = $this->_add_menu_page();
256
+		} else {
257
+			$wp_page_slug = '';
258
+		}
259
+
260
+		if (! empty($wp_page_slug) && $this->admin_init_page instanceof EE_Admin_Page_Init) {
261
+			try {
262
+				$this->admin_init_page->set_page_dependencies($wp_page_slug);
263
+			} catch (EE_Error $e) {
264
+				$e->get_error();
265
+			}
266
+		}
267
+	}
268 268
 }
Please login to merge, or discard this patch.
modules/ticket_sales_monitor/EED_Ticket_Sales_Monitor.module.php 2 patches
Spacing   +79 added lines, -79 removed lines patch added patch discarded remove patch
@@ -183,7 +183,7 @@  discard block
 block discarded – undo
183 183
     {
184 184
         // self::debug hardcoded to false
185 185
         if (self::debug) {
186
-            echo self::$nl . self::$nl . __LINE__ . ') ' . __METHOD__ . '()';
186
+            echo self::$nl.self::$nl.__LINE__.') '.__METHOD__.'()';
187 187
         }
188 188
         do_action('AHEE__EED_Ticket_Sales_Monitor__release_tickets_for_expired_carts__begin');
189 189
         $expired_ticket_IDs = array();
@@ -194,29 +194,29 @@  discard block
 block discarded – undo
194 194
         $timestamp = $session_lifespan->expiration();
195 195
         $expired_ticket_line_items = EEM_Line_Item::instance()->getTicketLineItemsForExpiredCarts($timestamp);
196 196
         if (self::debug) {
197
-            echo self::$nl . ' . time(): ' . time();
198
-            echo self::$nl . ' . time() as date: ' . date('Y-m-d H:i a');
199
-            echo self::$nl . ' . session expiration: ' . $session_lifespan->expiration();
200
-            echo self::$nl . ' . session expiration as date: ' . date('Y-m-d H:i a', $session_lifespan->expiration());
201
-            echo self::$nl . ' . timestamp: ' . $timestamp;
202
-            echo self::$nl . ' . $expired_ticket_line_items: ' . count($expired_ticket_line_items);
197
+            echo self::$nl.' . time(): '.time();
198
+            echo self::$nl.' . time() as date: '.date('Y-m-d H:i a');
199
+            echo self::$nl.' . session expiration: '.$session_lifespan->expiration();
200
+            echo self::$nl.' . session expiration as date: '.date('Y-m-d H:i a', $session_lifespan->expiration());
201
+            echo self::$nl.' . timestamp: '.$timestamp;
202
+            echo self::$nl.' . $expired_ticket_line_items: '.count($expired_ticket_line_items);
203 203
         }
204
-        if (! empty($expired_ticket_line_items)) {
204
+        if ( ! empty($expired_ticket_line_items)) {
205 205
             foreach ($expired_ticket_line_items as $expired_ticket_line_item) {
206
-                if (! $expired_ticket_line_item instanceof EE_Line_Item) {
206
+                if ( ! $expired_ticket_line_item instanceof EE_Line_Item) {
207 207
                     continue;
208 208
                 }
209
-                $expired_ticket_IDs[ $expired_ticket_line_item->OBJ_ID() ] = $expired_ticket_line_item->OBJ_ID();
209
+                $expired_ticket_IDs[$expired_ticket_line_item->OBJ_ID()] = $expired_ticket_line_item->OBJ_ID();
210 210
                 if (self::debug) {
211
-                    echo self::$nl . ' . $expired_ticket_line_item->OBJ_ID(): ' . $expired_ticket_line_item->OBJ_ID();
212
-                    echo self::$nl . ' . $expired_ticket_line_item->timestamp(): '
211
+                    echo self::$nl.' . $expired_ticket_line_item->OBJ_ID(): '.$expired_ticket_line_item->OBJ_ID();
212
+                    echo self::$nl.' . $expired_ticket_line_item->timestamp(): '
213 213
                          . date(
214 214
                              'Y-m-d h:i a',
215 215
                              $expired_ticket_line_item->timestamp(true)
216 216
                          );
217 217
                 }
218 218
             }
219
-            if (! empty($expired_ticket_IDs)) {
219
+            if ( ! empty($expired_ticket_IDs)) {
220 220
                 EED_Ticket_Sales_Monitor::release_reservations_for_tickets(
221 221
                     \EEM_Ticket::instance()->get_tickets_with_IDs($expired_ticket_IDs),
222 222
                     array(),
@@ -255,8 +255,8 @@  discard block
 block discarded – undo
255 255
         }
256 256
         // self::debug hardcoded to false
257 257
         if (self::debug) {
258
-            echo self::$nl . self::$nl . __LINE__ . ') ' . __METHOD__ . '()';
259
-            echo self::$nl . self::$nl . '<b> RETURNED QTY: ' . $qty . '</b>';
258
+            echo self::$nl.self::$nl.__LINE__.') '.__METHOD__.'()';
259
+            echo self::$nl.self::$nl.'<b> RETURNED QTY: '.$qty.'</b>';
260 260
         }
261 261
         return $qty;
262 262
     }
@@ -275,36 +275,36 @@  discard block
 block discarded – undo
275 275
     {
276 276
         // self::debug hardcoded to false
277 277
         if (self::debug) {
278
-            echo self::$nl . self::$nl . __LINE__ . ') ' . __METHOD__ . '() ';
278
+            echo self::$nl.self::$nl.__LINE__.') '.__METHOD__.'() ';
279 279
         }
280
-        if (! $ticket instanceof EE_Ticket) {
280
+        if ( ! $ticket instanceof EE_Ticket) {
281 281
             return 0;
282 282
         }
283 283
         if (self::debug) {
284
-            echo self::$nl . '<b> . ticket->ID: ' . $ticket->ID() . '</b>';
285
-            echo self::$nl . ' . original ticket->reserved: ' . $ticket->reserved();
284
+            echo self::$nl.'<b> . ticket->ID: '.$ticket->ID().'</b>';
285
+            echo self::$nl.' . original ticket->reserved: '.$ticket->reserved();
286 286
         }
287 287
         $ticket->refresh_from_db();
288 288
         // first let's determine the ticket availability based on sales
289 289
         $available = $ticket->qty('saleable');
290 290
         if (self::debug) {
291
-            echo self::$nl . ' . . . ticket->qty: ' . $ticket->qty();
292
-            echo self::$nl . ' . . . ticket->sold: ' . $ticket->sold();
293
-            echo self::$nl . ' . . . ticket->reserved: ' . $ticket->reserved();
294
-            echo self::$nl . ' . . . ticket->qty(saleable): ' . $ticket->qty('saleable');
295
-            echo self::$nl . ' . . . available: ' . $available;
291
+            echo self::$nl.' . . . ticket->qty: '.$ticket->qty();
292
+            echo self::$nl.' . . . ticket->sold: '.$ticket->sold();
293
+            echo self::$nl.' . . . ticket->reserved: '.$ticket->reserved();
294
+            echo self::$nl.' . . . ticket->qty(saleable): '.$ticket->qty('saleable');
295
+            echo self::$nl.' . . . available: '.$available;
296 296
         }
297 297
         if ($available < 1) {
298 298
             $this->_ticket_sold_out($ticket);
299 299
             return 0;
300 300
         }
301 301
         if (self::debug) {
302
-            echo self::$nl . ' . . . qty: ' . $qty;
302
+            echo self::$nl.' . . . qty: '.$qty;
303 303
         }
304 304
         if ($available < $qty) {
305 305
             $qty = $available;
306 306
             if (self::debug) {
307
-                echo self::$nl . ' . . . QTY ADJUSTED: ' . $qty;
307
+                echo self::$nl.' . . . QTY ADJUSTED: '.$qty;
308 308
             }
309 309
             $this->_ticket_quantity_decremented($ticket);
310 310
         }
@@ -328,9 +328,9 @@  discard block
 block discarded – undo
328 328
     {
329 329
         // self::debug hardcoded to false
330 330
         if (self::debug) {
331
-            echo self::$nl . self::$nl . ' . . . INCREASE RESERVED: ' . $quantity;
331
+            echo self::$nl.self::$nl.' . . . INCREASE RESERVED: '.$quantity;
332 332
         }
333
-        return $ticket->increaseReserved($quantity, 'TicketSalesMonitor:' . __LINE__);
333
+        return $ticket->increaseReserved($quantity, 'TicketSalesMonitor:'.__LINE__);
334 334
     }
335 335
 
336 336
 
@@ -344,12 +344,12 @@  discard block
 block discarded – undo
344 344
     {
345 345
         // self::debug hardcoded to false
346 346
         if (self::debug) {
347
-            echo self::$nl . ' . . . ticket->ID: ' . $ticket->ID();
348
-            echo self::$nl . ' . . . ticket->reserved before: ' . $ticket->reserved();
347
+            echo self::$nl.' . . . ticket->ID: '.$ticket->ID();
348
+            echo self::$nl.' . . . ticket->reserved before: '.$ticket->reserved();
349 349
         }
350
-        $ticket->decreaseReserved($quantity, true, 'TicketSalesMonitor:' . __LINE__);
350
+        $ticket->decreaseReserved($quantity, true, 'TicketSalesMonitor:'.__LINE__);
351 351
         if (self::debug) {
352
-            echo self::$nl . ' . . . ticket->reserved after: ' . $ticket->reserved();
352
+            echo self::$nl.' . . . ticket->reserved after: '.$ticket->reserved();
353 353
         }
354 354
         return $ticket->save() ? 1 : 0;
355 355
     }
@@ -367,8 +367,8 @@  discard block
 block discarded – undo
367 367
     {
368 368
         // self::debug hardcoded to false
369 369
         if (self::debug) {
370
-            echo self::$nl . self::$nl . __LINE__ . ') ' . __METHOD__ . '() ';
371
-            echo self::$nl . ' . . ticket->name: ' . $this->_get_ticket_and_event_name($ticket);
370
+            echo self::$nl.self::$nl.__LINE__.') '.__METHOD__.'() ';
371
+            echo self::$nl.' . . ticket->name: '.$this->_get_ticket_and_event_name($ticket);
372 372
         }
373 373
         $this->sold_out_tickets[] = $this->_get_ticket_and_event_name($ticket);
374 374
     }
@@ -386,8 +386,8 @@  discard block
 block discarded – undo
386 386
     {
387 387
         // self::debug hardcoded to false
388 388
         if (self::debug) {
389
-            echo self::$nl . self::$nl . __LINE__ . ') ' . __METHOD__ . '() ';
390
-            echo self::$nl . ' . . ticket->name: ' . $this->_get_ticket_and_event_name($ticket);
389
+            echo self::$nl.self::$nl.__LINE__.') '.__METHOD__.'() ';
390
+            echo self::$nl.' . . ticket->name: '.$this->_get_ticket_and_event_name($ticket);
391 391
         }
392 392
         $this->decremented_tickets[] = $this->_get_ticket_and_event_name($ticket);
393 393
     }
@@ -438,7 +438,7 @@  discard block
 block discarded – undo
438 438
         if ($ticket instanceof EE_Ticket) {
439 439
             $ticket->add_extra_meta(
440 440
                 EE_Ticket::META_KEY_TICKET_RESERVATIONS,
441
-                __LINE__ . ') ' . __METHOD__ . '()'
441
+                __LINE__.') '.__METHOD__.'()'
442 442
             );
443 443
             if ($quantity > 0) {
444 444
                 EED_Ticket_Sales_Monitor::instance()->_reserve_ticket($ticket, $quantity);
@@ -461,7 +461,7 @@  discard block
 block discarded – undo
461 461
     {
462 462
         $ticket->add_extra_meta(
463 463
             EE_Ticket::META_KEY_TICKET_RESERVATIONS,
464
-            __LINE__ . ') ' . __METHOD__ . '()'
464
+            __LINE__.') '.__METHOD__.'()'
465 465
         );
466 466
         EED_Ticket_Sales_Monitor::instance()->_release_reserved_ticket($ticket, $quantity);
467 467
     }
@@ -497,7 +497,7 @@  discard block
 block discarded – undo
497 497
     {
498 498
         // self::debug hardcoded to false
499 499
         if (self::debug) {
500
-            echo self::$nl . self::$nl . __LINE__ . ') ' . __METHOD__ . '() ';
500
+            echo self::$nl.self::$nl.__LINE__.') '.__METHOD__.'() ';
501 501
         }
502 502
         $refresh_msg = '';
503 503
         $none_added_msg = '';
@@ -508,7 +508,7 @@  discard block
 block discarded – undo
508 508
             );
509 509
             $none_added_msg = esc_html__('No tickets were added for the event.', 'event_espresso');
510 510
         }
511
-        if (! empty($this->sold_out_tickets)) {
511
+        if ( ! empty($this->sold_out_tickets)) {
512 512
             EE_Error::add_attention(
513 513
                 sprintf(
514 514
                     apply_filters(
@@ -531,7 +531,7 @@  discard block
 block discarded – undo
531 531
             // and reset the cart
532 532
             EED_Ticket_Sales_Monitor::session_cart_reset(EE_Registry::instance()->SSN);
533 533
         }
534
-        if (! empty($this->decremented_tickets)) {
534
+        if ( ! empty($this->decremented_tickets)) {
535 535
             EE_Error::add_attention(
536 536
                 sprintf(
537 537
                     apply_filters(
@@ -569,9 +569,9 @@  discard block
 block discarded – undo
569 569
     {
570 570
         // self::debug hardcoded to false
571 571
         if (self::debug) {
572
-            echo self::$nl . self::$nl . __LINE__ . ') ' . __METHOD__ . '() ';
573
-            echo self::$nl . ' . transaction->ID: ' . $transaction->ID();
574
-            echo self::$nl . ' . TXN status_ID: ' . $transaction->status_ID();
572
+            echo self::$nl.self::$nl.__LINE__.') '.__METHOD__.'() ';
573
+            echo self::$nl.' . transaction->ID: '.$transaction->ID();
574
+            echo self::$nl.' . TXN status_ID: '.$transaction->status_ID();
575 575
         }
576 576
         // check if 'finalize_registration' step has been completed...
577 577
         $finalized = $transaction->reg_step_completed('finalize_registration');
@@ -583,13 +583,13 @@  discard block
 block discarded – undo
583 583
                 __LINE__,
584 584
                 array('finalized' => $finalized),
585 585
                 false,
586
-                'EE_Transaction: ' . $transaction->ID()
586
+                'EE_Transaction: '.$transaction->ID()
587 587
             );
588 588
         }
589 589
         // how many tickets were released
590 590
         $count = 0;
591 591
         if (self::debug) {
592
-            echo self::$nl . ' . . . TXN finalized: ' . $finalized;
592
+            echo self::$nl.' . . . TXN finalized: '.$finalized;
593 593
         }
594 594
         $release_tickets_with_TXN_status = array(
595 595
             EEM_Transaction::failed_status_code,
@@ -598,28 +598,28 @@  discard block
 block discarded – undo
598 598
         );
599 599
         $events = array();
600 600
         // if the session is getting cleared BEFORE the TXN has been finalized or the transaction is not completed
601
-        if (! $finalized || in_array($transaction->status_ID(), $release_tickets_with_TXN_status, true)) {
601
+        if ( ! $finalized || in_array($transaction->status_ID(), $release_tickets_with_TXN_status, true)) {
602 602
             // cancel any reserved tickets for registrations that were not approved
603 603
             $registrations = $transaction->registrations();
604 604
             if (self::debug) {
605
-                echo self::$nl . ' . . . # registrations: ' . count($registrations);
605
+                echo self::$nl.' . . . # registrations: '.count($registrations);
606 606
                 $reg = reset($registrations);
607 607
                 $ticket = $reg->ticket();
608 608
                 if ($ticket instanceof EE_Ticket) {
609 609
                     $ticket->add_extra_meta(
610 610
                         EE_Ticket::META_KEY_TICKET_RESERVATIONS,
611
-                        __LINE__ . ') Release All Tickets TXN:' . $transaction->ID()
611
+                        __LINE__.') Release All Tickets TXN:'.$transaction->ID()
612 612
                     );
613 613
                 }
614 614
             }
615
-            if (! empty($registrations)) {
615
+            if ( ! empty($registrations)) {
616 616
                 foreach ($registrations as $registration) {
617 617
                     if (
618 618
                         $registration instanceof EE_Registration
619 619
                         && $this->_release_reserved_ticket_for_registration($registration, $transaction)
620 620
                     ) {
621 621
                         $count++;
622
-                        $events[ $registration->event_ID() ] = $registration->event();
622
+                        $events[$registration->event_ID()] = $registration->event();
623 623
                     }
624 624
                 }
625 625
             }
@@ -650,10 +650,10 @@  discard block
 block discarded – undo
650 650
         $STS_ID = $transaction->status_ID();
651 651
         // self::debug hardcoded to false
652 652
         if (self::debug) {
653
-            echo self::$nl . self::$nl . __LINE__ . ') ' . __METHOD__ . '() ';
654
-            echo self::$nl . ' . . registration->ID: ' . $registration->ID();
655
-            echo self::$nl . ' . . registration->status_ID: ' . $registration->status_ID();
656
-            echo self::$nl . ' . . transaction->status_ID(): ' . $STS_ID;
653
+            echo self::$nl.self::$nl.__LINE__.') '.__METHOD__.'() ';
654
+            echo self::$nl.' . . registration->ID: '.$registration->ID();
655
+            echo self::$nl.' . . registration->status_ID: '.$registration->status_ID();
656
+            echo self::$nl.' . . transaction->status_ID(): '.$STS_ID;
657 657
         }
658 658
         if (
659 659
 // release Tickets for Failed Transactions and Abandoned Transactions
@@ -666,12 +666,12 @@  discard block
 block discarded – undo
666 666
             )
667 667
         ) {
668 668
             if (self::debug) {
669
-                echo self::$nl . self::$nl . ' . . RELEASE RESERVED TICKET';
669
+                echo self::$nl.self::$nl.' . . RELEASE RESERVED TICKET';
670 670
                 $rsrvd = $registration->get_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, true);
671
-                echo self::$nl . ' . . . registration HAS_RESERVED_TICKET_KEY: ';
671
+                echo self::$nl.' . . . registration HAS_RESERVED_TICKET_KEY: ';
672 672
                 var_dump($rsrvd);
673 673
             }
674
-            $registration->release_reserved_ticket(true, 'TicketSalesMonitor:' . __LINE__);
674
+            $registration->release_reserved_ticket(true, 'TicketSalesMonitor:'.__LINE__);
675 675
             return 1;
676 676
         }
677 677
         return 0;
@@ -701,7 +701,7 @@  discard block
 block discarded – undo
701 701
         }
702 702
         // self::debug hardcoded to false
703 703
         if (self::debug) {
704
-            echo self::$nl . self::$nl . __LINE__ . ') ' . __METHOD__ . '() ';
704
+            echo self::$nl.self::$nl.__LINE__.') '.__METHOD__.'() ';
705 705
         }
706 706
         // first check of the session has a valid Checkout object
707 707
         $checkout = $session->checkout();
@@ -713,12 +713,12 @@  discard block
 block discarded – undo
713 713
         $cart = $session->cart();
714 714
         if ($cart instanceof EE_Cart) {
715 715
             if (self::debug) {
716
-                echo self::$nl . self::$nl . ' cart instance of EE_Cart: ';
716
+                echo self::$nl.self::$nl.' cart instance of EE_Cart: ';
717 717
             }
718 718
             EED_Ticket_Sales_Monitor::instance()->_session_cart_reset($cart, $session);
719 719
         } else {
720 720
             if (self::debug) {
721
-                echo self::$nl . self::$nl . ' invalid EE_Cart: ';
721
+                echo self::$nl.self::$nl.' invalid EE_Cart: ';
722 722
                 var_export($cart, true);
723 723
             }
724 724
         }
@@ -740,39 +740,39 @@  discard block
 block discarded – undo
740 740
     {
741 741
         // self::debug hardcoded to false
742 742
         if (self::debug) {
743
-            echo self::$nl . self::$nl . __LINE__ . ') ' . __METHOD__ . '() ';
743
+            echo self::$nl.self::$nl.__LINE__.') '.__METHOD__.'() ';
744 744
         }
745 745
         $ticket_line_items = $cart->get_tickets();
746 746
         if (empty($ticket_line_items)) {
747 747
             return;
748 748
         }
749 749
         if (self::debug) {
750
-            echo '<br /> . ticket_line_item count: ' . count($ticket_line_items);
750
+            echo '<br /> . ticket_line_item count: '.count($ticket_line_items);
751 751
         }
752 752
         foreach ($ticket_line_items as $ticket_line_item) {
753 753
             if (self::debug) {
754
-                echo self::$nl . ' . ticket_line_item->ID(): ' . $ticket_line_item->ID();
754
+                echo self::$nl.' . ticket_line_item->ID(): '.$ticket_line_item->ID();
755 755
             }
756 756
             if ($ticket_line_item instanceof EE_Line_Item && $ticket_line_item->OBJ_type() === 'Ticket') {
757 757
                 if (self::debug) {
758
-                    echo self::$nl . ' . . ticket_line_item->OBJ_ID(): ' . $ticket_line_item->OBJ_ID();
758
+                    echo self::$nl.' . . ticket_line_item->OBJ_ID(): '.$ticket_line_item->OBJ_ID();
759 759
                 }
760 760
                 $ticket = EEM_Ticket::instance()->get_one_by_ID($ticket_line_item->OBJ_ID());
761 761
                 if ($ticket instanceof EE_Ticket) {
762 762
                     if (self::debug) {
763
-                        echo self::$nl . ' . . ticket->ID(): ' . $ticket->ID();
764
-                        echo self::$nl . ' . . ticket_line_item->quantity(): ' . $ticket_line_item->quantity();
763
+                        echo self::$nl.' . . ticket->ID(): '.$ticket->ID();
764
+                        echo self::$nl.' . . ticket_line_item->quantity(): '.$ticket_line_item->quantity();
765 765
                     }
766 766
                     $ticket->add_extra_meta(
767 767
                         EE_Ticket::META_KEY_TICKET_RESERVATIONS,
768
-                        __LINE__ . ') ' . __METHOD__ . '() SID = ' . $session->id()
768
+                        __LINE__.') '.__METHOD__.'() SID = '.$session->id()
769 769
                     );
770 770
                     $this->_release_reserved_ticket($ticket, $ticket_line_item->quantity());
771 771
                 }
772 772
             }
773 773
         }
774 774
         if (self::debug) {
775
-            echo self::$nl . self::$nl . ' RESET COMPLETED ';
775
+            echo self::$nl.self::$nl.' RESET COMPLETED ';
776 776
         }
777 777
     }
778 778
 
@@ -814,7 +814,7 @@  discard block
 block discarded – undo
814 814
     {
815 815
         // self::debug hardcoded to false
816 816
         if (self::debug) {
817
-            echo self::$nl . self::$nl . __LINE__ . ') ' . __METHOD__ . '() ';
817
+            echo self::$nl.self::$nl.__LINE__.') '.__METHOD__.'() ';
818 818
         }
819 819
         // we want to release the each registration's reserved tickets if the session was cleared, but not if this is a revisit
820 820
         if ($checkout->revisit || ! $checkout->transaction instanceof EE_Transaction) {
@@ -863,7 +863,7 @@  discard block
 block discarded – undo
863 863
                     __LINE__,
864 864
                     array($transaction),
865 865
                     false,
866
-                    'EE_Transaction: ' . $transaction->ID()
866
+                    'EE_Transaction: '.$transaction->ID()
867 867
                 );
868 868
             }
869 869
             return;
@@ -880,7 +880,7 @@  discard block
 block discarded – undo
880 880
                         __LINE__,
881 881
                         array($payment),
882 882
                         false,
883
-                        'EE_Transaction: ' . $transaction->ID()
883
+                        'EE_Transaction: '.$transaction->ID()
884 884
                     );
885 885
                 }
886 886
                 return;
@@ -942,7 +942,7 @@  discard block
 block discarded – undo
942 942
             }
943 943
             $total_line_item = $transaction->total_line_item();
944 944
             // $transaction_in_progress->line
945
-            if (! $total_line_item instanceof EE_Line_Item) {
945
+            if ( ! $total_line_item instanceof EE_Line_Item) {
946 946
                 throw new DomainException(
947 947
                     esc_html__(
948 948
                         'Transaction does not have a valid Total Line Item associated with it.',
@@ -980,7 +980,7 @@  discard block
 block discarded – undo
980 980
         $ticket_line_items = EEH_Line_Item::get_ticket_line_items($total_line_item);
981 981
         foreach ($ticket_line_items as $ticket_line_item) {
982 982
             if ($ticket_line_item instanceof EE_Line_Item) {
983
-                $valid_reserved_tickets[ $ticket_line_item->ID() ] = $ticket_line_item;
983
+                $valid_reserved_tickets[$ticket_line_item->ID()] = $ticket_line_item;
984 984
             }
985 985
         }
986 986
         return $valid_reserved_tickets;
@@ -1013,7 +1013,7 @@  discard block
 block discarded – undo
1013 1013
         $total_tickets_released = 0;
1014 1014
         $sold_out_events = array();
1015 1015
         foreach ($tickets_with_reservations as $ticket_with_reservations) {
1016
-            if (! $ticket_with_reservations instanceof EE_Ticket) {
1016
+            if ( ! $ticket_with_reservations instanceof EE_Ticket) {
1017 1017
                 continue;
1018 1018
             }
1019 1019
             // The $valid_reserved_ticket_line_items tells us what the reserved count on their tickets (and datetimes)
@@ -1035,9 +1035,9 @@  discard block
 block discarded – undo
1035 1035
             if ($expired_reservations_count > 0) {
1036 1036
                 $ticket_with_reservations->add_extra_meta(
1037 1037
                     EE_Ticket::META_KEY_TICKET_RESERVATIONS,
1038
-                    __LINE__ . ') ' . $source . '()'
1038
+                    __LINE__.') '.$source.'()'
1039 1039
                 );
1040
-                $ticket_with_reservations->decreaseReserved($expired_reservations_count, true, 'TicketSalesMonitor:' . __LINE__);
1040
+                $ticket_with_reservations->decreaseReserved($expired_reservations_count, true, 'TicketSalesMonitor:'.__LINE__);
1041 1041
                 $total_tickets_released += $expired_reservations_count;
1042 1042
                 $event = $ticket_with_reservations->get_related_event();
1043 1043
                 // track sold out events
@@ -1073,7 +1073,7 @@  discard block
 block discarded – undo
1073 1073
     {
1074 1074
         /** @type WPDB $wpdb */
1075 1075
         global $wpdb;
1076
-        if (! absint($timestamp)) {
1076
+        if ( ! absint($timestamp)) {
1077 1077
             /** @var EventEspresso\core\domain\values\session\SessionLifespan $session_lifespan */
1078 1078
             $session_lifespan = LoaderFactory::getLoader()->getShared(
1079 1079
                 'EventEspresso\core\domain\values\session\SessionLifespan'
@@ -1082,7 +1082,7 @@  discard block
 block discarded – undo
1082 1082
         }
1083 1083
         return $wpdb->query(
1084 1084
             $wpdb->prepare(
1085
-                'DELETE FROM ' . EEM_Line_Item::instance()->table() . '
1085
+                'DELETE FROM '.EEM_Line_Item::instance()->table().'
1086 1086
                 WHERE TXN_ID = 0 AND LIN_timestamp <= %s',
1087 1087
                 // use GMT time because that's what LIN_timestamps are in
1088 1088
                 date('Y-m-d H:i:s', $timestamp)
Please login to merge, or discard this patch.
Indentation   +1067 added lines, -1067 removed lines patch added patch discarded remove patch
@@ -19,1073 +19,1073 @@
 block discarded – undo
19 19
  */
20 20
 class EED_Ticket_Sales_Monitor extends EED_Module
21 21
 {
22
-    const debug = false;
23
-
24
-    private static $nl = '';
25
-
26
-    /**
27
-     * an array of raw ticket data from EED_Ticket_Selector
28
-     *
29
-     * @var array $ticket_selections
30
-     */
31
-    protected $ticket_selections = array();
32
-
33
-    /**
34
-     * the raw ticket data from EED_Ticket_Selector is organized in rows
35
-     * according to how they are displayed in the actual Ticket_Selector
36
-     * this tracks the current row being processed
37
-     *
38
-     * @var int $current_row
39
-     */
40
-    protected $current_row = 0;
41
-
42
-    /**
43
-     * an array for tracking names of tickets that have sold out
44
-     *
45
-     * @var array $sold_out_tickets
46
-     */
47
-    protected $sold_out_tickets = array();
48
-
49
-    /**
50
-     * an array for tracking names of tickets that have had their quantities reduced
51
-     *
52
-     * @var array $decremented_tickets
53
-     */
54
-    protected $decremented_tickets = array();
55
-
56
-
57
-    /**
58
-     * set_hooks - for hooking into EE Core, other modules, etc
59
-     *
60
-     * @return    void
61
-     */
62
-    public static function set_hooks()
63
-    {
64
-        self::$nl = defined('EE_TESTS_DIR') ? "\n" : '<br />';
65
-        // release tickets for expired carts
66
-        add_action(
67
-            'EED_Ticket_Selector__process_ticket_selections__before',
68
-            array('EED_Ticket_Sales_Monitor', 'release_tickets_for_expired_carts'),
69
-            1
70
-        );
71
-        // check ticket reserves AFTER MER does it's check (hence priority 20)
72
-        add_filter(
73
-            'FHEE__EE_Ticket_Selector___add_ticket_to_cart__ticket_qty',
74
-            array('EED_Ticket_Sales_Monitor', 'validate_ticket_sale'),
75
-            20,
76
-            3
77
-        );
78
-        // add notices for sold out tickets
79
-        add_action(
80
-            'AHEE__EE_Ticket_Selector__process_ticket_selections__after_tickets_added_to_cart',
81
-            array('EED_Ticket_Sales_Monitor', 'post_notices'),
82
-            10
83
-        );
84
-
85
-        // handle tickets deleted from cart
86
-        add_action(
87
-            'FHEE__EED_Multi_Event_Registration__delete_ticket__ticket_removed_from_cart',
88
-            array('EED_Ticket_Sales_Monitor', 'ticket_removed_from_cart'),
89
-            10,
90
-            2
91
-        );
92
-        // handle emptied carts
93
-        add_action(
94
-            'AHEE__EE_Session__reset_cart__before_reset',
95
-            array('EED_Ticket_Sales_Monitor', 'session_cart_reset'),
96
-            10,
97
-            1
98
-        );
99
-        add_action(
100
-            'AHEE__EED_Multi_Event_Registration__empty_event_cart__before_delete_cart',
101
-            array('EED_Ticket_Sales_Monitor', 'session_cart_reset'),
102
-            10,
103
-            1
104
-        );
105
-        // handle cancelled registrations
106
-        add_action(
107
-            'AHEE__EE_Session__reset_checkout__before_reset',
108
-            array('EED_Ticket_Sales_Monitor', 'session_checkout_reset'),
109
-            10,
110
-            1
111
-        );
112
-        // cron tasks
113
-        add_action(
114
-            'AHEE__EE_Cron_Tasks__process_expired_transactions__abandoned_transaction',
115
-            array('EED_Ticket_Sales_Monitor', 'process_abandoned_transactions'),
116
-            10,
117
-            1
118
-        );
119
-        add_action(
120
-            'AHEE__EE_Cron_Tasks__process_expired_transactions__incomplete_transaction',
121
-            array('EED_Ticket_Sales_Monitor', 'process_abandoned_transactions'),
122
-            10,
123
-            1
124
-        );
125
-        add_action(
126
-            'AHEE__EE_Cron_Tasks__process_expired_transactions__failed_transaction',
127
-            array('EED_Ticket_Sales_Monitor', 'process_failed_transactions'),
128
-            10,
129
-            1
130
-        );
131
-    }
132
-
133
-
134
-    /**
135
-     * set_hooks_admin - for hooking into EE Admin Core, other modules, etc
136
-     *
137
-     * @return void
138
-     */
139
-    public static function set_hooks_admin()
140
-    {
141
-        EED_Ticket_Sales_Monitor::set_hooks();
142
-    }
143
-
144
-
145
-    /**
146
-     * @return EED_Ticket_Sales_Monitor|EED_Module
147
-     */
148
-    public static function instance()
149
-    {
150
-        return parent::get_instance(__CLASS__);
151
-    }
152
-
153
-
154
-    /**
155
-     * @param WP_Query $WP_Query
156
-     * @return    void
157
-     */
158
-    public function run($WP_Query)
159
-    {
160
-    }
161
-
162
-
163
-
164
-    /********************************** PRE_TICKET_SALES  **********************************/
165
-
166
-
167
-    /**
168
-     * Retrieves grand totals from the line items that have no TXN ID
169
-     * and timestamps less than the current time minus the session lifespan.
170
-     * These are carts that have been abandoned before the "registrant" even attempted to checkout.
171
-     * We're going to release the tickets for these line items before attempting to add more to the cart.
172
-     *
173
-     * @return void
174
-     * @throws DomainException
175
-     * @throws EE_Error
176
-     * @throws InvalidArgumentException
177
-     * @throws InvalidDataTypeException
178
-     * @throws InvalidInterfaceException
179
-     * @throws UnexpectedEntityException
180
-     */
181
-    public static function release_tickets_for_expired_carts()
182
-    {
183
-        // self::debug hardcoded to false
184
-        if (self::debug) {
185
-            echo self::$nl . self::$nl . __LINE__ . ') ' . __METHOD__ . '()';
186
-        }
187
-        do_action('AHEE__EED_Ticket_Sales_Monitor__release_tickets_for_expired_carts__begin');
188
-        $expired_ticket_IDs = array();
189
-        /** @var EventEspresso\core\domain\values\session\SessionLifespan $session_lifespan */
190
-        $session_lifespan = LoaderFactory::getLoader()->getShared(
191
-            'EventEspresso\core\domain\values\session\SessionLifespan'
192
-        );
193
-        $timestamp = $session_lifespan->expiration();
194
-        $expired_ticket_line_items = EEM_Line_Item::instance()->getTicketLineItemsForExpiredCarts($timestamp);
195
-        if (self::debug) {
196
-            echo self::$nl . ' . time(): ' . time();
197
-            echo self::$nl . ' . time() as date: ' . date('Y-m-d H:i a');
198
-            echo self::$nl . ' . session expiration: ' . $session_lifespan->expiration();
199
-            echo self::$nl . ' . session expiration as date: ' . date('Y-m-d H:i a', $session_lifespan->expiration());
200
-            echo self::$nl . ' . timestamp: ' . $timestamp;
201
-            echo self::$nl . ' . $expired_ticket_line_items: ' . count($expired_ticket_line_items);
202
-        }
203
-        if (! empty($expired_ticket_line_items)) {
204
-            foreach ($expired_ticket_line_items as $expired_ticket_line_item) {
205
-                if (! $expired_ticket_line_item instanceof EE_Line_Item) {
206
-                    continue;
207
-                }
208
-                $expired_ticket_IDs[ $expired_ticket_line_item->OBJ_ID() ] = $expired_ticket_line_item->OBJ_ID();
209
-                if (self::debug) {
210
-                    echo self::$nl . ' . $expired_ticket_line_item->OBJ_ID(): ' . $expired_ticket_line_item->OBJ_ID();
211
-                    echo self::$nl . ' . $expired_ticket_line_item->timestamp(): '
212
-                         . date(
213
-                             'Y-m-d h:i a',
214
-                             $expired_ticket_line_item->timestamp(true)
215
-                         );
216
-                }
217
-            }
218
-            if (! empty($expired_ticket_IDs)) {
219
-                EED_Ticket_Sales_Monitor::release_reservations_for_tickets(
220
-                    \EEM_Ticket::instance()->get_tickets_with_IDs($expired_ticket_IDs),
221
-                    array(),
222
-                    __FUNCTION__
223
-                );
224
-                // now  let's get rid of expired line items so that they can't interfere with tracking
225
-                EED_Ticket_Sales_Monitor::clear_expired_line_items_with_no_transaction($timestamp);
226
-            }
227
-        }
228
-        do_action(
229
-            'AHEE__EED_Ticket_Sales_Monitor__release_tickets_for_expired_carts__end',
230
-            $expired_ticket_IDs,
231
-            $expired_ticket_line_items
232
-        );
233
-    }
234
-
235
-
236
-
237
-    /********************************** VALIDATE_TICKET_SALE  **********************************/
238
-
239
-
240
-    /**
241
-     * callback for 'FHEE__EED_Ticket_Selector__process_ticket_selections__valid_post_data'
242
-     *
243
-     * @param int       $qty
244
-     * @param EE_Ticket $ticket
245
-     * @return bool
246
-     * @throws UnexpectedEntityException
247
-     * @throws EE_Error
248
-     */
249
-    public static function validate_ticket_sale($qty, EE_Ticket $ticket)
250
-    {
251
-        $qty = absint($qty);
252
-        if ($qty > 0) {
253
-            $qty = EED_Ticket_Sales_Monitor::instance()->_validate_ticket_sale($ticket, $qty);
254
-        }
255
-        // self::debug hardcoded to false
256
-        if (self::debug) {
257
-            echo self::$nl . self::$nl . __LINE__ . ') ' . __METHOD__ . '()';
258
-            echo self::$nl . self::$nl . '<b> RETURNED QTY: ' . $qty . '</b>';
259
-        }
260
-        return $qty;
261
-    }
262
-
263
-
264
-    /**
265
-     * checks whether an individual ticket is available for purchase based on datetime, and ticket details
266
-     *
267
-     * @param   EE_Ticket $ticket
268
-     * @param int         $qty
269
-     * @return int
270
-     * @throws UnexpectedEntityException
271
-     * @throws EE_Error
272
-     */
273
-    protected function _validate_ticket_sale(EE_Ticket $ticket, $qty = 1)
274
-    {
275
-        // self::debug hardcoded to false
276
-        if (self::debug) {
277
-            echo self::$nl . self::$nl . __LINE__ . ') ' . __METHOD__ . '() ';
278
-        }
279
-        if (! $ticket instanceof EE_Ticket) {
280
-            return 0;
281
-        }
282
-        if (self::debug) {
283
-            echo self::$nl . '<b> . ticket->ID: ' . $ticket->ID() . '</b>';
284
-            echo self::$nl . ' . original ticket->reserved: ' . $ticket->reserved();
285
-        }
286
-        $ticket->refresh_from_db();
287
-        // first let's determine the ticket availability based on sales
288
-        $available = $ticket->qty('saleable');
289
-        if (self::debug) {
290
-            echo self::$nl . ' . . . ticket->qty: ' . $ticket->qty();
291
-            echo self::$nl . ' . . . ticket->sold: ' . $ticket->sold();
292
-            echo self::$nl . ' . . . ticket->reserved: ' . $ticket->reserved();
293
-            echo self::$nl . ' . . . ticket->qty(saleable): ' . $ticket->qty('saleable');
294
-            echo self::$nl . ' . . . available: ' . $available;
295
-        }
296
-        if ($available < 1) {
297
-            $this->_ticket_sold_out($ticket);
298
-            return 0;
299
-        }
300
-        if (self::debug) {
301
-            echo self::$nl . ' . . . qty: ' . $qty;
302
-        }
303
-        if ($available < $qty) {
304
-            $qty = $available;
305
-            if (self::debug) {
306
-                echo self::$nl . ' . . . QTY ADJUSTED: ' . $qty;
307
-            }
308
-            $this->_ticket_quantity_decremented($ticket);
309
-        }
310
-        if ($this->_reserve_ticket($ticket, $qty)) {
311
-            return $qty;
312
-        } else {
313
-            return 0;
314
-        }
315
-    }
316
-
317
-
318
-    /**
319
-     * increments ticket reserved based on quantity passed
320
-     *
321
-     * @param    EE_Ticket $ticket
322
-     * @param int          $quantity
323
-     * @return bool indicating success or failure
324
-     * @throws EE_Error
325
-     */
326
-    protected function _reserve_ticket(EE_Ticket $ticket, $quantity = 1)
327
-    {
328
-        // self::debug hardcoded to false
329
-        if (self::debug) {
330
-            echo self::$nl . self::$nl . ' . . . INCREASE RESERVED: ' . $quantity;
331
-        }
332
-        return $ticket->increaseReserved($quantity, 'TicketSalesMonitor:' . __LINE__);
333
-    }
334
-
335
-
336
-    /**
337
-     * @param  EE_Ticket $ticket
338
-     * @param  int       $quantity
339
-     * @return bool
340
-     * @throws EE_Error
341
-     */
342
-    protected function _release_reserved_ticket(EE_Ticket $ticket, $quantity = 1)
343
-    {
344
-        // self::debug hardcoded to false
345
-        if (self::debug) {
346
-            echo self::$nl . ' . . . ticket->ID: ' . $ticket->ID();
347
-            echo self::$nl . ' . . . ticket->reserved before: ' . $ticket->reserved();
348
-        }
349
-        $ticket->decreaseReserved($quantity, true, 'TicketSalesMonitor:' . __LINE__);
350
-        if (self::debug) {
351
-            echo self::$nl . ' . . . ticket->reserved after: ' . $ticket->reserved();
352
-        }
353
-        return $ticket->save() ? 1 : 0;
354
-    }
355
-
356
-
357
-    /**
358
-     * removes quantities within the ticket selector based on zero ticket availability
359
-     *
360
-     * @param    EE_Ticket $ticket
361
-     * @return    void
362
-     * @throws UnexpectedEntityException
363
-     * @throws EE_Error
364
-     */
365
-    protected function _ticket_sold_out(EE_Ticket $ticket)
366
-    {
367
-        // self::debug hardcoded to false
368
-        if (self::debug) {
369
-            echo self::$nl . self::$nl . __LINE__ . ') ' . __METHOD__ . '() ';
370
-            echo self::$nl . ' . . ticket->name: ' . $this->_get_ticket_and_event_name($ticket);
371
-        }
372
-        $this->sold_out_tickets[] = $this->_get_ticket_and_event_name($ticket);
373
-    }
374
-
375
-
376
-    /**
377
-     * adjusts quantities within the ticket selector based on decreased ticket availability
378
-     *
379
-     * @param    EE_Ticket $ticket
380
-     * @return void
381
-     * @throws UnexpectedEntityException
382
-     * @throws EE_Error
383
-     */
384
-    protected function _ticket_quantity_decremented(EE_Ticket $ticket)
385
-    {
386
-        // self::debug hardcoded to false
387
-        if (self::debug) {
388
-            echo self::$nl . self::$nl . __LINE__ . ') ' . __METHOD__ . '() ';
389
-            echo self::$nl . ' . . ticket->name: ' . $this->_get_ticket_and_event_name($ticket);
390
-        }
391
-        $this->decremented_tickets[] = $this->_get_ticket_and_event_name($ticket);
392
-    }
393
-
394
-
395
-    /**
396
-     * builds string out of ticket and event name
397
-     *
398
-     * @param    EE_Ticket $ticket
399
-     * @return string
400
-     * @throws UnexpectedEntityException
401
-     * @throws EE_Error
402
-     */
403
-    protected function _get_ticket_and_event_name(EE_Ticket $ticket)
404
-    {
405
-        $event = $ticket->get_related_event();
406
-        if ($event instanceof EE_Event) {
407
-            $ticket_name = sprintf(
408
-                _x('%1$s for %2$s', 'ticket name for event name', 'event_espresso'),
409
-                $ticket->name(),
410
-                $event->name()
411
-            );
412
-        } else {
413
-            $ticket_name = $ticket->name();
414
-        }
415
-        return $ticket_name;
416
-    }
417
-
418
-
419
-
420
-    /********************************** EVENT CART  **********************************/
421
-
422
-
423
-    /**
424
-     * releases or reserves ticket(s) based on quantity passed
425
-     *
426
-     * @param  EE_Line_Item $line_item
427
-     * @param  int          $quantity
428
-     * @return void
429
-     * @throws EE_Error
430
-     * @throws InvalidArgumentException
431
-     * @throws InvalidDataTypeException
432
-     * @throws InvalidInterfaceException
433
-     */
434
-    public static function ticket_quantity_updated(EE_Line_Item $line_item, $quantity = 1)
435
-    {
436
-        $ticket = EEM_Ticket::instance()->get_one_by_ID(absint($line_item->OBJ_ID()));
437
-        if ($ticket instanceof EE_Ticket) {
438
-            $ticket->add_extra_meta(
439
-                EE_Ticket::META_KEY_TICKET_RESERVATIONS,
440
-                __LINE__ . ') ' . __METHOD__ . '()'
441
-            );
442
-            if ($quantity > 0) {
443
-                EED_Ticket_Sales_Monitor::instance()->_reserve_ticket($ticket, $quantity);
444
-            } else {
445
-                EED_Ticket_Sales_Monitor::instance()->_release_reserved_ticket($ticket, $quantity);
446
-            }
447
-        }
448
-    }
449
-
450
-
451
-    /**
452
-     * releases reserved ticket(s) based on quantity passed
453
-     *
454
-     * @param  EE_Ticket $ticket
455
-     * @param  int       $quantity
456
-     * @return void
457
-     * @throws EE_Error
458
-     */
459
-    public static function ticket_removed_from_cart(EE_Ticket $ticket, $quantity = 1)
460
-    {
461
-        $ticket->add_extra_meta(
462
-            EE_Ticket::META_KEY_TICKET_RESERVATIONS,
463
-            __LINE__ . ') ' . __METHOD__ . '()'
464
-        );
465
-        EED_Ticket_Sales_Monitor::instance()->_release_reserved_ticket($ticket, $quantity);
466
-    }
467
-
468
-
469
-
470
-    /********************************** POST_NOTICES  **********************************/
471
-
472
-
473
-    /**
474
-     * @return void
475
-     * @throws EE_Error
476
-     * @throws InvalidArgumentException
477
-     * @throws ReflectionException
478
-     * @throws InvalidDataTypeException
479
-     * @throws InvalidInterfaceException
480
-     */
481
-    public static function post_notices()
482
-    {
483
-        EED_Ticket_Sales_Monitor::instance()->_post_notices();
484
-    }
485
-
486
-
487
-    /**
488
-     * @return void
489
-     * @throws EE_Error
490
-     * @throws InvalidArgumentException
491
-     * @throws ReflectionException
492
-     * @throws InvalidDataTypeException
493
-     * @throws InvalidInterfaceException
494
-     */
495
-    protected function _post_notices()
496
-    {
497
-        // self::debug hardcoded to false
498
-        if (self::debug) {
499
-            echo self::$nl . self::$nl . __LINE__ . ') ' . __METHOD__ . '() ';
500
-        }
501
-        $refresh_msg = '';
502
-        $none_added_msg = '';
503
-        if (defined('DOING_AJAX') && DOING_AJAX) {
504
-            $refresh_msg = esc_html__(
505
-                'Please refresh the page to view updated ticket quantities.',
506
-                'event_espresso'
507
-            );
508
-            $none_added_msg = esc_html__('No tickets were added for the event.', 'event_espresso');
509
-        }
510
-        if (! empty($this->sold_out_tickets)) {
511
-            EE_Error::add_attention(
512
-                sprintf(
513
-                    apply_filters(
514
-                        'FHEE__EED_Ticket_Sales_Monitor___post_notices__sold_out_tickets_notice',
515
-                        esc_html__(
516
-                            'We\'re sorry...%1$sThe following items have sold out since you first viewed this page, and can no longer be registered for:%1$s%1$s%2$s%1$s%1$sPlease note that availability can change at any time due to cancellations, so please check back again later if registration for this event(s) is important to you.%1$s%1$s%3$s%1$s%4$s%1$s',
517
-                            'event_espresso'
518
-                        )
519
-                    ),
520
-                    '<br />',
521
-                    implode('<br />', $this->sold_out_tickets),
522
-                    $none_added_msg,
523
-                    $refresh_msg
524
-                )
525
-            );
526
-            // alter code flow in the Ticket Selector for better UX
527
-            add_filter('FHEE__EED_Ticket_Selector__process_ticket_selections__tckts_slctd', '__return_true');
528
-            add_filter('FHEE__EED_Ticket_Selector__process_ticket_selections__success', '__return_false');
529
-            $this->sold_out_tickets = array();
530
-            // and reset the cart
531
-            EED_Ticket_Sales_Monitor::session_cart_reset(EE_Registry::instance()->SSN);
532
-        }
533
-        if (! empty($this->decremented_tickets)) {
534
-            EE_Error::add_attention(
535
-                sprintf(
536
-                    apply_filters(
537
-                        'FHEE__EED_Ticket_Sales_Monitor___ticket_quantity_decremented__notice',
538
-                        esc_html__(
539
-                            'We\'re sorry...%1$sDue to sales that have occurred since you first viewed the last page, the following items have had their quantities adjusted to match the current available amount:%1$s%1$s%2$s%1$s%1$sPlease note that availability can change at any time due to cancellations, so please check back again later if registration for this event(s) is important to you.%1$s%1$s%3$s%1$s%4$s%1$s',
540
-                            'event_espresso'
541
-                        )
542
-                    ),
543
-                    '<br />',
544
-                    implode('<br />', $this->decremented_tickets),
545
-                    $none_added_msg,
546
-                    $refresh_msg
547
-                )
548
-            );
549
-            $this->decremented_tickets = array();
550
-        }
551
-    }
552
-
553
-
554
-
555
-    /********************************** RELEASE_ALL_RESERVED_TICKETS_FOR_TRANSACTION  **********************************/
556
-
557
-
558
-    /**
559
-     * releases reserved tickets for all registrations of an EE_Transaction
560
-     * by default, will NOT release tickets for finalized transactions
561
-     *
562
-     * @param    EE_Transaction $transaction
563
-     * @return int
564
-     * @throws EE_Error
565
-     * @throws InvalidSessionDataException
566
-     */
567
-    protected function _release_all_reserved_tickets_for_transaction(EE_Transaction $transaction)
568
-    {
569
-        // self::debug hardcoded to false
570
-        if (self::debug) {
571
-            echo self::$nl . self::$nl . __LINE__ . ') ' . __METHOD__ . '() ';
572
-            echo self::$nl . ' . transaction->ID: ' . $transaction->ID();
573
-            echo self::$nl . ' . TXN status_ID: ' . $transaction->status_ID();
574
-        }
575
-        // check if 'finalize_registration' step has been completed...
576
-        $finalized = $transaction->reg_step_completed('finalize_registration');
577
-        if (self::debug) {
578
-            // DEBUG LOG
579
-            EEH_Debug_Tools::log(
580
-                __CLASS__,
581
-                __FUNCTION__,
582
-                __LINE__,
583
-                array('finalized' => $finalized),
584
-                false,
585
-                'EE_Transaction: ' . $transaction->ID()
586
-            );
587
-        }
588
-        // how many tickets were released
589
-        $count = 0;
590
-        if (self::debug) {
591
-            echo self::$nl . ' . . . TXN finalized: ' . $finalized;
592
-        }
593
-        $release_tickets_with_TXN_status = array(
594
-            EEM_Transaction::failed_status_code,
595
-            EEM_Transaction::abandoned_status_code,
596
-            EEM_Transaction::incomplete_status_code,
597
-        );
598
-        $events = array();
599
-        // if the session is getting cleared BEFORE the TXN has been finalized or the transaction is not completed
600
-        if (! $finalized || in_array($transaction->status_ID(), $release_tickets_with_TXN_status, true)) {
601
-            // cancel any reserved tickets for registrations that were not approved
602
-            $registrations = $transaction->registrations();
603
-            if (self::debug) {
604
-                echo self::$nl . ' . . . # registrations: ' . count($registrations);
605
-                $reg = reset($registrations);
606
-                $ticket = $reg->ticket();
607
-                if ($ticket instanceof EE_Ticket) {
608
-                    $ticket->add_extra_meta(
609
-                        EE_Ticket::META_KEY_TICKET_RESERVATIONS,
610
-                        __LINE__ . ') Release All Tickets TXN:' . $transaction->ID()
611
-                    );
612
-                }
613
-            }
614
-            if (! empty($registrations)) {
615
-                foreach ($registrations as $registration) {
616
-                    if (
617
-                        $registration instanceof EE_Registration
618
-                        && $this->_release_reserved_ticket_for_registration($registration, $transaction)
619
-                    ) {
620
-                        $count++;
621
-                        $events[ $registration->event_ID() ] = $registration->event();
622
-                    }
623
-                }
624
-            }
625
-        }
626
-        if ($events !== array()) {
627
-            foreach ($events as $event) {
628
-                /** @var EE_Event $event */
629
-                $event->perform_sold_out_status_check();
630
-            }
631
-        }
632
-        return $count;
633
-    }
634
-
635
-
636
-    /**
637
-     * releases reserved tickets for an EE_Registration
638
-     * by default, will NOT release tickets for APPROVED registrations
639
-     *
640
-     * @param EE_Registration $registration
641
-     * @param EE_Transaction  $transaction
642
-     * @return int
643
-     * @throws EE_Error
644
-     */
645
-    protected function _release_reserved_ticket_for_registration(
646
-        EE_Registration $registration,
647
-        EE_Transaction $transaction
648
-    ) {
649
-        $STS_ID = $transaction->status_ID();
650
-        // self::debug hardcoded to false
651
-        if (self::debug) {
652
-            echo self::$nl . self::$nl . __LINE__ . ') ' . __METHOD__ . '() ';
653
-            echo self::$nl . ' . . registration->ID: ' . $registration->ID();
654
-            echo self::$nl . ' . . registration->status_ID: ' . $registration->status_ID();
655
-            echo self::$nl . ' . . transaction->status_ID(): ' . $STS_ID;
656
-        }
657
-        if (
22
+	const debug = false;
23
+
24
+	private static $nl = '';
25
+
26
+	/**
27
+	 * an array of raw ticket data from EED_Ticket_Selector
28
+	 *
29
+	 * @var array $ticket_selections
30
+	 */
31
+	protected $ticket_selections = array();
32
+
33
+	/**
34
+	 * the raw ticket data from EED_Ticket_Selector is organized in rows
35
+	 * according to how they are displayed in the actual Ticket_Selector
36
+	 * this tracks the current row being processed
37
+	 *
38
+	 * @var int $current_row
39
+	 */
40
+	protected $current_row = 0;
41
+
42
+	/**
43
+	 * an array for tracking names of tickets that have sold out
44
+	 *
45
+	 * @var array $sold_out_tickets
46
+	 */
47
+	protected $sold_out_tickets = array();
48
+
49
+	/**
50
+	 * an array for tracking names of tickets that have had their quantities reduced
51
+	 *
52
+	 * @var array $decremented_tickets
53
+	 */
54
+	protected $decremented_tickets = array();
55
+
56
+
57
+	/**
58
+	 * set_hooks - for hooking into EE Core, other modules, etc
59
+	 *
60
+	 * @return    void
61
+	 */
62
+	public static function set_hooks()
63
+	{
64
+		self::$nl = defined('EE_TESTS_DIR') ? "\n" : '<br />';
65
+		// release tickets for expired carts
66
+		add_action(
67
+			'EED_Ticket_Selector__process_ticket_selections__before',
68
+			array('EED_Ticket_Sales_Monitor', 'release_tickets_for_expired_carts'),
69
+			1
70
+		);
71
+		// check ticket reserves AFTER MER does it's check (hence priority 20)
72
+		add_filter(
73
+			'FHEE__EE_Ticket_Selector___add_ticket_to_cart__ticket_qty',
74
+			array('EED_Ticket_Sales_Monitor', 'validate_ticket_sale'),
75
+			20,
76
+			3
77
+		);
78
+		// add notices for sold out tickets
79
+		add_action(
80
+			'AHEE__EE_Ticket_Selector__process_ticket_selections__after_tickets_added_to_cart',
81
+			array('EED_Ticket_Sales_Monitor', 'post_notices'),
82
+			10
83
+		);
84
+
85
+		// handle tickets deleted from cart
86
+		add_action(
87
+			'FHEE__EED_Multi_Event_Registration__delete_ticket__ticket_removed_from_cart',
88
+			array('EED_Ticket_Sales_Monitor', 'ticket_removed_from_cart'),
89
+			10,
90
+			2
91
+		);
92
+		// handle emptied carts
93
+		add_action(
94
+			'AHEE__EE_Session__reset_cart__before_reset',
95
+			array('EED_Ticket_Sales_Monitor', 'session_cart_reset'),
96
+			10,
97
+			1
98
+		);
99
+		add_action(
100
+			'AHEE__EED_Multi_Event_Registration__empty_event_cart__before_delete_cart',
101
+			array('EED_Ticket_Sales_Monitor', 'session_cart_reset'),
102
+			10,
103
+			1
104
+		);
105
+		// handle cancelled registrations
106
+		add_action(
107
+			'AHEE__EE_Session__reset_checkout__before_reset',
108
+			array('EED_Ticket_Sales_Monitor', 'session_checkout_reset'),
109
+			10,
110
+			1
111
+		);
112
+		// cron tasks
113
+		add_action(
114
+			'AHEE__EE_Cron_Tasks__process_expired_transactions__abandoned_transaction',
115
+			array('EED_Ticket_Sales_Monitor', 'process_abandoned_transactions'),
116
+			10,
117
+			1
118
+		);
119
+		add_action(
120
+			'AHEE__EE_Cron_Tasks__process_expired_transactions__incomplete_transaction',
121
+			array('EED_Ticket_Sales_Monitor', 'process_abandoned_transactions'),
122
+			10,
123
+			1
124
+		);
125
+		add_action(
126
+			'AHEE__EE_Cron_Tasks__process_expired_transactions__failed_transaction',
127
+			array('EED_Ticket_Sales_Monitor', 'process_failed_transactions'),
128
+			10,
129
+			1
130
+		);
131
+	}
132
+
133
+
134
+	/**
135
+	 * set_hooks_admin - for hooking into EE Admin Core, other modules, etc
136
+	 *
137
+	 * @return void
138
+	 */
139
+	public static function set_hooks_admin()
140
+	{
141
+		EED_Ticket_Sales_Monitor::set_hooks();
142
+	}
143
+
144
+
145
+	/**
146
+	 * @return EED_Ticket_Sales_Monitor|EED_Module
147
+	 */
148
+	public static function instance()
149
+	{
150
+		return parent::get_instance(__CLASS__);
151
+	}
152
+
153
+
154
+	/**
155
+	 * @param WP_Query $WP_Query
156
+	 * @return    void
157
+	 */
158
+	public function run($WP_Query)
159
+	{
160
+	}
161
+
162
+
163
+
164
+	/********************************** PRE_TICKET_SALES  **********************************/
165
+
166
+
167
+	/**
168
+	 * Retrieves grand totals from the line items that have no TXN ID
169
+	 * and timestamps less than the current time minus the session lifespan.
170
+	 * These are carts that have been abandoned before the "registrant" even attempted to checkout.
171
+	 * We're going to release the tickets for these line items before attempting to add more to the cart.
172
+	 *
173
+	 * @return void
174
+	 * @throws DomainException
175
+	 * @throws EE_Error
176
+	 * @throws InvalidArgumentException
177
+	 * @throws InvalidDataTypeException
178
+	 * @throws InvalidInterfaceException
179
+	 * @throws UnexpectedEntityException
180
+	 */
181
+	public static function release_tickets_for_expired_carts()
182
+	{
183
+		// self::debug hardcoded to false
184
+		if (self::debug) {
185
+			echo self::$nl . self::$nl . __LINE__ . ') ' . __METHOD__ . '()';
186
+		}
187
+		do_action('AHEE__EED_Ticket_Sales_Monitor__release_tickets_for_expired_carts__begin');
188
+		$expired_ticket_IDs = array();
189
+		/** @var EventEspresso\core\domain\values\session\SessionLifespan $session_lifespan */
190
+		$session_lifespan = LoaderFactory::getLoader()->getShared(
191
+			'EventEspresso\core\domain\values\session\SessionLifespan'
192
+		);
193
+		$timestamp = $session_lifespan->expiration();
194
+		$expired_ticket_line_items = EEM_Line_Item::instance()->getTicketLineItemsForExpiredCarts($timestamp);
195
+		if (self::debug) {
196
+			echo self::$nl . ' . time(): ' . time();
197
+			echo self::$nl . ' . time() as date: ' . date('Y-m-d H:i a');
198
+			echo self::$nl . ' . session expiration: ' . $session_lifespan->expiration();
199
+			echo self::$nl . ' . session expiration as date: ' . date('Y-m-d H:i a', $session_lifespan->expiration());
200
+			echo self::$nl . ' . timestamp: ' . $timestamp;
201
+			echo self::$nl . ' . $expired_ticket_line_items: ' . count($expired_ticket_line_items);
202
+		}
203
+		if (! empty($expired_ticket_line_items)) {
204
+			foreach ($expired_ticket_line_items as $expired_ticket_line_item) {
205
+				if (! $expired_ticket_line_item instanceof EE_Line_Item) {
206
+					continue;
207
+				}
208
+				$expired_ticket_IDs[ $expired_ticket_line_item->OBJ_ID() ] = $expired_ticket_line_item->OBJ_ID();
209
+				if (self::debug) {
210
+					echo self::$nl . ' . $expired_ticket_line_item->OBJ_ID(): ' . $expired_ticket_line_item->OBJ_ID();
211
+					echo self::$nl . ' . $expired_ticket_line_item->timestamp(): '
212
+						 . date(
213
+							 'Y-m-d h:i a',
214
+							 $expired_ticket_line_item->timestamp(true)
215
+						 );
216
+				}
217
+			}
218
+			if (! empty($expired_ticket_IDs)) {
219
+				EED_Ticket_Sales_Monitor::release_reservations_for_tickets(
220
+					\EEM_Ticket::instance()->get_tickets_with_IDs($expired_ticket_IDs),
221
+					array(),
222
+					__FUNCTION__
223
+				);
224
+				// now  let's get rid of expired line items so that they can't interfere with tracking
225
+				EED_Ticket_Sales_Monitor::clear_expired_line_items_with_no_transaction($timestamp);
226
+			}
227
+		}
228
+		do_action(
229
+			'AHEE__EED_Ticket_Sales_Monitor__release_tickets_for_expired_carts__end',
230
+			$expired_ticket_IDs,
231
+			$expired_ticket_line_items
232
+		);
233
+	}
234
+
235
+
236
+
237
+	/********************************** VALIDATE_TICKET_SALE  **********************************/
238
+
239
+
240
+	/**
241
+	 * callback for 'FHEE__EED_Ticket_Selector__process_ticket_selections__valid_post_data'
242
+	 *
243
+	 * @param int       $qty
244
+	 * @param EE_Ticket $ticket
245
+	 * @return bool
246
+	 * @throws UnexpectedEntityException
247
+	 * @throws EE_Error
248
+	 */
249
+	public static function validate_ticket_sale($qty, EE_Ticket $ticket)
250
+	{
251
+		$qty = absint($qty);
252
+		if ($qty > 0) {
253
+			$qty = EED_Ticket_Sales_Monitor::instance()->_validate_ticket_sale($ticket, $qty);
254
+		}
255
+		// self::debug hardcoded to false
256
+		if (self::debug) {
257
+			echo self::$nl . self::$nl . __LINE__ . ') ' . __METHOD__ . '()';
258
+			echo self::$nl . self::$nl . '<b> RETURNED QTY: ' . $qty . '</b>';
259
+		}
260
+		return $qty;
261
+	}
262
+
263
+
264
+	/**
265
+	 * checks whether an individual ticket is available for purchase based on datetime, and ticket details
266
+	 *
267
+	 * @param   EE_Ticket $ticket
268
+	 * @param int         $qty
269
+	 * @return int
270
+	 * @throws UnexpectedEntityException
271
+	 * @throws EE_Error
272
+	 */
273
+	protected function _validate_ticket_sale(EE_Ticket $ticket, $qty = 1)
274
+	{
275
+		// self::debug hardcoded to false
276
+		if (self::debug) {
277
+			echo self::$nl . self::$nl . __LINE__ . ') ' . __METHOD__ . '() ';
278
+		}
279
+		if (! $ticket instanceof EE_Ticket) {
280
+			return 0;
281
+		}
282
+		if (self::debug) {
283
+			echo self::$nl . '<b> . ticket->ID: ' . $ticket->ID() . '</b>';
284
+			echo self::$nl . ' . original ticket->reserved: ' . $ticket->reserved();
285
+		}
286
+		$ticket->refresh_from_db();
287
+		// first let's determine the ticket availability based on sales
288
+		$available = $ticket->qty('saleable');
289
+		if (self::debug) {
290
+			echo self::$nl . ' . . . ticket->qty: ' . $ticket->qty();
291
+			echo self::$nl . ' . . . ticket->sold: ' . $ticket->sold();
292
+			echo self::$nl . ' . . . ticket->reserved: ' . $ticket->reserved();
293
+			echo self::$nl . ' . . . ticket->qty(saleable): ' . $ticket->qty('saleable');
294
+			echo self::$nl . ' . . . available: ' . $available;
295
+		}
296
+		if ($available < 1) {
297
+			$this->_ticket_sold_out($ticket);
298
+			return 0;
299
+		}
300
+		if (self::debug) {
301
+			echo self::$nl . ' . . . qty: ' . $qty;
302
+		}
303
+		if ($available < $qty) {
304
+			$qty = $available;
305
+			if (self::debug) {
306
+				echo self::$nl . ' . . . QTY ADJUSTED: ' . $qty;
307
+			}
308
+			$this->_ticket_quantity_decremented($ticket);
309
+		}
310
+		if ($this->_reserve_ticket($ticket, $qty)) {
311
+			return $qty;
312
+		} else {
313
+			return 0;
314
+		}
315
+	}
316
+
317
+
318
+	/**
319
+	 * increments ticket reserved based on quantity passed
320
+	 *
321
+	 * @param    EE_Ticket $ticket
322
+	 * @param int          $quantity
323
+	 * @return bool indicating success or failure
324
+	 * @throws EE_Error
325
+	 */
326
+	protected function _reserve_ticket(EE_Ticket $ticket, $quantity = 1)
327
+	{
328
+		// self::debug hardcoded to false
329
+		if (self::debug) {
330
+			echo self::$nl . self::$nl . ' . . . INCREASE RESERVED: ' . $quantity;
331
+		}
332
+		return $ticket->increaseReserved($quantity, 'TicketSalesMonitor:' . __LINE__);
333
+	}
334
+
335
+
336
+	/**
337
+	 * @param  EE_Ticket $ticket
338
+	 * @param  int       $quantity
339
+	 * @return bool
340
+	 * @throws EE_Error
341
+	 */
342
+	protected function _release_reserved_ticket(EE_Ticket $ticket, $quantity = 1)
343
+	{
344
+		// self::debug hardcoded to false
345
+		if (self::debug) {
346
+			echo self::$nl . ' . . . ticket->ID: ' . $ticket->ID();
347
+			echo self::$nl . ' . . . ticket->reserved before: ' . $ticket->reserved();
348
+		}
349
+		$ticket->decreaseReserved($quantity, true, 'TicketSalesMonitor:' . __LINE__);
350
+		if (self::debug) {
351
+			echo self::$nl . ' . . . ticket->reserved after: ' . $ticket->reserved();
352
+		}
353
+		return $ticket->save() ? 1 : 0;
354
+	}
355
+
356
+
357
+	/**
358
+	 * removes quantities within the ticket selector based on zero ticket availability
359
+	 *
360
+	 * @param    EE_Ticket $ticket
361
+	 * @return    void
362
+	 * @throws UnexpectedEntityException
363
+	 * @throws EE_Error
364
+	 */
365
+	protected function _ticket_sold_out(EE_Ticket $ticket)
366
+	{
367
+		// self::debug hardcoded to false
368
+		if (self::debug) {
369
+			echo self::$nl . self::$nl . __LINE__ . ') ' . __METHOD__ . '() ';
370
+			echo self::$nl . ' . . ticket->name: ' . $this->_get_ticket_and_event_name($ticket);
371
+		}
372
+		$this->sold_out_tickets[] = $this->_get_ticket_and_event_name($ticket);
373
+	}
374
+
375
+
376
+	/**
377
+	 * adjusts quantities within the ticket selector based on decreased ticket availability
378
+	 *
379
+	 * @param    EE_Ticket $ticket
380
+	 * @return void
381
+	 * @throws UnexpectedEntityException
382
+	 * @throws EE_Error
383
+	 */
384
+	protected function _ticket_quantity_decremented(EE_Ticket $ticket)
385
+	{
386
+		// self::debug hardcoded to false
387
+		if (self::debug) {
388
+			echo self::$nl . self::$nl . __LINE__ . ') ' . __METHOD__ . '() ';
389
+			echo self::$nl . ' . . ticket->name: ' . $this->_get_ticket_and_event_name($ticket);
390
+		}
391
+		$this->decremented_tickets[] = $this->_get_ticket_and_event_name($ticket);
392
+	}
393
+
394
+
395
+	/**
396
+	 * builds string out of ticket and event name
397
+	 *
398
+	 * @param    EE_Ticket $ticket
399
+	 * @return string
400
+	 * @throws UnexpectedEntityException
401
+	 * @throws EE_Error
402
+	 */
403
+	protected function _get_ticket_and_event_name(EE_Ticket $ticket)
404
+	{
405
+		$event = $ticket->get_related_event();
406
+		if ($event instanceof EE_Event) {
407
+			$ticket_name = sprintf(
408
+				_x('%1$s for %2$s', 'ticket name for event name', 'event_espresso'),
409
+				$ticket->name(),
410
+				$event->name()
411
+			);
412
+		} else {
413
+			$ticket_name = $ticket->name();
414
+		}
415
+		return $ticket_name;
416
+	}
417
+
418
+
419
+
420
+	/********************************** EVENT CART  **********************************/
421
+
422
+
423
+	/**
424
+	 * releases or reserves ticket(s) based on quantity passed
425
+	 *
426
+	 * @param  EE_Line_Item $line_item
427
+	 * @param  int          $quantity
428
+	 * @return void
429
+	 * @throws EE_Error
430
+	 * @throws InvalidArgumentException
431
+	 * @throws InvalidDataTypeException
432
+	 * @throws InvalidInterfaceException
433
+	 */
434
+	public static function ticket_quantity_updated(EE_Line_Item $line_item, $quantity = 1)
435
+	{
436
+		$ticket = EEM_Ticket::instance()->get_one_by_ID(absint($line_item->OBJ_ID()));
437
+		if ($ticket instanceof EE_Ticket) {
438
+			$ticket->add_extra_meta(
439
+				EE_Ticket::META_KEY_TICKET_RESERVATIONS,
440
+				__LINE__ . ') ' . __METHOD__ . '()'
441
+			);
442
+			if ($quantity > 0) {
443
+				EED_Ticket_Sales_Monitor::instance()->_reserve_ticket($ticket, $quantity);
444
+			} else {
445
+				EED_Ticket_Sales_Monitor::instance()->_release_reserved_ticket($ticket, $quantity);
446
+			}
447
+		}
448
+	}
449
+
450
+
451
+	/**
452
+	 * releases reserved ticket(s) based on quantity passed
453
+	 *
454
+	 * @param  EE_Ticket $ticket
455
+	 * @param  int       $quantity
456
+	 * @return void
457
+	 * @throws EE_Error
458
+	 */
459
+	public static function ticket_removed_from_cart(EE_Ticket $ticket, $quantity = 1)
460
+	{
461
+		$ticket->add_extra_meta(
462
+			EE_Ticket::META_KEY_TICKET_RESERVATIONS,
463
+			__LINE__ . ') ' . __METHOD__ . '()'
464
+		);
465
+		EED_Ticket_Sales_Monitor::instance()->_release_reserved_ticket($ticket, $quantity);
466
+	}
467
+
468
+
469
+
470
+	/********************************** POST_NOTICES  **********************************/
471
+
472
+
473
+	/**
474
+	 * @return void
475
+	 * @throws EE_Error
476
+	 * @throws InvalidArgumentException
477
+	 * @throws ReflectionException
478
+	 * @throws InvalidDataTypeException
479
+	 * @throws InvalidInterfaceException
480
+	 */
481
+	public static function post_notices()
482
+	{
483
+		EED_Ticket_Sales_Monitor::instance()->_post_notices();
484
+	}
485
+
486
+
487
+	/**
488
+	 * @return void
489
+	 * @throws EE_Error
490
+	 * @throws InvalidArgumentException
491
+	 * @throws ReflectionException
492
+	 * @throws InvalidDataTypeException
493
+	 * @throws InvalidInterfaceException
494
+	 */
495
+	protected function _post_notices()
496
+	{
497
+		// self::debug hardcoded to false
498
+		if (self::debug) {
499
+			echo self::$nl . self::$nl . __LINE__ . ') ' . __METHOD__ . '() ';
500
+		}
501
+		$refresh_msg = '';
502
+		$none_added_msg = '';
503
+		if (defined('DOING_AJAX') && DOING_AJAX) {
504
+			$refresh_msg = esc_html__(
505
+				'Please refresh the page to view updated ticket quantities.',
506
+				'event_espresso'
507
+			);
508
+			$none_added_msg = esc_html__('No tickets were added for the event.', 'event_espresso');
509
+		}
510
+		if (! empty($this->sold_out_tickets)) {
511
+			EE_Error::add_attention(
512
+				sprintf(
513
+					apply_filters(
514
+						'FHEE__EED_Ticket_Sales_Monitor___post_notices__sold_out_tickets_notice',
515
+						esc_html__(
516
+							'We\'re sorry...%1$sThe following items have sold out since you first viewed this page, and can no longer be registered for:%1$s%1$s%2$s%1$s%1$sPlease note that availability can change at any time due to cancellations, so please check back again later if registration for this event(s) is important to you.%1$s%1$s%3$s%1$s%4$s%1$s',
517
+							'event_espresso'
518
+						)
519
+					),
520
+					'<br />',
521
+					implode('<br />', $this->sold_out_tickets),
522
+					$none_added_msg,
523
+					$refresh_msg
524
+				)
525
+			);
526
+			// alter code flow in the Ticket Selector for better UX
527
+			add_filter('FHEE__EED_Ticket_Selector__process_ticket_selections__tckts_slctd', '__return_true');
528
+			add_filter('FHEE__EED_Ticket_Selector__process_ticket_selections__success', '__return_false');
529
+			$this->sold_out_tickets = array();
530
+			// and reset the cart
531
+			EED_Ticket_Sales_Monitor::session_cart_reset(EE_Registry::instance()->SSN);
532
+		}
533
+		if (! empty($this->decremented_tickets)) {
534
+			EE_Error::add_attention(
535
+				sprintf(
536
+					apply_filters(
537
+						'FHEE__EED_Ticket_Sales_Monitor___ticket_quantity_decremented__notice',
538
+						esc_html__(
539
+							'We\'re sorry...%1$sDue to sales that have occurred since you first viewed the last page, the following items have had their quantities adjusted to match the current available amount:%1$s%1$s%2$s%1$s%1$sPlease note that availability can change at any time due to cancellations, so please check back again later if registration for this event(s) is important to you.%1$s%1$s%3$s%1$s%4$s%1$s',
540
+							'event_espresso'
541
+						)
542
+					),
543
+					'<br />',
544
+					implode('<br />', $this->decremented_tickets),
545
+					$none_added_msg,
546
+					$refresh_msg
547
+				)
548
+			);
549
+			$this->decremented_tickets = array();
550
+		}
551
+	}
552
+
553
+
554
+
555
+	/********************************** RELEASE_ALL_RESERVED_TICKETS_FOR_TRANSACTION  **********************************/
556
+
557
+
558
+	/**
559
+	 * releases reserved tickets for all registrations of an EE_Transaction
560
+	 * by default, will NOT release tickets for finalized transactions
561
+	 *
562
+	 * @param    EE_Transaction $transaction
563
+	 * @return int
564
+	 * @throws EE_Error
565
+	 * @throws InvalidSessionDataException
566
+	 */
567
+	protected function _release_all_reserved_tickets_for_transaction(EE_Transaction $transaction)
568
+	{
569
+		// self::debug hardcoded to false
570
+		if (self::debug) {
571
+			echo self::$nl . self::$nl . __LINE__ . ') ' . __METHOD__ . '() ';
572
+			echo self::$nl . ' . transaction->ID: ' . $transaction->ID();
573
+			echo self::$nl . ' . TXN status_ID: ' . $transaction->status_ID();
574
+		}
575
+		// check if 'finalize_registration' step has been completed...
576
+		$finalized = $transaction->reg_step_completed('finalize_registration');
577
+		if (self::debug) {
578
+			// DEBUG LOG
579
+			EEH_Debug_Tools::log(
580
+				__CLASS__,
581
+				__FUNCTION__,
582
+				__LINE__,
583
+				array('finalized' => $finalized),
584
+				false,
585
+				'EE_Transaction: ' . $transaction->ID()
586
+			);
587
+		}
588
+		// how many tickets were released
589
+		$count = 0;
590
+		if (self::debug) {
591
+			echo self::$nl . ' . . . TXN finalized: ' . $finalized;
592
+		}
593
+		$release_tickets_with_TXN_status = array(
594
+			EEM_Transaction::failed_status_code,
595
+			EEM_Transaction::abandoned_status_code,
596
+			EEM_Transaction::incomplete_status_code,
597
+		);
598
+		$events = array();
599
+		// if the session is getting cleared BEFORE the TXN has been finalized or the transaction is not completed
600
+		if (! $finalized || in_array($transaction->status_ID(), $release_tickets_with_TXN_status, true)) {
601
+			// cancel any reserved tickets for registrations that were not approved
602
+			$registrations = $transaction->registrations();
603
+			if (self::debug) {
604
+				echo self::$nl . ' . . . # registrations: ' . count($registrations);
605
+				$reg = reset($registrations);
606
+				$ticket = $reg->ticket();
607
+				if ($ticket instanceof EE_Ticket) {
608
+					$ticket->add_extra_meta(
609
+						EE_Ticket::META_KEY_TICKET_RESERVATIONS,
610
+						__LINE__ . ') Release All Tickets TXN:' . $transaction->ID()
611
+					);
612
+				}
613
+			}
614
+			if (! empty($registrations)) {
615
+				foreach ($registrations as $registration) {
616
+					if (
617
+						$registration instanceof EE_Registration
618
+						&& $this->_release_reserved_ticket_for_registration($registration, $transaction)
619
+					) {
620
+						$count++;
621
+						$events[ $registration->event_ID() ] = $registration->event();
622
+					}
623
+				}
624
+			}
625
+		}
626
+		if ($events !== array()) {
627
+			foreach ($events as $event) {
628
+				/** @var EE_Event $event */
629
+				$event->perform_sold_out_status_check();
630
+			}
631
+		}
632
+		return $count;
633
+	}
634
+
635
+
636
+	/**
637
+	 * releases reserved tickets for an EE_Registration
638
+	 * by default, will NOT release tickets for APPROVED registrations
639
+	 *
640
+	 * @param EE_Registration $registration
641
+	 * @param EE_Transaction  $transaction
642
+	 * @return int
643
+	 * @throws EE_Error
644
+	 */
645
+	protected function _release_reserved_ticket_for_registration(
646
+		EE_Registration $registration,
647
+		EE_Transaction $transaction
648
+	) {
649
+		$STS_ID = $transaction->status_ID();
650
+		// self::debug hardcoded to false
651
+		if (self::debug) {
652
+			echo self::$nl . self::$nl . __LINE__ . ') ' . __METHOD__ . '() ';
653
+			echo self::$nl . ' . . registration->ID: ' . $registration->ID();
654
+			echo self::$nl . ' . . registration->status_ID: ' . $registration->status_ID();
655
+			echo self::$nl . ' . . transaction->status_ID(): ' . $STS_ID;
656
+		}
657
+		if (
658 658
 // release Tickets for Failed Transactions and Abandoned Transactions
659
-            $STS_ID === EEM_Transaction::failed_status_code
660
-            || $STS_ID === EEM_Transaction::abandoned_status_code
661
-            || (
662
-                // also release Tickets for Incomplete Transactions, but ONLY if the Registrations are NOT Approved
663
-                $STS_ID === EEM_Transaction::incomplete_status_code
664
-                && $registration->status_ID() !== EEM_Registration::status_id_approved
665
-            )
666
-        ) {
667
-            if (self::debug) {
668
-                echo self::$nl . self::$nl . ' . . RELEASE RESERVED TICKET';
669
-                $rsrvd = $registration->get_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, true);
670
-                echo self::$nl . ' . . . registration HAS_RESERVED_TICKET_KEY: ';
671
-                var_dump($rsrvd);
672
-            }
673
-            $registration->release_reserved_ticket(true, 'TicketSalesMonitor:' . __LINE__);
674
-            return 1;
675
-        }
676
-        return 0;
677
-    }
678
-
679
-
680
-
681
-    /********************************** SESSION_CART_RESET  **********************************/
682
-
683
-
684
-    /**
685
-     * callback hooked into 'AHEE__EE_Session__reset_cart__before_reset'
686
-     *
687
-     * @param EE_Session $session
688
-     * @return void
689
-     * @throws EE_Error
690
-     * @throws InvalidArgumentException
691
-     * @throws ReflectionException
692
-     * @throws InvalidDataTypeException
693
-     * @throws InvalidInterfaceException
694
-     */
695
-    public static function session_cart_reset(EE_Session $session)
696
-    {
697
-        // don't release tickets if checkout was already reset
698
-        if (did_action('AHEE__EE_Session__reset_checkout__before_reset')) {
699
-            return;
700
-        }
701
-        // self::debug hardcoded to false
702
-        if (self::debug) {
703
-            echo self::$nl . self::$nl . __LINE__ . ') ' . __METHOD__ . '() ';
704
-        }
705
-        // first check of the session has a valid Checkout object
706
-        $checkout = $session->checkout();
707
-        if ($checkout instanceof EE_Checkout) {
708
-            // and use that to clear ticket reservations because it will update the associated registration meta data
709
-            EED_Ticket_Sales_Monitor::instance()->_session_checkout_reset($checkout);
710
-            return;
711
-        }
712
-        $cart = $session->cart();
713
-        if ($cart instanceof EE_Cart) {
714
-            if (self::debug) {
715
-                echo self::$nl . self::$nl . ' cart instance of EE_Cart: ';
716
-            }
717
-            EED_Ticket_Sales_Monitor::instance()->_session_cart_reset($cart, $session);
718
-        } else {
719
-            if (self::debug) {
720
-                echo self::$nl . self::$nl . ' invalid EE_Cart: ';
721
-                var_export($cart, true);
722
-            }
723
-        }
724
-    }
725
-
726
-
727
-    /**
728
-     * releases reserved tickets in the EE_Cart
729
-     *
730
-     * @param EE_Cart $cart
731
-     * @return void
732
-     * @throws EE_Error
733
-     * @throws InvalidArgumentException
734
-     * @throws ReflectionException
735
-     * @throws InvalidDataTypeException
736
-     * @throws InvalidInterfaceException
737
-     */
738
-    protected function _session_cart_reset(EE_Cart $cart, EE_Session $session)
739
-    {
740
-        // self::debug hardcoded to false
741
-        if (self::debug) {
742
-            echo self::$nl . self::$nl . __LINE__ . ') ' . __METHOD__ . '() ';
743
-        }
744
-        $ticket_line_items = $cart->get_tickets();
745
-        if (empty($ticket_line_items)) {
746
-            return;
747
-        }
748
-        if (self::debug) {
749
-            echo '<br /> . ticket_line_item count: ' . count($ticket_line_items);
750
-        }
751
-        foreach ($ticket_line_items as $ticket_line_item) {
752
-            if (self::debug) {
753
-                echo self::$nl . ' . ticket_line_item->ID(): ' . $ticket_line_item->ID();
754
-            }
755
-            if ($ticket_line_item instanceof EE_Line_Item && $ticket_line_item->OBJ_type() === 'Ticket') {
756
-                if (self::debug) {
757
-                    echo self::$nl . ' . . ticket_line_item->OBJ_ID(): ' . $ticket_line_item->OBJ_ID();
758
-                }
759
-                $ticket = EEM_Ticket::instance()->get_one_by_ID($ticket_line_item->OBJ_ID());
760
-                if ($ticket instanceof EE_Ticket) {
761
-                    if (self::debug) {
762
-                        echo self::$nl . ' . . ticket->ID(): ' . $ticket->ID();
763
-                        echo self::$nl . ' . . ticket_line_item->quantity(): ' . $ticket_line_item->quantity();
764
-                    }
765
-                    $ticket->add_extra_meta(
766
-                        EE_Ticket::META_KEY_TICKET_RESERVATIONS,
767
-                        __LINE__ . ') ' . __METHOD__ . '() SID = ' . $session->id()
768
-                    );
769
-                    $this->_release_reserved_ticket($ticket, $ticket_line_item->quantity());
770
-                }
771
-            }
772
-        }
773
-        if (self::debug) {
774
-            echo self::$nl . self::$nl . ' RESET COMPLETED ';
775
-        }
776
-    }
777
-
778
-
779
-
780
-    /********************************** SESSION_CHECKOUT_RESET  **********************************/
781
-
782
-
783
-    /**
784
-     * callback hooked into 'AHEE__EE_Session__reset_checkout__before_reset'
785
-     *
786
-     * @param EE_Session $session
787
-     * @return void
788
-     * @throws EE_Error
789
-     * @throws InvalidSessionDataException
790
-     */
791
-    public static function session_checkout_reset(EE_Session $session)
792
-    {
793
-        // don't release tickets if cart was already reset
794
-        if (did_action('AHEE__EE_Session__reset_cart__before_reset')) {
795
-            return;
796
-        }
797
-        $checkout = $session->checkout();
798
-        if ($checkout instanceof EE_Checkout) {
799
-            EED_Ticket_Sales_Monitor::instance()->_session_checkout_reset($checkout);
800
-        }
801
-    }
802
-
803
-
804
-    /**
805
-     * releases reserved tickets for the EE_Checkout->transaction
806
-     *
807
-     * @param EE_Checkout $checkout
808
-     * @return void
809
-     * @throws EE_Error
810
-     * @throws InvalidSessionDataException
811
-     */
812
-    protected function _session_checkout_reset(EE_Checkout $checkout)
813
-    {
814
-        // self::debug hardcoded to false
815
-        if (self::debug) {
816
-            echo self::$nl . self::$nl . __LINE__ . ') ' . __METHOD__ . '() ';
817
-        }
818
-        // we want to release the each registration's reserved tickets if the session was cleared, but not if this is a revisit
819
-        if ($checkout->revisit || ! $checkout->transaction instanceof EE_Transaction) {
820
-            return;
821
-        }
822
-        $this->_release_all_reserved_tickets_for_transaction($checkout->transaction);
823
-    }
824
-
825
-
826
-
827
-    /********************************** SESSION_EXPIRED_RESET  **********************************/
828
-
829
-
830
-    /**
831
-     * @param    EE_Session $session
832
-     * @return    void
833
-     */
834
-    public static function session_expired_reset(EE_Session $session)
835
-    {
836
-    }
837
-
838
-
839
-
840
-    /********************************** PROCESS_ABANDONED_TRANSACTIONS  **********************************/
841
-
842
-
843
-    /**
844
-     * releases reserved tickets for all registrations of an ABANDONED EE_Transaction
845
-     * by default, will NOT release tickets for free transactions, or any that have received a payment
846
-     *
847
-     * @param EE_Transaction $transaction
848
-     * @return void
849
-     * @throws EE_Error
850
-     * @throws InvalidSessionDataException
851
-     */
852
-    public static function process_abandoned_transactions(EE_Transaction $transaction)
853
-    {
854
-        // is this TXN free or has any money been paid towards this TXN? If so, then leave it alone
855
-        if ($transaction->is_free() || $transaction->paid() > 0) {
856
-            // self::debug hardcoded to false
857
-            if (self::debug) {
858
-                // DEBUG LOG
859
-                EEH_Debug_Tools::log(
860
-                    __CLASS__,
861
-                    __FUNCTION__,
862
-                    __LINE__,
863
-                    array($transaction),
864
-                    false,
865
-                    'EE_Transaction: ' . $transaction->ID()
866
-                );
867
-            }
868
-            return;
869
-        }
870
-        // have their been any successful payments made ?
871
-        $payments = $transaction->payments();
872
-        foreach ($payments as $payment) {
873
-            if ($payment instanceof EE_Payment && $payment->status() === EEM_Payment::status_id_approved) {
874
-                if (self::debug) {
875
-                    // DEBUG LOG
876
-                    EEH_Debug_Tools::log(
877
-                        __CLASS__,
878
-                        __FUNCTION__,
879
-                        __LINE__,
880
-                        array($payment),
881
-                        false,
882
-                        'EE_Transaction: ' . $transaction->ID()
883
-                    );
884
-                }
885
-                return;
886
-            }
887
-        }
888
-        // since you haven't even attempted to pay for your ticket...
889
-        EED_Ticket_Sales_Monitor::instance()->_release_all_reserved_tickets_for_transaction($transaction);
890
-    }
891
-
892
-
893
-
894
-    /********************************** PROCESS_FAILED_TRANSACTIONS  **********************************/
895
-
896
-
897
-    /**
898
-     * releases reserved tickets for absolutely ALL registrations of a FAILED EE_Transaction
899
-     *
900
-     * @param EE_Transaction $transaction
901
-     * @return void
902
-     * @throws EE_Error
903
-     * @throws InvalidSessionDataException
904
-     */
905
-    public static function process_failed_transactions(EE_Transaction $transaction)
906
-    {
907
-        // since you haven't even attempted to pay for your ticket...
908
-        EED_Ticket_Sales_Monitor::instance()->_release_all_reserved_tickets_for_transaction($transaction);
909
-    }
910
-
911
-
912
-
913
-    /********************************** RESET RESERVATION COUNTS  *********************************/
914
-
915
-
916
-    /**
917
-     * Resets the ticket and datetime reserved counts.
918
-     *
919
-     * For all the tickets with reservations, recalculates what their actual reserved counts should be based
920
-     * on the valid transactions.
921
-     *
922
-     * @return int number of tickets whose reservations were released.
923
-     * @throws EE_Error
924
-     * @throws DomainException
925
-     * @throws InvalidDataTypeException
926
-     * @throws InvalidInterfaceException
927
-     * @throws InvalidArgumentException
928
-     * @throws UnexpectedEntityException
929
-     * @throws ReflectionException
930
-     */
931
-    public static function reset_reservation_counts()
932
-    {
933
-        /** @var EE_Line_Item[] $valid_reserved_tickets */
934
-        $valid_reserved_tickets = array();
935
-        /** @var EE_Transaction[] $transactions_in_progress */
936
-        $transactions_in_progress = EEM_Transaction::instance()->get_transactions_in_progress();
937
-        foreach ($transactions_in_progress as $transaction) {
938
-            // if this TXN has been fully completed, then skip it
939
-            if ($transaction->reg_step_completed('finalize_registration')) {
940
-                continue;
941
-            }
942
-            $total_line_item = $transaction->total_line_item();
943
-            // $transaction_in_progress->line
944
-            if (! $total_line_item instanceof EE_Line_Item) {
945
-                throw new DomainException(
946
-                    esc_html__(
947
-                        'Transaction does not have a valid Total Line Item associated with it.',
948
-                        'event_espresso'
949
-                    )
950
-                );
951
-            }
952
-            $valid_reserved_tickets += EED_Ticket_Sales_Monitor::get_ticket_line_items_for_grand_total(
953
-                $total_line_item
954
-            );
955
-        }
956
-        $total_line_items = EEM_Line_Item::instance()->get_total_line_items_for_active_carts();
957
-        foreach ($total_line_items as $total_line_item) {
958
-            $valid_reserved_tickets += EED_Ticket_Sales_Monitor::get_ticket_line_items_for_grand_total(
959
-                $total_line_item
960
-            );
961
-        }
962
-        $tickets_with_reservations = EEM_Ticket::instance()->get_tickets_with_reservations();
963
-        return EED_Ticket_Sales_Monitor::release_reservations_for_tickets(
964
-            $tickets_with_reservations,
965
-            $valid_reserved_tickets,
966
-            __FUNCTION__
967
-        );
968
-    }
969
-
970
-
971
-    /**
972
-     * @param EE_Line_Item $total_line_item
973
-     * @return EE_Line_Item[]
974
-     */
975
-    private static function get_ticket_line_items_for_grand_total(EE_Line_Item $total_line_item)
976
-    {
977
-        /** @var EE_Line_Item[] $valid_reserved_tickets */
978
-        $valid_reserved_tickets = array();
979
-        $ticket_line_items = EEH_Line_Item::get_ticket_line_items($total_line_item);
980
-        foreach ($ticket_line_items as $ticket_line_item) {
981
-            if ($ticket_line_item instanceof EE_Line_Item) {
982
-                $valid_reserved_tickets[ $ticket_line_item->ID() ] = $ticket_line_item;
983
-            }
984
-        }
985
-        return $valid_reserved_tickets;
986
-    }
987
-
988
-
989
-    /**
990
-     * Releases ticket and datetime reservations (ie, reduces the number of reserved spots on them).
991
-     *
992
-     * Given the list of tickets which have reserved spots on them, uses the complete list of line items for tickets
993
-     * whose transactions aren't complete and also aren't yet expired (ie, they're incomplete and younger than the
994
-     * session's expiry time) to update the ticket (and their datetimes') reserved counts.
995
-     *
996
-     * @param EE_Ticket[]    $tickets_with_reservations all tickets with TKT_reserved > 0
997
-     * @param EE_Line_Item[] $valid_reserved_ticket_line_items all line items for tickets and incomplete transactions
998
-     *                       whose session has NOT expired. We will use these to determine the number of ticket
999
-     *                       reservations are now invalid. We don't use the list of invalid ticket line items because
1000
-     *                       we don't know which of those have already been taken into account when reducing ticket
1001
-     *                       reservation counts, and which haven't.
1002
-     * @return int
1003
-     * @throws UnexpectedEntityException
1004
-     * @throws DomainException
1005
-     * @throws EE_Error
1006
-     */
1007
-    protected static function release_reservations_for_tickets(
1008
-        array $tickets_with_reservations,
1009
-        array $valid_reserved_ticket_line_items = array(),
1010
-        $source = ''
1011
-    ) {
1012
-        $total_tickets_released = 0;
1013
-        $sold_out_events = array();
1014
-        foreach ($tickets_with_reservations as $ticket_with_reservations) {
1015
-            if (! $ticket_with_reservations instanceof EE_Ticket) {
1016
-                continue;
1017
-            }
1018
-            // The $valid_reserved_ticket_line_items tells us what the reserved count on their tickets (and datetimes)
1019
-            // SHOULD be. Instead of just directly updating the list, we're going to use EE_Ticket::decreaseReserved()
1020
-            // to try to avoid race conditions, so instead of just finding the number to update TO, we're going to find
1021
-            // the number to RELEASE. It's the same end result, just different path.
1022
-            // Begin by assuming we're going to release all the reservations on this ticket.
1023
-            $expired_reservations_count = $ticket_with_reservations->reserved();
1024
-            // Now reduce that number using the list of current valid reservations.
1025
-            foreach ($valid_reserved_ticket_line_items as $valid_reserved_ticket_line_item) {
1026
-                if (
1027
-                    $valid_reserved_ticket_line_item instanceof EE_Line_Item
1028
-                    && $valid_reserved_ticket_line_item->OBJ_ID() === $ticket_with_reservations->ID()
1029
-                ) {
1030
-                    $expired_reservations_count -= $valid_reserved_ticket_line_item->quantity();
1031
-                }
1032
-            }
1033
-            // Only bother saving the tickets and datetimes if we're actually going to release some spots.
1034
-            if ($expired_reservations_count > 0) {
1035
-                $ticket_with_reservations->add_extra_meta(
1036
-                    EE_Ticket::META_KEY_TICKET_RESERVATIONS,
1037
-                    __LINE__ . ') ' . $source . '()'
1038
-                );
1039
-                $ticket_with_reservations->decreaseReserved($expired_reservations_count, true, 'TicketSalesMonitor:' . __LINE__);
1040
-                $total_tickets_released += $expired_reservations_count;
1041
-                $event = $ticket_with_reservations->get_related_event();
1042
-                // track sold out events
1043
-                if ($event instanceof EE_Event && $event->is_sold_out()) {
1044
-                    $sold_out_events[] = $event;
1045
-                }
1046
-            }
1047
-        }
1048
-        // Double check whether sold out events should remain sold out after releasing tickets
1049
-        if ($sold_out_events !== array()) {
1050
-            foreach ($sold_out_events as $sold_out_event) {
1051
-                /** @var EE_Event $sold_out_event */
1052
-                $sold_out_event->perform_sold_out_status_check();
1053
-            }
1054
-        }
1055
-        return $total_tickets_released;
1056
-    }
1057
-
1058
-
1059
-
1060
-    /********************************** SHUTDOWN  **********************************/
1061
-
1062
-
1063
-    /**
1064
-     * @param int $timestamp
1065
-     * @return false|int
1066
-     * @throws EE_Error
1067
-     * @throws InvalidArgumentException
1068
-     * @throws InvalidDataTypeException
1069
-     * @throws InvalidInterfaceException
1070
-     */
1071
-    public static function clear_expired_line_items_with_no_transaction($timestamp = 0)
1072
-    {
1073
-        /** @type WPDB $wpdb */
1074
-        global $wpdb;
1075
-        if (! absint($timestamp)) {
1076
-            /** @var EventEspresso\core\domain\values\session\SessionLifespan $session_lifespan */
1077
-            $session_lifespan = LoaderFactory::getLoader()->getShared(
1078
-                'EventEspresso\core\domain\values\session\SessionLifespan'
1079
-            );
1080
-            $timestamp = $session_lifespan->expiration();
1081
-        }
1082
-        return $wpdb->query(
1083
-            $wpdb->prepare(
1084
-                'DELETE FROM ' . EEM_Line_Item::instance()->table() . '
659
+			$STS_ID === EEM_Transaction::failed_status_code
660
+			|| $STS_ID === EEM_Transaction::abandoned_status_code
661
+			|| (
662
+				// also release Tickets for Incomplete Transactions, but ONLY if the Registrations are NOT Approved
663
+				$STS_ID === EEM_Transaction::incomplete_status_code
664
+				&& $registration->status_ID() !== EEM_Registration::status_id_approved
665
+			)
666
+		) {
667
+			if (self::debug) {
668
+				echo self::$nl . self::$nl . ' . . RELEASE RESERVED TICKET';
669
+				$rsrvd = $registration->get_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, true);
670
+				echo self::$nl . ' . . . registration HAS_RESERVED_TICKET_KEY: ';
671
+				var_dump($rsrvd);
672
+			}
673
+			$registration->release_reserved_ticket(true, 'TicketSalesMonitor:' . __LINE__);
674
+			return 1;
675
+		}
676
+		return 0;
677
+	}
678
+
679
+
680
+
681
+	/********************************** SESSION_CART_RESET  **********************************/
682
+
683
+
684
+	/**
685
+	 * callback hooked into 'AHEE__EE_Session__reset_cart__before_reset'
686
+	 *
687
+	 * @param EE_Session $session
688
+	 * @return void
689
+	 * @throws EE_Error
690
+	 * @throws InvalidArgumentException
691
+	 * @throws ReflectionException
692
+	 * @throws InvalidDataTypeException
693
+	 * @throws InvalidInterfaceException
694
+	 */
695
+	public static function session_cart_reset(EE_Session $session)
696
+	{
697
+		// don't release tickets if checkout was already reset
698
+		if (did_action('AHEE__EE_Session__reset_checkout__before_reset')) {
699
+			return;
700
+		}
701
+		// self::debug hardcoded to false
702
+		if (self::debug) {
703
+			echo self::$nl . self::$nl . __LINE__ . ') ' . __METHOD__ . '() ';
704
+		}
705
+		// first check of the session has a valid Checkout object
706
+		$checkout = $session->checkout();
707
+		if ($checkout instanceof EE_Checkout) {
708
+			// and use that to clear ticket reservations because it will update the associated registration meta data
709
+			EED_Ticket_Sales_Monitor::instance()->_session_checkout_reset($checkout);
710
+			return;
711
+		}
712
+		$cart = $session->cart();
713
+		if ($cart instanceof EE_Cart) {
714
+			if (self::debug) {
715
+				echo self::$nl . self::$nl . ' cart instance of EE_Cart: ';
716
+			}
717
+			EED_Ticket_Sales_Monitor::instance()->_session_cart_reset($cart, $session);
718
+		} else {
719
+			if (self::debug) {
720
+				echo self::$nl . self::$nl . ' invalid EE_Cart: ';
721
+				var_export($cart, true);
722
+			}
723
+		}
724
+	}
725
+
726
+
727
+	/**
728
+	 * releases reserved tickets in the EE_Cart
729
+	 *
730
+	 * @param EE_Cart $cart
731
+	 * @return void
732
+	 * @throws EE_Error
733
+	 * @throws InvalidArgumentException
734
+	 * @throws ReflectionException
735
+	 * @throws InvalidDataTypeException
736
+	 * @throws InvalidInterfaceException
737
+	 */
738
+	protected function _session_cart_reset(EE_Cart $cart, EE_Session $session)
739
+	{
740
+		// self::debug hardcoded to false
741
+		if (self::debug) {
742
+			echo self::$nl . self::$nl . __LINE__ . ') ' . __METHOD__ . '() ';
743
+		}
744
+		$ticket_line_items = $cart->get_tickets();
745
+		if (empty($ticket_line_items)) {
746
+			return;
747
+		}
748
+		if (self::debug) {
749
+			echo '<br /> . ticket_line_item count: ' . count($ticket_line_items);
750
+		}
751
+		foreach ($ticket_line_items as $ticket_line_item) {
752
+			if (self::debug) {
753
+				echo self::$nl . ' . ticket_line_item->ID(): ' . $ticket_line_item->ID();
754
+			}
755
+			if ($ticket_line_item instanceof EE_Line_Item && $ticket_line_item->OBJ_type() === 'Ticket') {
756
+				if (self::debug) {
757
+					echo self::$nl . ' . . ticket_line_item->OBJ_ID(): ' . $ticket_line_item->OBJ_ID();
758
+				}
759
+				$ticket = EEM_Ticket::instance()->get_one_by_ID($ticket_line_item->OBJ_ID());
760
+				if ($ticket instanceof EE_Ticket) {
761
+					if (self::debug) {
762
+						echo self::$nl . ' . . ticket->ID(): ' . $ticket->ID();
763
+						echo self::$nl . ' . . ticket_line_item->quantity(): ' . $ticket_line_item->quantity();
764
+					}
765
+					$ticket->add_extra_meta(
766
+						EE_Ticket::META_KEY_TICKET_RESERVATIONS,
767
+						__LINE__ . ') ' . __METHOD__ . '() SID = ' . $session->id()
768
+					);
769
+					$this->_release_reserved_ticket($ticket, $ticket_line_item->quantity());
770
+				}
771
+			}
772
+		}
773
+		if (self::debug) {
774
+			echo self::$nl . self::$nl . ' RESET COMPLETED ';
775
+		}
776
+	}
777
+
778
+
779
+
780
+	/********************************** SESSION_CHECKOUT_RESET  **********************************/
781
+
782
+
783
+	/**
784
+	 * callback hooked into 'AHEE__EE_Session__reset_checkout__before_reset'
785
+	 *
786
+	 * @param EE_Session $session
787
+	 * @return void
788
+	 * @throws EE_Error
789
+	 * @throws InvalidSessionDataException
790
+	 */
791
+	public static function session_checkout_reset(EE_Session $session)
792
+	{
793
+		// don't release tickets if cart was already reset
794
+		if (did_action('AHEE__EE_Session__reset_cart__before_reset')) {
795
+			return;
796
+		}
797
+		$checkout = $session->checkout();
798
+		if ($checkout instanceof EE_Checkout) {
799
+			EED_Ticket_Sales_Monitor::instance()->_session_checkout_reset($checkout);
800
+		}
801
+	}
802
+
803
+
804
+	/**
805
+	 * releases reserved tickets for the EE_Checkout->transaction
806
+	 *
807
+	 * @param EE_Checkout $checkout
808
+	 * @return void
809
+	 * @throws EE_Error
810
+	 * @throws InvalidSessionDataException
811
+	 */
812
+	protected function _session_checkout_reset(EE_Checkout $checkout)
813
+	{
814
+		// self::debug hardcoded to false
815
+		if (self::debug) {
816
+			echo self::$nl . self::$nl . __LINE__ . ') ' . __METHOD__ . '() ';
817
+		}
818
+		// we want to release the each registration's reserved tickets if the session was cleared, but not if this is a revisit
819
+		if ($checkout->revisit || ! $checkout->transaction instanceof EE_Transaction) {
820
+			return;
821
+		}
822
+		$this->_release_all_reserved_tickets_for_transaction($checkout->transaction);
823
+	}
824
+
825
+
826
+
827
+	/********************************** SESSION_EXPIRED_RESET  **********************************/
828
+
829
+
830
+	/**
831
+	 * @param    EE_Session $session
832
+	 * @return    void
833
+	 */
834
+	public static function session_expired_reset(EE_Session $session)
835
+	{
836
+	}
837
+
838
+
839
+
840
+	/********************************** PROCESS_ABANDONED_TRANSACTIONS  **********************************/
841
+
842
+
843
+	/**
844
+	 * releases reserved tickets for all registrations of an ABANDONED EE_Transaction
845
+	 * by default, will NOT release tickets for free transactions, or any that have received a payment
846
+	 *
847
+	 * @param EE_Transaction $transaction
848
+	 * @return void
849
+	 * @throws EE_Error
850
+	 * @throws InvalidSessionDataException
851
+	 */
852
+	public static function process_abandoned_transactions(EE_Transaction $transaction)
853
+	{
854
+		// is this TXN free or has any money been paid towards this TXN? If so, then leave it alone
855
+		if ($transaction->is_free() || $transaction->paid() > 0) {
856
+			// self::debug hardcoded to false
857
+			if (self::debug) {
858
+				// DEBUG LOG
859
+				EEH_Debug_Tools::log(
860
+					__CLASS__,
861
+					__FUNCTION__,
862
+					__LINE__,
863
+					array($transaction),
864
+					false,
865
+					'EE_Transaction: ' . $transaction->ID()
866
+				);
867
+			}
868
+			return;
869
+		}
870
+		// have their been any successful payments made ?
871
+		$payments = $transaction->payments();
872
+		foreach ($payments as $payment) {
873
+			if ($payment instanceof EE_Payment && $payment->status() === EEM_Payment::status_id_approved) {
874
+				if (self::debug) {
875
+					// DEBUG LOG
876
+					EEH_Debug_Tools::log(
877
+						__CLASS__,
878
+						__FUNCTION__,
879
+						__LINE__,
880
+						array($payment),
881
+						false,
882
+						'EE_Transaction: ' . $transaction->ID()
883
+					);
884
+				}
885
+				return;
886
+			}
887
+		}
888
+		// since you haven't even attempted to pay for your ticket...
889
+		EED_Ticket_Sales_Monitor::instance()->_release_all_reserved_tickets_for_transaction($transaction);
890
+	}
891
+
892
+
893
+
894
+	/********************************** PROCESS_FAILED_TRANSACTIONS  **********************************/
895
+
896
+
897
+	/**
898
+	 * releases reserved tickets for absolutely ALL registrations of a FAILED EE_Transaction
899
+	 *
900
+	 * @param EE_Transaction $transaction
901
+	 * @return void
902
+	 * @throws EE_Error
903
+	 * @throws InvalidSessionDataException
904
+	 */
905
+	public static function process_failed_transactions(EE_Transaction $transaction)
906
+	{
907
+		// since you haven't even attempted to pay for your ticket...
908
+		EED_Ticket_Sales_Monitor::instance()->_release_all_reserved_tickets_for_transaction($transaction);
909
+	}
910
+
911
+
912
+
913
+	/********************************** RESET RESERVATION COUNTS  *********************************/
914
+
915
+
916
+	/**
917
+	 * Resets the ticket and datetime reserved counts.
918
+	 *
919
+	 * For all the tickets with reservations, recalculates what their actual reserved counts should be based
920
+	 * on the valid transactions.
921
+	 *
922
+	 * @return int number of tickets whose reservations were released.
923
+	 * @throws EE_Error
924
+	 * @throws DomainException
925
+	 * @throws InvalidDataTypeException
926
+	 * @throws InvalidInterfaceException
927
+	 * @throws InvalidArgumentException
928
+	 * @throws UnexpectedEntityException
929
+	 * @throws ReflectionException
930
+	 */
931
+	public static function reset_reservation_counts()
932
+	{
933
+		/** @var EE_Line_Item[] $valid_reserved_tickets */
934
+		$valid_reserved_tickets = array();
935
+		/** @var EE_Transaction[] $transactions_in_progress */
936
+		$transactions_in_progress = EEM_Transaction::instance()->get_transactions_in_progress();
937
+		foreach ($transactions_in_progress as $transaction) {
938
+			// if this TXN has been fully completed, then skip it
939
+			if ($transaction->reg_step_completed('finalize_registration')) {
940
+				continue;
941
+			}
942
+			$total_line_item = $transaction->total_line_item();
943
+			// $transaction_in_progress->line
944
+			if (! $total_line_item instanceof EE_Line_Item) {
945
+				throw new DomainException(
946
+					esc_html__(
947
+						'Transaction does not have a valid Total Line Item associated with it.',
948
+						'event_espresso'
949
+					)
950
+				);
951
+			}
952
+			$valid_reserved_tickets += EED_Ticket_Sales_Monitor::get_ticket_line_items_for_grand_total(
953
+				$total_line_item
954
+			);
955
+		}
956
+		$total_line_items = EEM_Line_Item::instance()->get_total_line_items_for_active_carts();
957
+		foreach ($total_line_items as $total_line_item) {
958
+			$valid_reserved_tickets += EED_Ticket_Sales_Monitor::get_ticket_line_items_for_grand_total(
959
+				$total_line_item
960
+			);
961
+		}
962
+		$tickets_with_reservations = EEM_Ticket::instance()->get_tickets_with_reservations();
963
+		return EED_Ticket_Sales_Monitor::release_reservations_for_tickets(
964
+			$tickets_with_reservations,
965
+			$valid_reserved_tickets,
966
+			__FUNCTION__
967
+		);
968
+	}
969
+
970
+
971
+	/**
972
+	 * @param EE_Line_Item $total_line_item
973
+	 * @return EE_Line_Item[]
974
+	 */
975
+	private static function get_ticket_line_items_for_grand_total(EE_Line_Item $total_line_item)
976
+	{
977
+		/** @var EE_Line_Item[] $valid_reserved_tickets */
978
+		$valid_reserved_tickets = array();
979
+		$ticket_line_items = EEH_Line_Item::get_ticket_line_items($total_line_item);
980
+		foreach ($ticket_line_items as $ticket_line_item) {
981
+			if ($ticket_line_item instanceof EE_Line_Item) {
982
+				$valid_reserved_tickets[ $ticket_line_item->ID() ] = $ticket_line_item;
983
+			}
984
+		}
985
+		return $valid_reserved_tickets;
986
+	}
987
+
988
+
989
+	/**
990
+	 * Releases ticket and datetime reservations (ie, reduces the number of reserved spots on them).
991
+	 *
992
+	 * Given the list of tickets which have reserved spots on them, uses the complete list of line items for tickets
993
+	 * whose transactions aren't complete and also aren't yet expired (ie, they're incomplete and younger than the
994
+	 * session's expiry time) to update the ticket (and their datetimes') reserved counts.
995
+	 *
996
+	 * @param EE_Ticket[]    $tickets_with_reservations all tickets with TKT_reserved > 0
997
+	 * @param EE_Line_Item[] $valid_reserved_ticket_line_items all line items for tickets and incomplete transactions
998
+	 *                       whose session has NOT expired. We will use these to determine the number of ticket
999
+	 *                       reservations are now invalid. We don't use the list of invalid ticket line items because
1000
+	 *                       we don't know which of those have already been taken into account when reducing ticket
1001
+	 *                       reservation counts, and which haven't.
1002
+	 * @return int
1003
+	 * @throws UnexpectedEntityException
1004
+	 * @throws DomainException
1005
+	 * @throws EE_Error
1006
+	 */
1007
+	protected static function release_reservations_for_tickets(
1008
+		array $tickets_with_reservations,
1009
+		array $valid_reserved_ticket_line_items = array(),
1010
+		$source = ''
1011
+	) {
1012
+		$total_tickets_released = 0;
1013
+		$sold_out_events = array();
1014
+		foreach ($tickets_with_reservations as $ticket_with_reservations) {
1015
+			if (! $ticket_with_reservations instanceof EE_Ticket) {
1016
+				continue;
1017
+			}
1018
+			// The $valid_reserved_ticket_line_items tells us what the reserved count on their tickets (and datetimes)
1019
+			// SHOULD be. Instead of just directly updating the list, we're going to use EE_Ticket::decreaseReserved()
1020
+			// to try to avoid race conditions, so instead of just finding the number to update TO, we're going to find
1021
+			// the number to RELEASE. It's the same end result, just different path.
1022
+			// Begin by assuming we're going to release all the reservations on this ticket.
1023
+			$expired_reservations_count = $ticket_with_reservations->reserved();
1024
+			// Now reduce that number using the list of current valid reservations.
1025
+			foreach ($valid_reserved_ticket_line_items as $valid_reserved_ticket_line_item) {
1026
+				if (
1027
+					$valid_reserved_ticket_line_item instanceof EE_Line_Item
1028
+					&& $valid_reserved_ticket_line_item->OBJ_ID() === $ticket_with_reservations->ID()
1029
+				) {
1030
+					$expired_reservations_count -= $valid_reserved_ticket_line_item->quantity();
1031
+				}
1032
+			}
1033
+			// Only bother saving the tickets and datetimes if we're actually going to release some spots.
1034
+			if ($expired_reservations_count > 0) {
1035
+				$ticket_with_reservations->add_extra_meta(
1036
+					EE_Ticket::META_KEY_TICKET_RESERVATIONS,
1037
+					__LINE__ . ') ' . $source . '()'
1038
+				);
1039
+				$ticket_with_reservations->decreaseReserved($expired_reservations_count, true, 'TicketSalesMonitor:' . __LINE__);
1040
+				$total_tickets_released += $expired_reservations_count;
1041
+				$event = $ticket_with_reservations->get_related_event();
1042
+				// track sold out events
1043
+				if ($event instanceof EE_Event && $event->is_sold_out()) {
1044
+					$sold_out_events[] = $event;
1045
+				}
1046
+			}
1047
+		}
1048
+		// Double check whether sold out events should remain sold out after releasing tickets
1049
+		if ($sold_out_events !== array()) {
1050
+			foreach ($sold_out_events as $sold_out_event) {
1051
+				/** @var EE_Event $sold_out_event */
1052
+				$sold_out_event->perform_sold_out_status_check();
1053
+			}
1054
+		}
1055
+		return $total_tickets_released;
1056
+	}
1057
+
1058
+
1059
+
1060
+	/********************************** SHUTDOWN  **********************************/
1061
+
1062
+
1063
+	/**
1064
+	 * @param int $timestamp
1065
+	 * @return false|int
1066
+	 * @throws EE_Error
1067
+	 * @throws InvalidArgumentException
1068
+	 * @throws InvalidDataTypeException
1069
+	 * @throws InvalidInterfaceException
1070
+	 */
1071
+	public static function clear_expired_line_items_with_no_transaction($timestamp = 0)
1072
+	{
1073
+		/** @type WPDB $wpdb */
1074
+		global $wpdb;
1075
+		if (! absint($timestamp)) {
1076
+			/** @var EventEspresso\core\domain\values\session\SessionLifespan $session_lifespan */
1077
+			$session_lifespan = LoaderFactory::getLoader()->getShared(
1078
+				'EventEspresso\core\domain\values\session\SessionLifespan'
1079
+			);
1080
+			$timestamp = $session_lifespan->expiration();
1081
+		}
1082
+		return $wpdb->query(
1083
+			$wpdb->prepare(
1084
+				'DELETE FROM ' . EEM_Line_Item::instance()->table() . '
1085 1085
                 WHERE TXN_ID = 0 AND LIN_timestamp <= %s',
1086
-                // use GMT time because that's what LIN_timestamps are in
1087
-                date('Y-m-d H:i:s', $timestamp)
1088
-            )
1089
-        );
1090
-    }
1086
+				// use GMT time because that's what LIN_timestamps are in
1087
+				date('Y-m-d H:i:s', $timestamp)
1088
+			)
1089
+		);
1090
+	}
1091 1091
 }
Please login to merge, or discard this patch.
thank_you_page/templates/thank-you-page-registration-details.template.php 2 patches
Spacing   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -21,7 +21,7 @@  discard block
 block discarded – undo
21 21
     $event_name    = '';
22 22
     $wait_list     = false;
23 23
     foreach ($registrations as $registration) {
24
-        if (! $registration instanceof EE_Registration) {
24
+        if ( ! $registration instanceof EE_Registration) {
25 25
             continue;
26 26
         }
27 27
         if ($event_name != $registration->event_name() && ! empty($event_name)) { ?>
@@ -55,7 +55,7 @@  discard block
 block discarded – undo
55 55
             <tbody>
56 56
             <?php
57 57
         }
58
-        if ($is_primary || (! $is_primary && $reg_url_link == $registration->reg_url_link())) { ?>
58
+        if ($is_primary || ( ! $is_primary && $reg_url_link == $registration->reg_url_link())) { ?>
59 59
             <tr>
60 60
                 <td width="40%">
61 61
                     <?php
Please login to merge, or discard this patch.
Indentation   +62 added lines, -62 removed lines patch added patch discarded remove patch
@@ -14,24 +14,24 @@  discard block
 block discarded – undo
14 14
 
15 15
 <div class="ee-registration-details-dv">
16 16
     <?php
17
-    $registrations = $transaction->registrations();
18
-    $registrations = is_array($registrations) ? $registrations : [];
19
-    $reg_count     = count($registrations);
20
-    $reg_cntr      = 0;
21
-    $event_name    = '';
22
-    $wait_list     = false;
23
-    foreach ($registrations as $registration) {
24
-        if (! $registration instanceof EE_Registration) {
25
-            continue;
26
-        }
27
-        if ($event_name != $registration->event_name() && ! empty($event_name)) { ?>
17
+	$registrations = $transaction->registrations();
18
+	$registrations = is_array($registrations) ? $registrations : [];
19
+	$reg_count     = count($registrations);
20
+	$reg_cntr      = 0;
21
+	$event_name    = '';
22
+	$wait_list     = false;
23
+	foreach ($registrations as $registration) {
24
+		if (! $registration instanceof EE_Registration) {
25
+			continue;
26
+		}
27
+		if ($event_name != $registration->event_name() && ! empty($event_name)) { ?>
28 28
             </tbody>
29 29
             </table>
30 30
             <?php
31
-        }
32
-        $reg_cntr++;
33
-        if ($event_name != $registration->event_name()) {
34
-            ?>
31
+		}
32
+		$reg_cntr++;
33
+		if ($event_name != $registration->event_name()) {
34
+			?>
35 35
             <h5>
36 36
                 <span class="smaller-text grey-text">
37 37
                     <?php esc_html_e('for', 'event_espresso'); ?> :
@@ -54,23 +54,23 @@  discard block
 block discarded – undo
54 54
             </thead>
55 55
             <tbody>
56 56
             <?php
57
-        }
58
-        if ($is_primary || (! $is_primary && $reg_url_link == $registration->reg_url_link())) { ?>
57
+		}
58
+		if ($is_primary || (! $is_primary && $reg_url_link == $registration->reg_url_link())) { ?>
59 59
             <tr>
60 60
                 <td width="40%">
61 61
                     <?php
62
-                    if ($registration->attendee() instanceof EE_Attendee) {
63
-                        echo esc_html($registration->attendee()->full_name(true));
64
-                    }
65
-                    ?>
62
+					if ($registration->attendee() instanceof EE_Attendee) {
63
+						echo esc_html($registration->attendee()->full_name(true));
64
+					}
65
+					?>
66 66
                     <p class="tiny-text" style="margin: .75em 0 0;">
67 67
                         <?php if ($registration->count_question_groups()) { ?>
68 68
                             <a class="ee-icon-only-lnk"
69 69
                                href="<?php echo esc_url_raw($registration->edit_attendee_information_url()); ?>"
70 70
                                title="<?php esc_attr_e(
71
-                                   'Click here to edit Attendee Information',
72
-                                   'event_espresso'
73
-                               ); ?>"
71
+								   'Click here to edit Attendee Information',
72
+								   'event_espresso'
73
+							   ); ?>"
74 74
                             >
75 75
                                 <span class="ee-icon ee-icon-user-edit"></span>
76 76
                                 <?php esc_html_e('edit info', 'event_espresso'); ?>
@@ -78,15 +78,15 @@  discard block
 block discarded – undo
78 78
                         <?php } ?>
79 79
                         <a class="ee-resend-reg-confirmation-email ee-icon-only-lnk"
80 80
                            href="<?php echo esc_url_raw(
81
-                               add_query_arg(
82
-                                   ['token' => $registration->reg_url_link(), 'resend_reg_confirmation' => 'true'],
83
-                                   EE_Registry::instance()->CFG->core->thank_you_page_url()
84
-                               )
85
-                           ); ?>"
81
+							   add_query_arg(
82
+								   ['token' => $registration->reg_url_link(), 'resend_reg_confirmation' => 'true'],
83
+								   EE_Registry::instance()->CFG->core->thank_you_page_url()
84
+							   )
85
+						   ); ?>"
86 86
                            title="<?php esc_attr_e(
87
-                               'Click here to resend the Registration Confirmation email',
88
-                               'event_espresso'
89
-                           ); ?>"
87
+							   'Click here to resend the Registration Confirmation email',
88
+							   'event_espresso'
89
+						   ); ?>"
90 90
                            rel="<?php echo esc_attr($registration->reg_url_link()); ?>"
91 91
                         >
92 92
                             <span class="dashicons dashicons-email-alt"></span>
@@ -100,27 +100,27 @@  discard block
 block discarded – undo
100 100
                 <td width="35%" class="jst-left">
101 101
                     <?php $registration->e_pretty_status(true) ?>
102 102
                     <?php
103
-                    if ($registration->status_ID() === EEM_Registration::status_id_wait_list) {
104
-                        $wait_list = true;
105
-                    }
106
-                    ?>
103
+					if ($registration->status_ID() === EEM_Registration::status_id_wait_list) {
104
+						$wait_list = true;
105
+					}
106
+					?>
107 107
                 </td>
108 108
             </tr>
109 109
             <?php do_action(
110
-                'AHEE__thank_you_page_registration_details_template__after_registration_table_row',
111
-                $registration
112
-            ); ?>
110
+				'AHEE__thank_you_page_registration_details_template__after_registration_table_row',
111
+				$registration
112
+			); ?>
113 113
             <?php
114
-            $event_name = $registration->event_name();
115
-        }
116
-        if ($reg_cntr >= $reg_count) {
117
-            ?>
114
+			$event_name = $registration->event_name();
115
+		}
116
+		if ($reg_cntr >= $reg_count) {
117
+			?>
118 118
             </tbody>
119 119
             </table>
120 120
             <?php
121
-        }
122
-    }
123
-    ?>
121
+		}
122
+	}
123
+	?>
124 124
     <?php if ($is_primary && $SPCO_attendee_information_url) { ?>
125 125
         <p class="small-text jst-rght">
126 126
             <a href='<?php echo esc_url_raw($SPCO_attendee_information_url) ?>'>
@@ -129,22 +129,22 @@  discard block
 block discarded – undo
129 129
         </p>
130 130
     <?php } ?>
131 131
     <?php
132
-    if ($wait_list) {
133
-        echo apply_filters(
134
-            'AFEE__thank_you_page_registration_details_template__wait_list_notice',
135
-            sprintf(
136
-                esc_html__(
137
-                    '%1$sre: Wait List Registrations%2$sPlease note that the total cost listed below in the Transaction Details is for ALL registrations, including those that are on the wait list, even though they can not be currently paid for. If any spaces become available however, you may be notified by the Event admin and have the opportunity to secure the remaining tickets by making a payment for them.%3$s',
138
-                    'event_espresso'
139
-                ),
140
-                '<h6 class="" style="margin-bottom:.25em;"><span class="dashicons dashicons-clipboard ee-icon-size-16 purple-text"></span>',
141
-                '</h6 ><p class="ee-wait-list-notice">',
142
-                '</p ><br />'
143
-            )
144
-        );
145
-    }
146
-    do_action('AHEE__thank_you_page_registration_details_template__after_registration_details');
147
-    ?>
132
+	if ($wait_list) {
133
+		echo apply_filters(
134
+			'AFEE__thank_you_page_registration_details_template__wait_list_notice',
135
+			sprintf(
136
+				esc_html__(
137
+					'%1$sre: Wait List Registrations%2$sPlease note that the total cost listed below in the Transaction Details is for ALL registrations, including those that are on the wait list, even though they can not be currently paid for. If any spaces become available however, you may be notified by the Event admin and have the opportunity to secure the remaining tickets by making a payment for them.%3$s',
138
+					'event_espresso'
139
+				),
140
+				'<h6 class="" style="margin-bottom:.25em;"><span class="dashicons dashicons-clipboard ee-icon-size-16 purple-text"></span>',
141
+				'</h6 ><p class="ee-wait-list-notice">',
142
+				'</p ><br />'
143
+			)
144
+		);
145
+	}
146
+	do_action('AHEE__thank_you_page_registration_details_template__after_registration_details');
147
+	?>
148 148
 
149 149
 </div>
150 150
 <!-- end of .registration-details -->
Please login to merge, or discard this patch.
thank_you_page/templates/thank-you-page-transaction-details.template.php 1 patch
Indentation   +6 added lines, -6 removed lines patch added patch discarded remove patch
@@ -28,8 +28,8 @@  discard block
 block discarded – undo
28 28
                 <label><?php esc_html_e('Amount Owing: ', 'event_espresso'); ?></label>
29 29
             </td>
30 30
             <td class="<?php echo ($transaction->paid() == $transaction->total())
31
-                ? 'ee-transaction-paid'
32
-                : 'ee-transaction-unpaid' ?>">
31
+				? 'ee-transaction-paid'
32
+				: 'ee-transaction-unpaid' ?>">
33 33
                 <?php echo EEH_Template::format_currency($transaction->remaining()); // already escaped ?>
34 34
             </td>
35 35
         </tr>
@@ -39,7 +39,7 @@  discard block
 block discarded – undo
39 39
             </td>
40 40
             <td>
41 41
                 <?php $transaction->e_pretty_status(true);
42
-                if ($show_try_pay_again_link && ! $transaction->is_completed()) { ?>
42
+				if ($show_try_pay_again_link && ! $transaction->is_completed()) { ?>
43 43
                     &nbsp; <span class="small-text">
44 44
                         <a href='<?php echo esc_url_raw($SPCO_payment_options_url) ?>'>
45 45
                             <?php esc_html_e('View Payment Options', 'event_espresso'); ?>
@@ -57,9 +57,9 @@  discard block
 block discarded – undo
57 57
             </td>
58 58
         </tr>
59 59
         <?php do_action(
60
-            'AHEE__thank_you_page_transaction_details_template__after_transaction_table_row',
61
-            $transaction
62
-        ); ?>
60
+			'AHEE__thank_you_page_transaction_details_template__after_transaction_table_row',
61
+			$transaction
62
+		); ?>
63 63
         </tbody>
64 64
     </table>
65 65
 
Please login to merge, or discard this patch.