@@ -1,9 +1,9 @@ discard block |
||
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 |
||
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 |
@@ -11,7 +11,7 @@ |
||
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 |
@@ -51,7 +51,7 @@ discard block |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 */ |
@@ -20,998 +20,998 @@ |
||
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 | } |
@@ -226,7 +226,7 @@ discard block |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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); |
@@ -14,758 +14,758 @@ |
||
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 | } |
@@ -100,13 +100,13 @@ discard block |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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); |
@@ -13,665 +13,665 @@ |
||
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 | } |
@@ -145,7 +145,7 @@ discard block |
||
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 |
||
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 |
||
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 |
||
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 |
||
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) { |
@@ -9,260 +9,260 @@ |
||
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 | } |
@@ -183,7 +183,7 @@ discard block |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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) |
@@ -19,1073 +19,1073 @@ |
||
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 | } |
@@ -21,7 +21,7 @@ discard block |
||
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 |
||
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 |
@@ -14,24 +14,24 @@ discard block |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 --> |
@@ -28,8 +28,8 @@ discard block |
||
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 |
||
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 | <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 |
||
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 |