@@ -37,138 +37,138 @@ |
||
37 | 37 | * @since 4.0 |
38 | 38 | */ |
39 | 39 | if (function_exists('espresso_version')) { |
40 | - if (! function_exists('espresso_duplicate_plugin_error')) { |
|
41 | - /** |
|
42 | - * espresso_duplicate_plugin_error |
|
43 | - * displays if more than one version of EE is activated at the same time. |
|
44 | - */ |
|
45 | - function espresso_duplicate_plugin_error() |
|
46 | - { |
|
47 | - ?> |
|
40 | + if (! function_exists('espresso_duplicate_plugin_error')) { |
|
41 | + /** |
|
42 | + * espresso_duplicate_plugin_error |
|
43 | + * displays if more than one version of EE is activated at the same time. |
|
44 | + */ |
|
45 | + function espresso_duplicate_plugin_error() |
|
46 | + { |
|
47 | + ?> |
|
48 | 48 | <div class="error"> |
49 | 49 | <p> |
50 | 50 | <?php |
51 | - echo esc_html__( |
|
52 | - 'Can not run multiple versions of Event Espresso! One version has been automatically deactivated. Please verify that you have the correct version you want still active.', |
|
53 | - 'event_espresso' |
|
54 | - ); ?> |
|
51 | + echo esc_html__( |
|
52 | + 'Can not run multiple versions of Event Espresso! One version has been automatically deactivated. Please verify that you have the correct version you want still active.', |
|
53 | + 'event_espresso' |
|
54 | + ); ?> |
|
55 | 55 | </p> |
56 | 56 | </div> |
57 | 57 | <?php |
58 | - espresso_deactivate_plugin(plugin_basename(__FILE__)); |
|
59 | - } |
|
60 | - } |
|
61 | - add_action('admin_notices', 'espresso_duplicate_plugin_error', 1); |
|
58 | + espresso_deactivate_plugin(plugin_basename(__FILE__)); |
|
59 | + } |
|
60 | + } |
|
61 | + add_action('admin_notices', 'espresso_duplicate_plugin_error', 1); |
|
62 | 62 | } else { |
63 | - define('EE_MIN_PHP_VER_REQUIRED', '7.4.0'); |
|
64 | - if (! version_compare(PHP_VERSION, EE_MIN_PHP_VER_REQUIRED, '>=')) { |
|
65 | - /** |
|
66 | - * espresso_minimum_php_version_error |
|
67 | - * |
|
68 | - * @return void |
|
69 | - */ |
|
70 | - function espresso_minimum_php_version_error() |
|
71 | - { |
|
72 | - ?> |
|
63 | + define('EE_MIN_PHP_VER_REQUIRED', '7.4.0'); |
|
64 | + if (! version_compare(PHP_VERSION, EE_MIN_PHP_VER_REQUIRED, '>=')) { |
|
65 | + /** |
|
66 | + * espresso_minimum_php_version_error |
|
67 | + * |
|
68 | + * @return void |
|
69 | + */ |
|
70 | + function espresso_minimum_php_version_error() |
|
71 | + { |
|
72 | + ?> |
|
73 | 73 | <div class="error"> |
74 | 74 | <p> |
75 | 75 | <?php |
76 | - printf( |
|
77 | - esc_html__( |
|
78 | - 'We\'re sorry, but Event Espresso requires PHP version %1$s or greater in order to operate. You are currently running version %2$s.%3$sIn order to update your version of PHP, you will need to contact your current hosting provider.%3$sFor information on stable PHP versions, please go to %4$s.', |
|
79 | - 'event_espresso' |
|
80 | - ), |
|
81 | - EE_MIN_PHP_VER_REQUIRED, |
|
82 | - PHP_VERSION, |
|
83 | - '<br/>', |
|
84 | - '<a href="https://www.php.net/downloads.php">https://php.net/downloads.php</a>' |
|
85 | - ); |
|
86 | - ?> |
|
76 | + printf( |
|
77 | + esc_html__( |
|
78 | + 'We\'re sorry, but Event Espresso requires PHP version %1$s or greater in order to operate. You are currently running version %2$s.%3$sIn order to update your version of PHP, you will need to contact your current hosting provider.%3$sFor information on stable PHP versions, please go to %4$s.', |
|
79 | + 'event_espresso' |
|
80 | + ), |
|
81 | + EE_MIN_PHP_VER_REQUIRED, |
|
82 | + PHP_VERSION, |
|
83 | + '<br/>', |
|
84 | + '<a href="https://www.php.net/downloads.php">https://php.net/downloads.php</a>' |
|
85 | + ); |
|
86 | + ?> |
|
87 | 87 | </p> |
88 | 88 | </div> |
89 | 89 | <?php |
90 | - espresso_deactivate_plugin(plugin_basename(__FILE__)); |
|
91 | - } |
|
90 | + espresso_deactivate_plugin(plugin_basename(__FILE__)); |
|
91 | + } |
|
92 | 92 | |
93 | - add_action('admin_notices', 'espresso_minimum_php_version_error', 1); |
|
94 | - } else { |
|
95 | - define('EVENT_ESPRESSO_MAIN_FILE', __FILE__); |
|
93 | + add_action('admin_notices', 'espresso_minimum_php_version_error', 1); |
|
94 | + } else { |
|
95 | + define('EVENT_ESPRESSO_MAIN_FILE', __FILE__); |
|
96 | 96 | |
97 | - require_once __DIR__ . '/vendor/autoload.php'; |
|
97 | + require_once __DIR__ . '/vendor/autoload.php'; |
|
98 | 98 | |
99 | - /** |
|
100 | - * espresso_version |
|
101 | - * Returns the plugin version |
|
102 | - * |
|
103 | - * @return string |
|
104 | - */ |
|
105 | - function espresso_version(): string |
|
106 | - { |
|
107 | - return apply_filters('FHEE__espresso__espresso_version', '5.0.47'); |
|
108 | - } |
|
99 | + /** |
|
100 | + * espresso_version |
|
101 | + * Returns the plugin version |
|
102 | + * |
|
103 | + * @return string |
|
104 | + */ |
|
105 | + function espresso_version(): string |
|
106 | + { |
|
107 | + return apply_filters('FHEE__espresso__espresso_version', '5.0.47'); |
|
108 | + } |
|
109 | 109 | |
110 | - /** |
|
111 | - * espresso_plugin_activation |
|
112 | - * adds a wp-option to indicate that EE has been activated via the WP admin plugins page |
|
113 | - */ |
|
114 | - function espresso_plugin_activation() |
|
115 | - { |
|
116 | - update_option('ee_espresso_activation', true); |
|
117 | - update_option('event-espresso-core_allow_tracking', 'no'); |
|
118 | - update_option('event-espresso-core_tracking_notice', 'hide'); |
|
119 | - // Run WP GraphQL activation callback |
|
120 | - espressoLoadWpGraphQL(); |
|
121 | - graphql_activation_callback(); |
|
122 | - } |
|
110 | + /** |
|
111 | + * espresso_plugin_activation |
|
112 | + * adds a wp-option to indicate that EE has been activated via the WP admin plugins page |
|
113 | + */ |
|
114 | + function espresso_plugin_activation() |
|
115 | + { |
|
116 | + update_option('ee_espresso_activation', true); |
|
117 | + update_option('event-espresso-core_allow_tracking', 'no'); |
|
118 | + update_option('event-espresso-core_tracking_notice', 'hide'); |
|
119 | + // Run WP GraphQL activation callback |
|
120 | + espressoLoadWpGraphQL(); |
|
121 | + graphql_activation_callback(); |
|
122 | + } |
|
123 | 123 | |
124 | - register_activation_hook(EVENT_ESPRESSO_MAIN_FILE, 'espresso_plugin_activation'); |
|
124 | + register_activation_hook(EVENT_ESPRESSO_MAIN_FILE, 'espresso_plugin_activation'); |
|
125 | 125 | |
126 | - /** |
|
127 | - * espresso_plugin_deactivation |
|
128 | - */ |
|
129 | - function espresso_plugin_deactivation() |
|
130 | - { |
|
131 | - // Run WP GraphQL deactivation callback |
|
132 | - espressoLoadWpGraphQL(); |
|
133 | - graphql_deactivation_callback(); |
|
134 | - delete_option('event-espresso-core_allow_tracking'); |
|
135 | - delete_option('event-espresso-core_tracking_notice'); |
|
136 | - } |
|
137 | - register_deactivation_hook(EVENT_ESPRESSO_MAIN_FILE, 'espresso_plugin_deactivation'); |
|
126 | + /** |
|
127 | + * espresso_plugin_deactivation |
|
128 | + */ |
|
129 | + function espresso_plugin_deactivation() |
|
130 | + { |
|
131 | + // Run WP GraphQL deactivation callback |
|
132 | + espressoLoadWpGraphQL(); |
|
133 | + graphql_deactivation_callback(); |
|
134 | + delete_option('event-espresso-core_allow_tracking'); |
|
135 | + delete_option('event-espresso-core_tracking_notice'); |
|
136 | + } |
|
137 | + register_deactivation_hook(EVENT_ESPRESSO_MAIN_FILE, 'espresso_plugin_deactivation'); |
|
138 | 138 | |
139 | - require_once __DIR__ . '/core/bootstrap_espresso.php'; |
|
140 | - bootstrap_espresso(); |
|
141 | - } |
|
139 | + require_once __DIR__ . '/core/bootstrap_espresso.php'; |
|
140 | + bootstrap_espresso(); |
|
141 | + } |
|
142 | 142 | } |
143 | 143 | |
144 | 144 | if (! function_exists('espresso_deactivate_plugin')) { |
145 | - /** |
|
146 | - * deactivate_plugin |
|
147 | - * usage: espresso_deactivate_plugin( plugin_basename( __FILE__ )); |
|
148 | - * |
|
149 | - * @access public |
|
150 | - * @param string $plugin_basename - the results of plugin_basename( __FILE__ ) for the plugin's main file |
|
151 | - * @return void |
|
152 | - */ |
|
153 | - function espresso_deactivate_plugin(string $plugin_basename = '') |
|
154 | - { |
|
155 | - if (! function_exists('deactivate_plugins')) { |
|
156 | - require_once ABSPATH . 'wp-admin/includes/plugin.php'; |
|
157 | - } |
|
158 | - unset($_GET['activate'], $_REQUEST['activate']); |
|
159 | - deactivate_plugins($plugin_basename); |
|
160 | - } |
|
145 | + /** |
|
146 | + * deactivate_plugin |
|
147 | + * usage: espresso_deactivate_plugin( plugin_basename( __FILE__ )); |
|
148 | + * |
|
149 | + * @access public |
|
150 | + * @param string $plugin_basename - the results of plugin_basename( __FILE__ ) for the plugin's main file |
|
151 | + * @return void |
|
152 | + */ |
|
153 | + function espresso_deactivate_plugin(string $plugin_basename = '') |
|
154 | + { |
|
155 | + if (! function_exists('deactivate_plugins')) { |
|
156 | + require_once ABSPATH . 'wp-admin/includes/plugin.php'; |
|
157 | + } |
|
158 | + unset($_GET['activate'], $_REQUEST['activate']); |
|
159 | + deactivate_plugins($plugin_basename); |
|
160 | + } |
|
161 | 161 | } |
162 | 162 | |
163 | 163 | |
164 | 164 | if (! function_exists('espressoLoadWpGraphQL')) { |
165 | - function espressoLoadWpGraphQL() |
|
166 | - { |
|
167 | - if ( |
|
168 | - ! class_exists('WPGraphQL') |
|
169 | - && is_readable(__DIR__ . '/vendor/wp-graphql/wp-graphql/wp-graphql.php') |
|
170 | - ) { |
|
171 | - require_once __DIR__ . '/vendor/wp-graphql/wp-graphql/wp-graphql.php'; |
|
172 | - } |
|
173 | - } |
|
165 | + function espressoLoadWpGraphQL() |
|
166 | + { |
|
167 | + if ( |
|
168 | + ! class_exists('WPGraphQL') |
|
169 | + && is_readable(__DIR__ . '/vendor/wp-graphql/wp-graphql/wp-graphql.php') |
|
170 | + ) { |
|
171 | + require_once __DIR__ . '/vendor/wp-graphql/wp-graphql/wp-graphql.php'; |
|
172 | + } |
|
173 | + } |
|
174 | 174 | } |
@@ -20,115 +20,115 @@ |
||
20 | 20 | */ |
21 | 21 | abstract class TicketSelector |
22 | 22 | { |
23 | - /** |
|
24 | - * @var EE_Event |
|
25 | - */ |
|
26 | - protected $event; |
|
27 | - |
|
28 | - /** |
|
29 | - * @var EE_Ticket[] |
|
30 | - */ |
|
31 | - protected $tickets; |
|
32 | - |
|
33 | - /** |
|
34 | - * @var int |
|
35 | - */ |
|
36 | - protected $max_attendees; |
|
37 | - |
|
38 | - /** |
|
39 | - * @var array |
|
40 | - */ |
|
41 | - protected $template_args; |
|
42 | - |
|
43 | - /** |
|
44 | - * @var int |
|
45 | - */ |
|
46 | - protected $ticket_rows = 0; |
|
47 | - |
|
48 | - |
|
49 | - /** |
|
50 | - * TicketSelectorSimple constructor. |
|
51 | - * |
|
52 | - * @param EE_Event $event |
|
53 | - * @param EE_Ticket[] $tickets |
|
54 | - * @param int $max_attendees |
|
55 | - * @param array $template_args |
|
56 | - */ |
|
57 | - public function __construct(EE_Event $event, array $tickets, $max_attendees, array $template_args) |
|
58 | - { |
|
59 | - $this->event = $event; |
|
60 | - $this->tickets = $tickets; |
|
61 | - $this->max_attendees = $max_attendees; |
|
62 | - $this->template_args = $template_args; |
|
63 | - $this->addTemplateArgs(); |
|
64 | - EE_Registry::$i18n_js_strings['required_checkbox_notice'] = esc_html__( |
|
65 | - 'This ticket is required and must be selected', |
|
66 | - 'event_espresso' |
|
67 | - ); |
|
68 | - } |
|
69 | - |
|
70 | - |
|
71 | - /** |
|
72 | - * sets any and all template args that are required for this Ticket Selector |
|
73 | - * |
|
74 | - * @return void |
|
75 | - */ |
|
76 | - abstract protected function addTemplateArgs(); |
|
77 | - |
|
78 | - |
|
79 | - /** |
|
80 | - * loadTicketSelectorTemplate |
|
81 | - * |
|
82 | - * @return string |
|
83 | - */ |
|
84 | - protected function loadTicketSelectorTemplate() |
|
85 | - { |
|
86 | - try { |
|
87 | - $this->template_args['hidden_inputs'] = $this->getHiddenInputs(); |
|
88 | - return EEH_Template::locate_template( |
|
89 | - apply_filters( |
|
90 | - 'FHEE__EE_Ticket_Selector__display_ticket_selector__template_path', |
|
91 | - $this->template_args['template_path'], |
|
92 | - $this->event |
|
93 | - ), |
|
94 | - $this->template_args |
|
95 | - ); |
|
96 | - } catch (Exception $e) { |
|
97 | - EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__); |
|
98 | - } |
|
99 | - return ''; |
|
100 | - } |
|
101 | - |
|
102 | - |
|
103 | - /** |
|
104 | - * The __toString method allows a class to decide how it will react when it is converted to a string. |
|
105 | - * |
|
106 | - * @return string |
|
107 | - * @link http://php.net/manual/en/language.oop5.magic.php#language.oop5.magic.tostring |
|
108 | - */ |
|
109 | - public function __toString() |
|
110 | - { |
|
111 | - return $this->loadTicketSelectorTemplate(); |
|
112 | - } |
|
113 | - |
|
114 | - |
|
115 | - /** |
|
116 | - * getHiddenInputs |
|
117 | - * |
|
118 | - * @return string |
|
119 | - * @throws EE_Error |
|
120 | - * @throws ReflectionException |
|
121 | - */ |
|
122 | - public function getHiddenInputs() |
|
123 | - { |
|
124 | - $html = '<input type="hidden" name="noheader" value="true"/>'; |
|
125 | - $html .= '<input type="hidden" name="tkt-slctr-return-url-' . $this->event->ID() . '"'; |
|
126 | - $html .= ' value="' . EEH_URL::current_url() . $this->template_args['anchor_id'] . '"/>'; |
|
127 | - $html .= '<input type="hidden" name="tkt-slctr-rows-' . $this->event->ID(); |
|
128 | - $html .= '" value="' . $this->ticket_rows . '"/>'; |
|
129 | - $html .= '<input type="hidden" name="tkt-slctr-max-atndz-' . $this->event->ID(); |
|
130 | - $html .= '" value="' . $this->template_args['max_atndz'] . '"/>'; |
|
131 | - $html .= '<input type="hidden" name="tkt-slctr-event-id" value="' . $this->event->ID() . '"/>'; |
|
132 | - return $html; |
|
133 | - } |
|
23 | + /** |
|
24 | + * @var EE_Event |
|
25 | + */ |
|
26 | + protected $event; |
|
27 | + |
|
28 | + /** |
|
29 | + * @var EE_Ticket[] |
|
30 | + */ |
|
31 | + protected $tickets; |
|
32 | + |
|
33 | + /** |
|
34 | + * @var int |
|
35 | + */ |
|
36 | + protected $max_attendees; |
|
37 | + |
|
38 | + /** |
|
39 | + * @var array |
|
40 | + */ |
|
41 | + protected $template_args; |
|
42 | + |
|
43 | + /** |
|
44 | + * @var int |
|
45 | + */ |
|
46 | + protected $ticket_rows = 0; |
|
47 | + |
|
48 | + |
|
49 | + /** |
|
50 | + * TicketSelectorSimple constructor. |
|
51 | + * |
|
52 | + * @param EE_Event $event |
|
53 | + * @param EE_Ticket[] $tickets |
|
54 | + * @param int $max_attendees |
|
55 | + * @param array $template_args |
|
56 | + */ |
|
57 | + public function __construct(EE_Event $event, array $tickets, $max_attendees, array $template_args) |
|
58 | + { |
|
59 | + $this->event = $event; |
|
60 | + $this->tickets = $tickets; |
|
61 | + $this->max_attendees = $max_attendees; |
|
62 | + $this->template_args = $template_args; |
|
63 | + $this->addTemplateArgs(); |
|
64 | + EE_Registry::$i18n_js_strings['required_checkbox_notice'] = esc_html__( |
|
65 | + 'This ticket is required and must be selected', |
|
66 | + 'event_espresso' |
|
67 | + ); |
|
68 | + } |
|
69 | + |
|
70 | + |
|
71 | + /** |
|
72 | + * sets any and all template args that are required for this Ticket Selector |
|
73 | + * |
|
74 | + * @return void |
|
75 | + */ |
|
76 | + abstract protected function addTemplateArgs(); |
|
77 | + |
|
78 | + |
|
79 | + /** |
|
80 | + * loadTicketSelectorTemplate |
|
81 | + * |
|
82 | + * @return string |
|
83 | + */ |
|
84 | + protected function loadTicketSelectorTemplate() |
|
85 | + { |
|
86 | + try { |
|
87 | + $this->template_args['hidden_inputs'] = $this->getHiddenInputs(); |
|
88 | + return EEH_Template::locate_template( |
|
89 | + apply_filters( |
|
90 | + 'FHEE__EE_Ticket_Selector__display_ticket_selector__template_path', |
|
91 | + $this->template_args['template_path'], |
|
92 | + $this->event |
|
93 | + ), |
|
94 | + $this->template_args |
|
95 | + ); |
|
96 | + } catch (Exception $e) { |
|
97 | + EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__); |
|
98 | + } |
|
99 | + return ''; |
|
100 | + } |
|
101 | + |
|
102 | + |
|
103 | + /** |
|
104 | + * The __toString method allows a class to decide how it will react when it is converted to a string. |
|
105 | + * |
|
106 | + * @return string |
|
107 | + * @link http://php.net/manual/en/language.oop5.magic.php#language.oop5.magic.tostring |
|
108 | + */ |
|
109 | + public function __toString() |
|
110 | + { |
|
111 | + return $this->loadTicketSelectorTemplate(); |
|
112 | + } |
|
113 | + |
|
114 | + |
|
115 | + /** |
|
116 | + * getHiddenInputs |
|
117 | + * |
|
118 | + * @return string |
|
119 | + * @throws EE_Error |
|
120 | + * @throws ReflectionException |
|
121 | + */ |
|
122 | + public function getHiddenInputs() |
|
123 | + { |
|
124 | + $html = '<input type="hidden" name="noheader" value="true"/>'; |
|
125 | + $html .= '<input type="hidden" name="tkt-slctr-return-url-' . $this->event->ID() . '"'; |
|
126 | + $html .= ' value="' . EEH_URL::current_url() . $this->template_args['anchor_id'] . '"/>'; |
|
127 | + $html .= '<input type="hidden" name="tkt-slctr-rows-' . $this->event->ID(); |
|
128 | + $html .= '" value="' . $this->ticket_rows . '"/>'; |
|
129 | + $html .= '<input type="hidden" name="tkt-slctr-max-atndz-' . $this->event->ID(); |
|
130 | + $html .= '" value="' . $this->template_args['max_atndz'] . '"/>'; |
|
131 | + $html .= '<input type="hidden" name="tkt-slctr-event-id" value="' . $this->event->ID() . '"/>'; |
|
132 | + return $html; |
|
133 | + } |
|
134 | 134 | } |
@@ -21,148 +21,148 @@ |
||
21 | 21 | */ |
22 | 22 | class TicketSelectorStandard extends TicketSelector |
23 | 23 | { |
24 | - protected string $date_format; |
|
24 | + protected string $date_format; |
|
25 | 25 | |
26 | - protected string $time_format; |
|
26 | + protected string $time_format; |
|
27 | 27 | |
28 | - protected EE_Ticket_Selector_Config $ticket_selector_config; |
|
28 | + protected EE_Ticket_Selector_Config $ticket_selector_config; |
|
29 | 29 | |
30 | - protected EE_Tax_Config $tax_config; |
|
30 | + protected EE_Tax_Config $tax_config; |
|
31 | 31 | |
32 | 32 | |
33 | - /** |
|
34 | - * TicketSelectorSimple constructor. |
|
35 | - * |
|
36 | - * @param EE_Ticket_Selector_Config $ticket_selector_config |
|
37 | - * @param EE_Tax_Config $tax_config |
|
38 | - * @param EE_Event $event |
|
39 | - * @param EE_Ticket[] $tickets |
|
40 | - * @param int $max_attendees |
|
41 | - * @param array $template_args |
|
42 | - * @param string $date_format |
|
43 | - * @param string $time_format |
|
44 | - */ |
|
45 | - public function __construct( |
|
46 | - EE_Ticket_Selector_Config $ticket_selector_config, |
|
47 | - EE_Tax_Config $tax_config, |
|
48 | - EE_Event $event, |
|
49 | - array $tickets, |
|
50 | - int $max_attendees, |
|
51 | - array $template_args, |
|
52 | - string $date_format = 'Y-m-d', |
|
53 | - string $time_format = 'g:i a' |
|
54 | - ) { |
|
55 | - $this->ticket_selector_config = $ticket_selector_config; |
|
56 | - $this->tax_config = $tax_config; |
|
57 | - $this->date_format = $date_format; |
|
58 | - $this->time_format = $time_format; |
|
59 | - parent::__construct($event, $tickets, $max_attendees, $template_args); |
|
60 | - } |
|
33 | + /** |
|
34 | + * TicketSelectorSimple constructor. |
|
35 | + * |
|
36 | + * @param EE_Ticket_Selector_Config $ticket_selector_config |
|
37 | + * @param EE_Tax_Config $tax_config |
|
38 | + * @param EE_Event $event |
|
39 | + * @param EE_Ticket[] $tickets |
|
40 | + * @param int $max_attendees |
|
41 | + * @param array $template_args |
|
42 | + * @param string $date_format |
|
43 | + * @param string $time_format |
|
44 | + */ |
|
45 | + public function __construct( |
|
46 | + EE_Ticket_Selector_Config $ticket_selector_config, |
|
47 | + EE_Tax_Config $tax_config, |
|
48 | + EE_Event $event, |
|
49 | + array $tickets, |
|
50 | + int $max_attendees, |
|
51 | + array $template_args, |
|
52 | + string $date_format = 'Y-m-d', |
|
53 | + string $time_format = 'g:i a' |
|
54 | + ) { |
|
55 | + $this->ticket_selector_config = $ticket_selector_config; |
|
56 | + $this->tax_config = $tax_config; |
|
57 | + $this->date_format = $date_format; |
|
58 | + $this->time_format = $time_format; |
|
59 | + parent::__construct($event, $tickets, $max_attendees, $template_args); |
|
60 | + } |
|
61 | 61 | |
62 | 62 | |
63 | - /** |
|
64 | - * sets any and all template args that are required for this Ticket Selector |
|
65 | - * |
|
66 | - * @return void |
|
67 | - * @throws EE_Error |
|
68 | - * @throws ReflectionException |
|
69 | - */ |
|
70 | - protected function addTemplateArgs() |
|
71 | - { |
|
72 | - $this->ticket_rows = 0; |
|
73 | - $all_ticket_rows_html = ''; |
|
74 | - $required_ticket_sold_out = false; |
|
75 | - // flag to indicate that at least one taxable ticket has been encountered |
|
76 | - $taxable_tickets = false; |
|
77 | - $datetime_selector = null; |
|
78 | - $this->template_args['datetime_selector'] = ''; |
|
79 | - if ( |
|
80 | - $this->ticket_selector_config->getShowDatetimeSelector() |
|
81 | - !== EE_Ticket_Selector_Config::DO_NOT_SHOW_DATETIME_SELECTOR |
|
82 | - ) { |
|
83 | - $datetime_selector = new DatetimeSelector( |
|
84 | - $this->event, |
|
85 | - $this->tickets, |
|
86 | - $this->ticket_selector_config, |
|
87 | - $this->date_format, |
|
88 | - $this->time_format |
|
89 | - ); |
|
90 | - $this->template_args['datetime_selector'] = $datetime_selector->getDatetimeSelector(); |
|
91 | - } |
|
63 | + /** |
|
64 | + * sets any and all template args that are required for this Ticket Selector |
|
65 | + * |
|
66 | + * @return void |
|
67 | + * @throws EE_Error |
|
68 | + * @throws ReflectionException |
|
69 | + */ |
|
70 | + protected function addTemplateArgs() |
|
71 | + { |
|
72 | + $this->ticket_rows = 0; |
|
73 | + $all_ticket_rows_html = ''; |
|
74 | + $required_ticket_sold_out = false; |
|
75 | + // flag to indicate that at least one taxable ticket has been encountered |
|
76 | + $taxable_tickets = false; |
|
77 | + $datetime_selector = null; |
|
78 | + $this->template_args['datetime_selector'] = ''; |
|
79 | + if ( |
|
80 | + $this->ticket_selector_config->getShowDatetimeSelector() |
|
81 | + !== EE_Ticket_Selector_Config::DO_NOT_SHOW_DATETIME_SELECTOR |
|
82 | + ) { |
|
83 | + $datetime_selector = new DatetimeSelector( |
|
84 | + $this->event, |
|
85 | + $this->tickets, |
|
86 | + $this->ticket_selector_config, |
|
87 | + $this->date_format, |
|
88 | + $this->time_format |
|
89 | + ); |
|
90 | + $this->template_args['datetime_selector'] = $datetime_selector->getDatetimeSelector(); |
|
91 | + } |
|
92 | 92 | |
93 | - $total_tickets = count($this->tickets); |
|
94 | - // loop through tickets |
|
95 | - foreach ($this->tickets as $ticket) { |
|
96 | - if ($ticket instanceof EE_Ticket) { |
|
97 | - $this->ticket_rows++; |
|
98 | - $cols = 2; |
|
99 | - $taxable_tickets = $ticket->taxable() ? true : $taxable_tickets; |
|
100 | - $ticket_selector_row = new TicketSelectorRowStandard( |
|
101 | - new TicketDetails($ticket, $this->ticket_selector_config, $this->template_args), |
|
102 | - $this->tax_config, |
|
103 | - $total_tickets, |
|
104 | - $this->max_attendees, |
|
105 | - $this->ticket_rows, |
|
106 | - $cols, |
|
107 | - $required_ticket_sold_out, |
|
108 | - $this->template_args['event_status'], |
|
109 | - $datetime_selector instanceof DatetimeSelector |
|
110 | - ? $datetime_selector->getTicketDatetimeClasses($ticket) |
|
111 | - : '', |
|
112 | - $this->ticket_selector_config->useNewCheckboxSelector() |
|
113 | - ); |
|
114 | - $ticket_row_html = $ticket_selector_row->getHtml(); |
|
115 | - // check if something was actually returned |
|
116 | - if (! empty($ticket_row_html)) { |
|
117 | - // add any output to the cumulative HTML |
|
118 | - $all_ticket_rows_html .= $ticket_row_html; |
|
119 | - } |
|
120 | - if (empty($ticket_row_html) || ! $ticket_selector_row->isOnSale()) { |
|
121 | - // decrement the ticket row count since it looks like one has been removed |
|
122 | - $this->ticket_rows--; |
|
123 | - } |
|
93 | + $total_tickets = count($this->tickets); |
|
94 | + // loop through tickets |
|
95 | + foreach ($this->tickets as $ticket) { |
|
96 | + if ($ticket instanceof EE_Ticket) { |
|
97 | + $this->ticket_rows++; |
|
98 | + $cols = 2; |
|
99 | + $taxable_tickets = $ticket->taxable() ? true : $taxable_tickets; |
|
100 | + $ticket_selector_row = new TicketSelectorRowStandard( |
|
101 | + new TicketDetails($ticket, $this->ticket_selector_config, $this->template_args), |
|
102 | + $this->tax_config, |
|
103 | + $total_tickets, |
|
104 | + $this->max_attendees, |
|
105 | + $this->ticket_rows, |
|
106 | + $cols, |
|
107 | + $required_ticket_sold_out, |
|
108 | + $this->template_args['event_status'], |
|
109 | + $datetime_selector instanceof DatetimeSelector |
|
110 | + ? $datetime_selector->getTicketDatetimeClasses($ticket) |
|
111 | + : '', |
|
112 | + $this->ticket_selector_config->useNewCheckboxSelector() |
|
113 | + ); |
|
114 | + $ticket_row_html = $ticket_selector_row->getHtml(); |
|
115 | + // check if something was actually returned |
|
116 | + if (! empty($ticket_row_html)) { |
|
117 | + // add any output to the cumulative HTML |
|
118 | + $all_ticket_rows_html .= $ticket_row_html; |
|
119 | + } |
|
120 | + if (empty($ticket_row_html) || ! $ticket_selector_row->isOnSale()) { |
|
121 | + // decrement the ticket row count since it looks like one has been removed |
|
122 | + $this->ticket_rows--; |
|
123 | + } |
|
124 | 124 | |
125 | - $required_ticket_sold_out = $ticket_selector_row->getRequiredTicketSoldOut(); |
|
126 | - } |
|
127 | - } |
|
128 | - $this->template_args['allowed_form_tags'] = AllowedTags::getWithFormTags(); |
|
129 | - $this->template_args['row'] = $this->ticket_rows; |
|
130 | - $this->template_args['ticket_row_html'] = $all_ticket_rows_html; |
|
131 | - $this->template_args['taxable_tickets'] = $taxable_tickets; |
|
132 | - $this->template_args['use_new_form_styles_class'] = $this->ticket_selector_config->useNewFormStyles() |
|
133 | - ? ' tkt-slctr-use-new-form-styles' |
|
134 | - : ''; |
|
135 | - $this->template_args['prices_displayed_including_taxes'] = $this->tax_config->prices_displayed_including_taxes; |
|
125 | + $required_ticket_sold_out = $ticket_selector_row->getRequiredTicketSoldOut(); |
|
126 | + } |
|
127 | + } |
|
128 | + $this->template_args['allowed_form_tags'] = AllowedTags::getWithFormTags(); |
|
129 | + $this->template_args['row'] = $this->ticket_rows; |
|
130 | + $this->template_args['ticket_row_html'] = $all_ticket_rows_html; |
|
131 | + $this->template_args['taxable_tickets'] = $taxable_tickets; |
|
132 | + $this->template_args['use_new_form_styles_class'] = $this->ticket_selector_config->useNewFormStyles() |
|
133 | + ? ' tkt-slctr-use-new-form-styles' |
|
134 | + : ''; |
|
135 | + $this->template_args['prices_displayed_including_taxes'] = $this->tax_config->prices_displayed_including_taxes; |
|
136 | 136 | |
137 | 137 | |
138 | - /** |
|
139 | - * Filters the text printed for the header of the price column in the ticket selector table |
|
140 | - * |
|
141 | - * @param string 'Price' The translatable text to display in the table header for price |
|
142 | - * @param int $EVT_ID The Event ID |
|
143 | - * @since 4.7.2 |
|
144 | - * |
|
145 | - */ |
|
146 | - $this->template_args['table_header_price'] = apply_filters( |
|
147 | - 'FHEE__ticket_selector_chart_template__table_header_price', |
|
148 | - esc_html__('Price', 'event_espresso'), |
|
149 | - $this->event->ID() |
|
150 | - ); |
|
138 | + /** |
|
139 | + * Filters the text printed for the header of the price column in the ticket selector table |
|
140 | + * |
|
141 | + * @param string 'Price' The translatable text to display in the table header for price |
|
142 | + * @param int $EVT_ID The Event ID |
|
143 | + * @since 4.7.2 |
|
144 | + * |
|
145 | + */ |
|
146 | + $this->template_args['table_header_price'] = apply_filters( |
|
147 | + 'FHEE__ticket_selector_chart_template__table_header_price', |
|
148 | + esc_html__('Price', 'event_espresso'), |
|
149 | + $this->event->ID() |
|
150 | + ); |
|
151 | 151 | |
152 | - /** |
|
153 | - * Filters the text printed for the header of the quantity column in the ticket selector table |
|
154 | - * |
|
155 | - * @param string 'Qty' The translatable text to display in the table header for the Quantity of tickets |
|
156 | - * @param int $EVT_ID The Event ID |
|
157 | - * @since 4.7.2 |
|
158 | - * |
|
159 | - */ |
|
160 | - $this->template_args['table_header_qty'] = apply_filters( |
|
161 | - 'FHEE__ticket_selector_chart_template__table_header_qty', |
|
162 | - esc_html__('Qty', 'event_espresso'), |
|
163 | - $this->event->ID() |
|
164 | - ); |
|
165 | - $this->template_args['template_path'] = TICKET_SELECTOR_TEMPLATES_PATH . 'standard_ticket_selector.template.php'; |
|
166 | - remove_all_filters('FHEE__EE_Ticket_Selector__hide_ticket_selector'); |
|
167 | - } |
|
152 | + /** |
|
153 | + * Filters the text printed for the header of the quantity column in the ticket selector table |
|
154 | + * |
|
155 | + * @param string 'Qty' The translatable text to display in the table header for the Quantity of tickets |
|
156 | + * @param int $EVT_ID The Event ID |
|
157 | + * @since 4.7.2 |
|
158 | + * |
|
159 | + */ |
|
160 | + $this->template_args['table_header_qty'] = apply_filters( |
|
161 | + 'FHEE__ticket_selector_chart_template__table_header_qty', |
|
162 | + esc_html__('Qty', 'event_espresso'), |
|
163 | + $this->event->ID() |
|
164 | + ); |
|
165 | + $this->template_args['template_path'] = TICKET_SELECTOR_TEMPLATES_PATH . 'standard_ticket_selector.template.php'; |
|
166 | + remove_all_filters('FHEE__EE_Ticket_Selector__hide_ticket_selector'); |
|
167 | + } |
|
168 | 168 | } |
@@ -14,32 +14,32 @@ |
||
14 | 14 | */ |
15 | 15 | class TicketSelectorRowSimple extends TicketSelectorRow |
16 | 16 | { |
17 | - /** |
|
18 | - * @throws EE_Error |
|
19 | - * @throws ReflectionException |
|
20 | - */ |
|
21 | - public function setupTicketStatusDisplay() |
|
22 | - { |
|
23 | - $remaining = $this->ticket->remaining(); |
|
24 | - $this->setTicketMinAndMax($remaining); |
|
25 | - $this->setTicketStatusClasses($remaining); |
|
26 | - $this->setTicketStatusDisplay($remaining); |
|
27 | - } |
|
17 | + /** |
|
18 | + * @throws EE_Error |
|
19 | + * @throws ReflectionException |
|
20 | + */ |
|
21 | + public function setupTicketStatusDisplay() |
|
22 | + { |
|
23 | + $remaining = $this->ticket->remaining(); |
|
24 | + $this->setTicketMinAndMax($remaining); |
|
25 | + $this->setTicketStatusClasses($remaining); |
|
26 | + $this->setTicketStatusDisplay($remaining); |
|
27 | + } |
|
28 | 28 | |
29 | 29 | |
30 | - /** |
|
31 | - * @return bool|string |
|
32 | - * @throws EE_Error |
|
33 | - * @throws ReflectionException |
|
34 | - */ |
|
35 | - public function getTicketDescription() |
|
36 | - { |
|
37 | - $filtered_row_content = $this->getFilteredRowContents(); |
|
38 | - if ($filtered_row_content !== false) { |
|
39 | - remove_filter('FHEE__EE_Ticket_Selector__display_ticket_selector_submit', '__return_true'); |
|
40 | - add_filter('FHEE__EE_Ticket_Selector__display_ticket_selector_submit', '__return_false'); |
|
41 | - return $filtered_row_content; |
|
42 | - } |
|
43 | - return $this->ticket->description(); |
|
44 | - } |
|
30 | + /** |
|
31 | + * @return bool|string |
|
32 | + * @throws EE_Error |
|
33 | + * @throws ReflectionException |
|
34 | + */ |
|
35 | + public function getTicketDescription() |
|
36 | + { |
|
37 | + $filtered_row_content = $this->getFilteredRowContents(); |
|
38 | + if ($filtered_row_content !== false) { |
|
39 | + remove_filter('FHEE__EE_Ticket_Selector__display_ticket_selector_submit', '__return_true'); |
|
40 | + add_filter('FHEE__EE_Ticket_Selector__display_ticket_selector_submit', '__return_false'); |
|
41 | + return $filtered_row_content; |
|
42 | + } |
|
43 | + return $this->ticket->description(); |
|
44 | + } |
|
45 | 45 | } |
@@ -19,393 +19,393 @@ |
||
19 | 19 | */ |
20 | 20 | class TicketSelectorRowStandard extends TicketSelectorRow |
21 | 21 | { |
22 | - /** |
|
23 | - * @var TicketDetails |
|
24 | - */ |
|
25 | - protected $ticket_details; |
|
26 | - |
|
27 | - /** |
|
28 | - * @var EE_Ticket_Selector_Config |
|
29 | - */ |
|
30 | - protected $template_settings; |
|
31 | - |
|
32 | - /** |
|
33 | - * @var EE_Tax_Config |
|
34 | - */ |
|
35 | - protected $tax_settings; |
|
36 | - |
|
37 | - /** |
|
38 | - * @var boolean |
|
39 | - */ |
|
40 | - protected $prices_displayed_including_taxes; |
|
41 | - |
|
42 | - /** |
|
43 | - * @var int |
|
44 | - */ |
|
45 | - protected $row; |
|
46 | - |
|
47 | - /** |
|
48 | - * @var int |
|
49 | - */ |
|
50 | - protected $cols; |
|
51 | - |
|
52 | - /** |
|
53 | - * @var boolean |
|
54 | - */ |
|
55 | - protected $hidden_input_qty = false; |
|
56 | - |
|
57 | - /** |
|
58 | - * @var string |
|
59 | - */ |
|
60 | - protected $ticket_datetime_classes; |
|
61 | - |
|
62 | - private bool $use_new_checkbox_selector; |
|
63 | - |
|
64 | - |
|
65 | - /** |
|
66 | - * TicketDetails constructor. |
|
67 | - * |
|
68 | - * @param TicketDetails $ticket_details |
|
69 | - * @param EE_Tax_Config $tax_settings |
|
70 | - * @param int $total_tickets |
|
71 | - * @param int $max_attendees |
|
72 | - * @param int $row |
|
73 | - * @param int $cols |
|
74 | - * @param boolean $required_ticket_sold_out |
|
75 | - * @param string $event_status |
|
76 | - * @param string $ticket_datetime_classes |
|
77 | - * @param bool $use_new_checkbox_selector |
|
78 | - * @throws EE_Error |
|
79 | - * @throws UnexpectedEntityException |
|
80 | - */ |
|
81 | - public function __construct( |
|
82 | - TicketDetails $ticket_details, |
|
83 | - EE_Tax_Config $tax_settings, |
|
84 | - $total_tickets, |
|
85 | - $max_attendees, |
|
86 | - $row, |
|
87 | - $cols, |
|
88 | - $required_ticket_sold_out, |
|
89 | - $event_status, |
|
90 | - $ticket_datetime_classes, |
|
91 | - bool $use_new_checkbox_selector = false |
|
92 | - ) { |
|
93 | - $this->ticket_details = $ticket_details; |
|
94 | - $this->template_settings = $ticket_details->getTemplateSettings(); |
|
95 | - $this->tax_settings = $tax_settings; |
|
96 | - $this->row = $row; |
|
97 | - $this->cols = $cols; |
|
98 | - $this->ticket_datetime_classes = $ticket_datetime_classes; |
|
99 | - $this->use_new_checkbox_selector = $use_new_checkbox_selector; |
|
100 | - parent::__construct( |
|
101 | - $ticket_details->getTicket(), |
|
102 | - $max_attendees, |
|
103 | - $ticket_details->getDateFormat(), |
|
104 | - $event_status, |
|
105 | - $required_ticket_sold_out, |
|
106 | - $total_tickets |
|
107 | - ); |
|
108 | - } |
|
109 | - |
|
110 | - |
|
111 | - /** |
|
112 | - * other ticket rows will need to know if a required ticket is sold out, |
|
113 | - * so that they are not offered for sale |
|
114 | - * |
|
115 | - * @return boolean |
|
116 | - */ |
|
117 | - public function getRequiredTicketSoldOut() |
|
118 | - { |
|
119 | - return $this->required_ticket_sold_out; |
|
120 | - } |
|
121 | - |
|
122 | - |
|
123 | - /** |
|
124 | - * @return int |
|
125 | - */ |
|
126 | - public function getCols() |
|
127 | - { |
|
128 | - return $this->cols; |
|
129 | - } |
|
130 | - |
|
131 | - |
|
132 | - /** |
|
133 | - * getHtml |
|
134 | - * |
|
135 | - * @return string |
|
136 | - * @throws EE_Error |
|
137 | - * @throws ReflectionException |
|
138 | - */ |
|
139 | - public function getHtml() |
|
140 | - { |
|
141 | - $this->min = 0; |
|
142 | - $this->max = $this->ticket->max(); |
|
143 | - $remaining = $this->ticket->remaining(); |
|
144 | - $this->setTicketMinAndMax($remaining); |
|
145 | - // set flag if ticket is required (flag is set to start date so that future tickets are not blocked) |
|
146 | - $this->required_ticket_sold_out = $this->ticket->required() && ! $remaining |
|
147 | - ? $this->ticket->start_date() |
|
148 | - : $this->required_ticket_sold_out; |
|
149 | - $this->setTicketPriceDetails(); |
|
150 | - $this->setTicketStatusClasses($remaining); |
|
151 | - $filtered_row_html = $this->getFilteredRowHtml(); |
|
152 | - if ($filtered_row_html !== false) { |
|
153 | - return $filtered_row_html; |
|
154 | - } |
|
155 | - $ticket_selector_row_html = EEH_HTML::tr( |
|
156 | - '', |
|
157 | - '', |
|
158 | - "tckt-slctr-tbl-tr {$this->status_class}{$this->ticket_datetime_classes} " |
|
159 | - . espresso_get_object_css_class($this->ticket) |
|
160 | - ); |
|
161 | - $filtered_row_content = $this->getFilteredRowContents(); |
|
162 | - if ($filtered_row_content !== false) { |
|
163 | - if ($this->max_attendees === 1) { |
|
164 | - return $ticket_selector_row_html |
|
165 | - . $filtered_row_content |
|
166 | - . $this->ticketQtyAndIdHiddenInputs() |
|
167 | - . EEH_HTML::trx(); |
|
168 | - } |
|
169 | - return $ticket_selector_row_html |
|
170 | - . $filtered_row_content |
|
171 | - . EEH_HTML::trx(); |
|
172 | - } |
|
173 | - $this->hidden_input_qty = $this->max_attendees > 1; |
|
174 | - |
|
175 | - $ticket_selector_row_html .= $this->ticketNameTableCell(); |
|
176 | - $ticket_selector_row_html .= $this->ticketPriceTableCell(); |
|
177 | - $ticket_selector_row_html .= EEH_HTML::td( |
|
178 | - '', |
|
179 | - '', |
|
180 | - 'tckt-slctr-tbl-td-qty cntr', |
|
181 | - '', |
|
182 | - 'headers="quantity-' . $this->EVT_ID . '"' |
|
183 | - ); |
|
184 | - $this->setTicketStatusDisplay($remaining); |
|
185 | - if (empty($this->ticket_status_display)) { |
|
186 | - $this->hidden_input_qty = false; |
|
187 | - // display submit button since we have tickets available |
|
188 | - add_filter('FHEE__EE_Ticket_Selector__display_ticket_selector_submit', '__return_true'); |
|
189 | - if ($this->max_attendees === 1) { |
|
190 | - // only ONE attendee is allowed to register at a time |
|
191 | - $ticket_selector_row_html .= $this->onlyOneAttendeeCanRegister(); |
|
192 | - } else { |
|
193 | - $ticket_selector_row_html .= $this->max === 1 && $this->use_new_checkbox_selector |
|
194 | - ? $this->ticketCheckboxSelector() |
|
195 | - : $this->ticketQuantitySelector(); |
|
196 | - } |
|
197 | - } |
|
198 | - $ticket_selector_row_html .= $this->ticket_status_display; |
|
199 | - $ticket_selector_row_html .= $this->ticketQtyAndIdHiddenInputs(); |
|
200 | - $ticket_selector_row_html .= $this->ticket_details->display( |
|
201 | - $this->ticket_price, |
|
202 | - $remaining, |
|
203 | - $this->cols |
|
204 | - ); |
|
205 | - $ticket_selector_row_html .= EEH_HTML::tdx(); |
|
206 | - $ticket_selector_row_html .= EEH_HTML::trx(); |
|
207 | - |
|
208 | - |
|
209 | - $this->row++; |
|
210 | - return $ticket_selector_row_html; |
|
211 | - } |
|
212 | - |
|
213 | - |
|
214 | - /** |
|
215 | - * getTicketPriceDetails |
|
216 | - * |
|
217 | - * @return void |
|
218 | - * @throws EE_Error |
|
219 | - * @throws ReflectionException |
|
220 | - */ |
|
221 | - protected function setTicketPriceDetails() |
|
222 | - { |
|
223 | - $this->ticket_price = $this->tax_settings->prices_displayed_including_taxes |
|
224 | - ? $this->ticket->get_ticket_total_with_taxes() |
|
225 | - : $this->ticket->get_ticket_subtotal(); |
|
226 | - $this->ticket_bundle = false; |
|
227 | - $ticket_min = $this->ticket->min(); |
|
228 | - // for ticket bundles, set min and max qty the same |
|
229 | - if ($ticket_min !== 0 && $ticket_min === $this->ticket->max()) { |
|
230 | - $this->ticket_price *= $ticket_min; |
|
231 | - $this->ticket_bundle = true; |
|
232 | - } |
|
233 | - $this->ticket_price = apply_filters( |
|
234 | - 'FHEE__ticket_selector_chart_template__ticket_price', |
|
235 | - $this->ticket_price, |
|
236 | - $this->ticket |
|
237 | - ); |
|
238 | - } |
|
239 | - |
|
240 | - |
|
241 | - /** |
|
242 | - * ticketNameTableCell |
|
243 | - * |
|
244 | - * @return string |
|
245 | - * @throws EE_Error |
|
246 | - * @throws ReflectionException |
|
247 | - */ |
|
248 | - protected function ticketNameTableCell() |
|
249 | - { |
|
250 | - $html = EEH_HTML::td( |
|
251 | - '', |
|
252 | - '', |
|
253 | - 'tckt-slctr-tbl-td-name', |
|
254 | - '', |
|
255 | - 'headers="details-' . $this->EVT_ID . '"' |
|
256 | - ); |
|
257 | - $html .= EEH_HTML::strong($this->ticket->get_pretty('TKT_name')); |
|
258 | - $html .= $this->ticket_details->getShowHideLinks(); |
|
259 | - if ($this->ticket->required()) { |
|
260 | - $html .= EEH_HTML::p( |
|
261 | - apply_filters( |
|
262 | - 'FHEE__ticket_selector_chart_template__ticket_required_message', |
|
263 | - esc_html__('This ticket is required and must be purchased.', 'event_espresso') |
|
264 | - ), |
|
265 | - '', |
|
266 | - 'ticket-required-pg' |
|
267 | - ); |
|
268 | - } |
|
269 | - $html .= EEH_HTML::tdx(); |
|
270 | - return $html; |
|
271 | - } |
|
272 | - |
|
273 | - |
|
274 | - /** |
|
275 | - * ticketPriceTableCell |
|
276 | - * |
|
277 | - * @return string |
|
278 | - * @throws EE_Error |
|
279 | - * @throws ReflectionException |
|
280 | - */ |
|
281 | - protected function ticketPriceTableCell() |
|
282 | - { |
|
283 | - $html = ''; |
|
284 | - if (apply_filters('FHEE__ticket_selector_chart_template__display_ticket_price_details', true)) { |
|
285 | - $html .= EEH_HTML::td( |
|
286 | - '', |
|
287 | - '', |
|
288 | - 'tckt-slctr-tbl-td-price jst-rght', |
|
289 | - '', |
|
290 | - 'headers="price-' . $this->EVT_ID . '"' |
|
291 | - ); |
|
292 | - $html .= EEH_HTML::span( |
|
293 | - EEH_Template::format_currency($this->ticket_price), |
|
294 | - '', |
|
295 | - 'tckt-price--nowrap' |
|
296 | - ); |
|
297 | - $html .= $this->ticket->taxable() |
|
298 | - ? EEH_HTML::span('*', '', 'taxable-tickets-asterisk grey-text') |
|
299 | - : ''; |
|
300 | - $html .= ' '; |
|
301 | - // phpcs:disable WordPress.WP.I18n.NoEmptyStrings |
|
302 | - $html .= EEH_HTML::span( |
|
303 | - $this->ticket_bundle |
|
304 | - ? apply_filters( |
|
305 | - 'FHEE__ticket_selector_chart_template__per_ticket_bundle_text', |
|
306 | - esc_html__(' / bundle', 'event_espresso') |
|
307 | - ) |
|
308 | - : apply_filters( |
|
309 | - 'FHEE__ticket_selector_chart_template__per_ticket_text', |
|
310 | - esc_html__('', 'event_espresso') |
|
311 | - ), |
|
312 | - '', |
|
313 | - 'smaller-text no-bold' |
|
314 | - ); |
|
315 | - $html .= ' '; |
|
316 | - $html .= EEH_HTML::tdx(); |
|
317 | - $this->cols++; |
|
318 | - } |
|
319 | - return $html; |
|
320 | - } |
|
321 | - |
|
322 | - |
|
323 | - /** |
|
324 | - * @return string |
|
325 | - * @throws EE_Error |
|
326 | - * @throws ReflectionException |
|
327 | - */ |
|
328 | - protected function onlyOneAttendeeCanRegister(): string |
|
329 | - { |
|
330 | - $TKT = $this->ticket->ID(); |
|
331 | - $label = esc_html__('Select this ticket', 'event_espresso'); |
|
332 | - $name = "tkt-slctr-qty-$this->EVT_ID"; |
|
333 | - $class = "ticket-selector-tbl-qty-slct"; |
|
334 | - $id = "$class-$this->EVT_ID-$this->row"; |
|
335 | - $checked = $this->total_tickets === 1 ? ' checked="checked"' : ''; |
|
336 | - |
|
337 | - return " |
|
22 | + /** |
|
23 | + * @var TicketDetails |
|
24 | + */ |
|
25 | + protected $ticket_details; |
|
26 | + |
|
27 | + /** |
|
28 | + * @var EE_Ticket_Selector_Config |
|
29 | + */ |
|
30 | + protected $template_settings; |
|
31 | + |
|
32 | + /** |
|
33 | + * @var EE_Tax_Config |
|
34 | + */ |
|
35 | + protected $tax_settings; |
|
36 | + |
|
37 | + /** |
|
38 | + * @var boolean |
|
39 | + */ |
|
40 | + protected $prices_displayed_including_taxes; |
|
41 | + |
|
42 | + /** |
|
43 | + * @var int |
|
44 | + */ |
|
45 | + protected $row; |
|
46 | + |
|
47 | + /** |
|
48 | + * @var int |
|
49 | + */ |
|
50 | + protected $cols; |
|
51 | + |
|
52 | + /** |
|
53 | + * @var boolean |
|
54 | + */ |
|
55 | + protected $hidden_input_qty = false; |
|
56 | + |
|
57 | + /** |
|
58 | + * @var string |
|
59 | + */ |
|
60 | + protected $ticket_datetime_classes; |
|
61 | + |
|
62 | + private bool $use_new_checkbox_selector; |
|
63 | + |
|
64 | + |
|
65 | + /** |
|
66 | + * TicketDetails constructor. |
|
67 | + * |
|
68 | + * @param TicketDetails $ticket_details |
|
69 | + * @param EE_Tax_Config $tax_settings |
|
70 | + * @param int $total_tickets |
|
71 | + * @param int $max_attendees |
|
72 | + * @param int $row |
|
73 | + * @param int $cols |
|
74 | + * @param boolean $required_ticket_sold_out |
|
75 | + * @param string $event_status |
|
76 | + * @param string $ticket_datetime_classes |
|
77 | + * @param bool $use_new_checkbox_selector |
|
78 | + * @throws EE_Error |
|
79 | + * @throws UnexpectedEntityException |
|
80 | + */ |
|
81 | + public function __construct( |
|
82 | + TicketDetails $ticket_details, |
|
83 | + EE_Tax_Config $tax_settings, |
|
84 | + $total_tickets, |
|
85 | + $max_attendees, |
|
86 | + $row, |
|
87 | + $cols, |
|
88 | + $required_ticket_sold_out, |
|
89 | + $event_status, |
|
90 | + $ticket_datetime_classes, |
|
91 | + bool $use_new_checkbox_selector = false |
|
92 | + ) { |
|
93 | + $this->ticket_details = $ticket_details; |
|
94 | + $this->template_settings = $ticket_details->getTemplateSettings(); |
|
95 | + $this->tax_settings = $tax_settings; |
|
96 | + $this->row = $row; |
|
97 | + $this->cols = $cols; |
|
98 | + $this->ticket_datetime_classes = $ticket_datetime_classes; |
|
99 | + $this->use_new_checkbox_selector = $use_new_checkbox_selector; |
|
100 | + parent::__construct( |
|
101 | + $ticket_details->getTicket(), |
|
102 | + $max_attendees, |
|
103 | + $ticket_details->getDateFormat(), |
|
104 | + $event_status, |
|
105 | + $required_ticket_sold_out, |
|
106 | + $total_tickets |
|
107 | + ); |
|
108 | + } |
|
109 | + |
|
110 | + |
|
111 | + /** |
|
112 | + * other ticket rows will need to know if a required ticket is sold out, |
|
113 | + * so that they are not offered for sale |
|
114 | + * |
|
115 | + * @return boolean |
|
116 | + */ |
|
117 | + public function getRequiredTicketSoldOut() |
|
118 | + { |
|
119 | + return $this->required_ticket_sold_out; |
|
120 | + } |
|
121 | + |
|
122 | + |
|
123 | + /** |
|
124 | + * @return int |
|
125 | + */ |
|
126 | + public function getCols() |
|
127 | + { |
|
128 | + return $this->cols; |
|
129 | + } |
|
130 | + |
|
131 | + |
|
132 | + /** |
|
133 | + * getHtml |
|
134 | + * |
|
135 | + * @return string |
|
136 | + * @throws EE_Error |
|
137 | + * @throws ReflectionException |
|
138 | + */ |
|
139 | + public function getHtml() |
|
140 | + { |
|
141 | + $this->min = 0; |
|
142 | + $this->max = $this->ticket->max(); |
|
143 | + $remaining = $this->ticket->remaining(); |
|
144 | + $this->setTicketMinAndMax($remaining); |
|
145 | + // set flag if ticket is required (flag is set to start date so that future tickets are not blocked) |
|
146 | + $this->required_ticket_sold_out = $this->ticket->required() && ! $remaining |
|
147 | + ? $this->ticket->start_date() |
|
148 | + : $this->required_ticket_sold_out; |
|
149 | + $this->setTicketPriceDetails(); |
|
150 | + $this->setTicketStatusClasses($remaining); |
|
151 | + $filtered_row_html = $this->getFilteredRowHtml(); |
|
152 | + if ($filtered_row_html !== false) { |
|
153 | + return $filtered_row_html; |
|
154 | + } |
|
155 | + $ticket_selector_row_html = EEH_HTML::tr( |
|
156 | + '', |
|
157 | + '', |
|
158 | + "tckt-slctr-tbl-tr {$this->status_class}{$this->ticket_datetime_classes} " |
|
159 | + . espresso_get_object_css_class($this->ticket) |
|
160 | + ); |
|
161 | + $filtered_row_content = $this->getFilteredRowContents(); |
|
162 | + if ($filtered_row_content !== false) { |
|
163 | + if ($this->max_attendees === 1) { |
|
164 | + return $ticket_selector_row_html |
|
165 | + . $filtered_row_content |
|
166 | + . $this->ticketQtyAndIdHiddenInputs() |
|
167 | + . EEH_HTML::trx(); |
|
168 | + } |
|
169 | + return $ticket_selector_row_html |
|
170 | + . $filtered_row_content |
|
171 | + . EEH_HTML::trx(); |
|
172 | + } |
|
173 | + $this->hidden_input_qty = $this->max_attendees > 1; |
|
174 | + |
|
175 | + $ticket_selector_row_html .= $this->ticketNameTableCell(); |
|
176 | + $ticket_selector_row_html .= $this->ticketPriceTableCell(); |
|
177 | + $ticket_selector_row_html .= EEH_HTML::td( |
|
178 | + '', |
|
179 | + '', |
|
180 | + 'tckt-slctr-tbl-td-qty cntr', |
|
181 | + '', |
|
182 | + 'headers="quantity-' . $this->EVT_ID . '"' |
|
183 | + ); |
|
184 | + $this->setTicketStatusDisplay($remaining); |
|
185 | + if (empty($this->ticket_status_display)) { |
|
186 | + $this->hidden_input_qty = false; |
|
187 | + // display submit button since we have tickets available |
|
188 | + add_filter('FHEE__EE_Ticket_Selector__display_ticket_selector_submit', '__return_true'); |
|
189 | + if ($this->max_attendees === 1) { |
|
190 | + // only ONE attendee is allowed to register at a time |
|
191 | + $ticket_selector_row_html .= $this->onlyOneAttendeeCanRegister(); |
|
192 | + } else { |
|
193 | + $ticket_selector_row_html .= $this->max === 1 && $this->use_new_checkbox_selector |
|
194 | + ? $this->ticketCheckboxSelector() |
|
195 | + : $this->ticketQuantitySelector(); |
|
196 | + } |
|
197 | + } |
|
198 | + $ticket_selector_row_html .= $this->ticket_status_display; |
|
199 | + $ticket_selector_row_html .= $this->ticketQtyAndIdHiddenInputs(); |
|
200 | + $ticket_selector_row_html .= $this->ticket_details->display( |
|
201 | + $this->ticket_price, |
|
202 | + $remaining, |
|
203 | + $this->cols |
|
204 | + ); |
|
205 | + $ticket_selector_row_html .= EEH_HTML::tdx(); |
|
206 | + $ticket_selector_row_html .= EEH_HTML::trx(); |
|
207 | + |
|
208 | + |
|
209 | + $this->row++; |
|
210 | + return $ticket_selector_row_html; |
|
211 | + } |
|
212 | + |
|
213 | + |
|
214 | + /** |
|
215 | + * getTicketPriceDetails |
|
216 | + * |
|
217 | + * @return void |
|
218 | + * @throws EE_Error |
|
219 | + * @throws ReflectionException |
|
220 | + */ |
|
221 | + protected function setTicketPriceDetails() |
|
222 | + { |
|
223 | + $this->ticket_price = $this->tax_settings->prices_displayed_including_taxes |
|
224 | + ? $this->ticket->get_ticket_total_with_taxes() |
|
225 | + : $this->ticket->get_ticket_subtotal(); |
|
226 | + $this->ticket_bundle = false; |
|
227 | + $ticket_min = $this->ticket->min(); |
|
228 | + // for ticket bundles, set min and max qty the same |
|
229 | + if ($ticket_min !== 0 && $ticket_min === $this->ticket->max()) { |
|
230 | + $this->ticket_price *= $ticket_min; |
|
231 | + $this->ticket_bundle = true; |
|
232 | + } |
|
233 | + $this->ticket_price = apply_filters( |
|
234 | + 'FHEE__ticket_selector_chart_template__ticket_price', |
|
235 | + $this->ticket_price, |
|
236 | + $this->ticket |
|
237 | + ); |
|
238 | + } |
|
239 | + |
|
240 | + |
|
241 | + /** |
|
242 | + * ticketNameTableCell |
|
243 | + * |
|
244 | + * @return string |
|
245 | + * @throws EE_Error |
|
246 | + * @throws ReflectionException |
|
247 | + */ |
|
248 | + protected function ticketNameTableCell() |
|
249 | + { |
|
250 | + $html = EEH_HTML::td( |
|
251 | + '', |
|
252 | + '', |
|
253 | + 'tckt-slctr-tbl-td-name', |
|
254 | + '', |
|
255 | + 'headers="details-' . $this->EVT_ID . '"' |
|
256 | + ); |
|
257 | + $html .= EEH_HTML::strong($this->ticket->get_pretty('TKT_name')); |
|
258 | + $html .= $this->ticket_details->getShowHideLinks(); |
|
259 | + if ($this->ticket->required()) { |
|
260 | + $html .= EEH_HTML::p( |
|
261 | + apply_filters( |
|
262 | + 'FHEE__ticket_selector_chart_template__ticket_required_message', |
|
263 | + esc_html__('This ticket is required and must be purchased.', 'event_espresso') |
|
264 | + ), |
|
265 | + '', |
|
266 | + 'ticket-required-pg' |
|
267 | + ); |
|
268 | + } |
|
269 | + $html .= EEH_HTML::tdx(); |
|
270 | + return $html; |
|
271 | + } |
|
272 | + |
|
273 | + |
|
274 | + /** |
|
275 | + * ticketPriceTableCell |
|
276 | + * |
|
277 | + * @return string |
|
278 | + * @throws EE_Error |
|
279 | + * @throws ReflectionException |
|
280 | + */ |
|
281 | + protected function ticketPriceTableCell() |
|
282 | + { |
|
283 | + $html = ''; |
|
284 | + if (apply_filters('FHEE__ticket_selector_chart_template__display_ticket_price_details', true)) { |
|
285 | + $html .= EEH_HTML::td( |
|
286 | + '', |
|
287 | + '', |
|
288 | + 'tckt-slctr-tbl-td-price jst-rght', |
|
289 | + '', |
|
290 | + 'headers="price-' . $this->EVT_ID . '"' |
|
291 | + ); |
|
292 | + $html .= EEH_HTML::span( |
|
293 | + EEH_Template::format_currency($this->ticket_price), |
|
294 | + '', |
|
295 | + 'tckt-price--nowrap' |
|
296 | + ); |
|
297 | + $html .= $this->ticket->taxable() |
|
298 | + ? EEH_HTML::span('*', '', 'taxable-tickets-asterisk grey-text') |
|
299 | + : ''; |
|
300 | + $html .= ' '; |
|
301 | + // phpcs:disable WordPress.WP.I18n.NoEmptyStrings |
|
302 | + $html .= EEH_HTML::span( |
|
303 | + $this->ticket_bundle |
|
304 | + ? apply_filters( |
|
305 | + 'FHEE__ticket_selector_chart_template__per_ticket_bundle_text', |
|
306 | + esc_html__(' / bundle', 'event_espresso') |
|
307 | + ) |
|
308 | + : apply_filters( |
|
309 | + 'FHEE__ticket_selector_chart_template__per_ticket_text', |
|
310 | + esc_html__('', 'event_espresso') |
|
311 | + ), |
|
312 | + '', |
|
313 | + 'smaller-text no-bold' |
|
314 | + ); |
|
315 | + $html .= ' '; |
|
316 | + $html .= EEH_HTML::tdx(); |
|
317 | + $this->cols++; |
|
318 | + } |
|
319 | + return $html; |
|
320 | + } |
|
321 | + |
|
322 | + |
|
323 | + /** |
|
324 | + * @return string |
|
325 | + * @throws EE_Error |
|
326 | + * @throws ReflectionException |
|
327 | + */ |
|
328 | + protected function onlyOneAttendeeCanRegister(): string |
|
329 | + { |
|
330 | + $TKT = $this->ticket->ID(); |
|
331 | + $label = esc_html__('Select this ticket', 'event_espresso'); |
|
332 | + $name = "tkt-slctr-qty-$this->EVT_ID"; |
|
333 | + $class = "ticket-selector-tbl-qty-slct"; |
|
334 | + $id = "$class-$this->EVT_ID-$this->row"; |
|
335 | + $checked = $this->total_tickets === 1 ? ' checked="checked"' : ''; |
|
336 | + |
|
337 | + return " |
|
338 | 338 | <label class='ee-a11y-screen-reader-text' for='$id' >$label</label> |
339 | 339 | <input type='radio'$checked name='$name' id='$id' class='$class' value='$TKT-1'/>"; |
340 | - } |
|
341 | - |
|
342 | - |
|
343 | - /** |
|
344 | - * @return string |
|
345 | - * @throws EE_Error |
|
346 | - * @throws ReflectionException |
|
347 | - */ |
|
348 | - protected function ticketCheckboxSelector(): string |
|
349 | - { |
|
350 | - $TKT = $this->ticket->ID(); |
|
351 | - $label = esc_html__('Select this ticket', 'event_espresso'); |
|
352 | - $name = "tkt-slctr-qty-$this->EVT_ID[$TKT]"; |
|
353 | - $class = 'ticket-selector-tbl-qty-slct'; |
|
354 | - $id = "$class-$this->EVT_ID-$this->row"; |
|
355 | - $title = esc_html__('only one of this ticket can be purchased at a time', 'event_espresso'); |
|
356 | - $checked = $this->ticket->required() ? ' checked="checked"' : ''; |
|
357 | - $required = $this->ticket->required() ? ' required="required"' : ''; |
|
358 | - |
|
359 | - return " |
|
340 | + } |
|
341 | + |
|
342 | + |
|
343 | + /** |
|
344 | + * @return string |
|
345 | + * @throws EE_Error |
|
346 | + * @throws ReflectionException |
|
347 | + */ |
|
348 | + protected function ticketCheckboxSelector(): string |
|
349 | + { |
|
350 | + $TKT = $this->ticket->ID(); |
|
351 | + $label = esc_html__('Select this ticket', 'event_espresso'); |
|
352 | + $name = "tkt-slctr-qty-$this->EVT_ID[$TKT]"; |
|
353 | + $class = 'ticket-selector-tbl-qty-slct'; |
|
354 | + $id = "$class-$this->EVT_ID-$this->row"; |
|
355 | + $title = esc_html__('only one of this ticket can be purchased at a time', 'event_espresso'); |
|
356 | + $checked = $this->ticket->required() ? ' checked="checked"' : ''; |
|
357 | + $required = $this->ticket->required() ? ' required="required"' : ''; |
|
358 | + |
|
359 | + return " |
|
360 | 360 | <label class='ee-a11y-screen-reader-text' for='$id' >$label</label> |
361 | 361 | <input type='checkbox' name='$name' id='$id' class='$class' value='1' title='$title'$checked$required/>"; |
362 | - } |
|
363 | - |
|
364 | - |
|
365 | - /** |
|
366 | - * @return string |
|
367 | - * @throws EE_Error |
|
368 | - * @throws ReflectionException |
|
369 | - */ |
|
370 | - protected function ticketQuantitySelector(): string |
|
371 | - { |
|
372 | - $TKT = $this->ticket->ID(); |
|
373 | - $label = esc_html__('Quantity', 'event_espresso'); |
|
374 | - $name = "tkt-slctr-qty-$this->EVT_ID[$TKT]"; |
|
375 | - $class = 'ticket-selector-tbl-qty-slct'; |
|
376 | - $id = "$class-$this->EVT_ID-$this->row"; |
|
377 | - $required = $this->ticket->required() ? ' required="required"' : ''; |
|
378 | - |
|
379 | - $html = "<label class='ee-a11y-screen-reader-text' for='$id' >$label</label>"; |
|
380 | - $html .= "<select name='$name' id='$id' class='$class'$required>"; |
|
381 | - // this ensures that non-required tickets with non-zero MIN QTYs don't HAVE to be purchased |
|
382 | - if ($this->min !== 0 && ! $this->ticket->required()) { |
|
383 | - $html .= "<option value='0'> 0 </option>"; |
|
384 | - } |
|
385 | - // offer ticket quantities from the min to the max |
|
386 | - for ($i = $this->min; $i <= $this->max; $i++) { |
|
387 | - $html .= "<option value='$i'> $i </option>"; |
|
388 | - } |
|
389 | - $html .= "</select>"; |
|
390 | - return $html; |
|
391 | - } |
|
392 | - |
|
393 | - |
|
394 | - /** |
|
395 | - * @return string |
|
396 | - * @throws EE_Error |
|
397 | - * @throws ReflectionException |
|
398 | - */ |
|
399 | - protected function ticketQtyAndIdHiddenInputs(): string |
|
400 | - { |
|
401 | - $html = ''; |
|
402 | - $EVT = $this->EVT_ID; |
|
403 | - $TKT = $this->ticket->ID(); |
|
404 | - // depending on group reg we need to change the format for qty |
|
405 | - if ($this->hidden_input_qty) { |
|
406 | - $html .= "<input type='hidden' name='tkt-slctr-qty-{$EVT}[]' value='0' />"; |
|
407 | - } |
|
408 | - $html .= "<input type='hidden' name='tkt-slctr-ticket-id-{$EVT}[]' value='$TKT' />"; |
|
409 | - return $html; |
|
410 | - } |
|
362 | + } |
|
363 | + |
|
364 | + |
|
365 | + /** |
|
366 | + * @return string |
|
367 | + * @throws EE_Error |
|
368 | + * @throws ReflectionException |
|
369 | + */ |
|
370 | + protected function ticketQuantitySelector(): string |
|
371 | + { |
|
372 | + $TKT = $this->ticket->ID(); |
|
373 | + $label = esc_html__('Quantity', 'event_espresso'); |
|
374 | + $name = "tkt-slctr-qty-$this->EVT_ID[$TKT]"; |
|
375 | + $class = 'ticket-selector-tbl-qty-slct'; |
|
376 | + $id = "$class-$this->EVT_ID-$this->row"; |
|
377 | + $required = $this->ticket->required() ? ' required="required"' : ''; |
|
378 | + |
|
379 | + $html = "<label class='ee-a11y-screen-reader-text' for='$id' >$label</label>"; |
|
380 | + $html .= "<select name='$name' id='$id' class='$class'$required>"; |
|
381 | + // this ensures that non-required tickets with non-zero MIN QTYs don't HAVE to be purchased |
|
382 | + if ($this->min !== 0 && ! $this->ticket->required()) { |
|
383 | + $html .= "<option value='0'> 0 </option>"; |
|
384 | + } |
|
385 | + // offer ticket quantities from the min to the max |
|
386 | + for ($i = $this->min; $i <= $this->max; $i++) { |
|
387 | + $html .= "<option value='$i'> $i </option>"; |
|
388 | + } |
|
389 | + $html .= "</select>"; |
|
390 | + return $html; |
|
391 | + } |
|
392 | + |
|
393 | + |
|
394 | + /** |
|
395 | + * @return string |
|
396 | + * @throws EE_Error |
|
397 | + * @throws ReflectionException |
|
398 | + */ |
|
399 | + protected function ticketQtyAndIdHiddenInputs(): string |
|
400 | + { |
|
401 | + $html = ''; |
|
402 | + $EVT = $this->EVT_ID; |
|
403 | + $TKT = $this->ticket->ID(); |
|
404 | + // depending on group reg we need to change the format for qty |
|
405 | + if ($this->hidden_input_qty) { |
|
406 | + $html .= "<input type='hidden' name='tkt-slctr-qty-{$EVT}[]' value='0' />"; |
|
407 | + } |
|
408 | + $html .= "<input type='hidden' name='tkt-slctr-ticket-id-{$EVT}[]' value='$TKT' />"; |
|
409 | + return $html; |
|
410 | + } |
|
411 | 411 | } |
@@ -158,7 +158,7 @@ discard block |
||
158 | 158 | "tckt-slctr-tbl-tr {$this->status_class}{$this->ticket_datetime_classes} " |
159 | 159 | . espresso_get_object_css_class($this->ticket) |
160 | 160 | ); |
161 | - $filtered_row_content = $this->getFilteredRowContents(); |
|
161 | + $filtered_row_content = $this->getFilteredRowContents(); |
|
162 | 162 | if ($filtered_row_content !== false) { |
163 | 163 | if ($this->max_attendees === 1) { |
164 | 164 | return $ticket_selector_row_html |
@@ -179,7 +179,7 @@ discard block |
||
179 | 179 | '', |
180 | 180 | 'tckt-slctr-tbl-td-qty cntr', |
181 | 181 | '', |
182 | - 'headers="quantity-' . $this->EVT_ID . '"' |
|
182 | + 'headers="quantity-'.$this->EVT_ID.'"' |
|
183 | 183 | ); |
184 | 184 | $this->setTicketStatusDisplay($remaining); |
185 | 185 | if (empty($this->ticket_status_display)) { |
@@ -227,7 +227,7 @@ discard block |
||
227 | 227 | $ticket_min = $this->ticket->min(); |
228 | 228 | // for ticket bundles, set min and max qty the same |
229 | 229 | if ($ticket_min !== 0 && $ticket_min === $this->ticket->max()) { |
230 | - $this->ticket_price *= $ticket_min; |
|
230 | + $this->ticket_price *= $ticket_min; |
|
231 | 231 | $this->ticket_bundle = true; |
232 | 232 | } |
233 | 233 | $this->ticket_price = apply_filters( |
@@ -252,7 +252,7 @@ discard block |
||
252 | 252 | '', |
253 | 253 | 'tckt-slctr-tbl-td-name', |
254 | 254 | '', |
255 | - 'headers="details-' . $this->EVT_ID . '"' |
|
255 | + 'headers="details-'.$this->EVT_ID.'"' |
|
256 | 256 | ); |
257 | 257 | $html .= EEH_HTML::strong($this->ticket->get_pretty('TKT_name')); |
258 | 258 | $html .= $this->ticket_details->getShowHideLinks(); |
@@ -287,7 +287,7 @@ discard block |
||
287 | 287 | '', |
288 | 288 | 'tckt-slctr-tbl-td-price jst-rght', |
289 | 289 | '', |
290 | - 'headers="price-' . $this->EVT_ID . '"' |
|
290 | + 'headers="price-'.$this->EVT_ID.'"' |
|
291 | 291 | ); |
292 | 292 | $html .= EEH_HTML::span( |
293 | 293 | EEH_Template::format_currency($this->ticket_price), |
@@ -20,516 +20,516 @@ |
||
20 | 20 | */ |
21 | 21 | final class EE_Front_Controller |
22 | 22 | { |
23 | - /** |
|
24 | - * @var string |
|
25 | - */ |
|
26 | - private $_template_path; |
|
27 | - |
|
28 | - /** |
|
29 | - * @var string |
|
30 | - */ |
|
31 | - private $_template; |
|
32 | - |
|
33 | - /** |
|
34 | - * @type EE_Registry |
|
35 | - */ |
|
36 | - protected $Registry; |
|
37 | - |
|
38 | - /** |
|
39 | - * @type EE_Request_Handler |
|
40 | - */ |
|
41 | - protected $Request_Handler; |
|
42 | - |
|
43 | - /** |
|
44 | - * @type EE_Module_Request_Router |
|
45 | - */ |
|
46 | - protected $Module_Request_Router; |
|
47 | - |
|
48 | - /** |
|
49 | - * @type CurrentPage |
|
50 | - */ |
|
51 | - protected $current_page; |
|
52 | - |
|
53 | - |
|
54 | - /** |
|
55 | - * class constructor |
|
56 | - * should fire after shortcode, module, addon, or other plugin's default priority init phases have run |
|
57 | - * |
|
58 | - * @access public |
|
59 | - * @param EE_Registry $Registry |
|
60 | - * @param CurrentPage $EspressoPage |
|
61 | - * @param EE_Module_Request_Router $Module_Request_Router |
|
62 | - */ |
|
63 | - public function __construct( |
|
64 | - EE_Registry $Registry, |
|
65 | - CurrentPage $EspressoPage, |
|
66 | - EE_Module_Request_Router $Module_Request_Router |
|
67 | - ) { |
|
68 | - $this->Registry = $Registry; |
|
69 | - $this->current_page = $EspressoPage; |
|
70 | - $this->Module_Request_Router = $Module_Request_Router; |
|
71 | - // load other resources and begin to actually run shortcodes and modules |
|
72 | - // analyse the incoming WP request |
|
73 | - add_action('parse_request', [$this, 'get_request'], 1); |
|
74 | - // process request with module factory |
|
75 | - add_action('pre_get_posts', [$this, 'pre_get_posts']); |
|
76 | - // before headers sent |
|
77 | - add_action('wp', [$this, 'wp'], 5); |
|
78 | - // primarily used to process any content shortcodes |
|
79 | - add_action('template_redirect', [$this, 'templateRedirect'], 999); |
|
80 | - // header |
|
81 | - add_action('wp_head', [$this, 'header_meta_tag'], 5); |
|
82 | - add_action('wp_print_scripts', [$this, 'wp_print_scripts']); |
|
83 | - add_filter('template_include', [$this, 'template_include'], 1); |
|
84 | - // display errors |
|
85 | - add_action('loop_start', [$this, 'display_errors'], 2); |
|
86 | - // the content |
|
87 | - // add_filter( 'the_content', array( $this, 'the_content' ), 5, 1 ); |
|
88 | - // exclude our private cpt comments |
|
89 | - add_filter('comments_clauses', [$this, 'filter_wp_comments']); |
|
90 | - // make sure any ajax requests will respect the url schema |
|
91 | - // when requests are made against admin-ajax.php (http:// or https://) |
|
92 | - add_filter('admin_url', [$this, 'maybe_force_admin_ajax_ssl'], 200); |
|
93 | - // action hook EE |
|
94 | - do_action('AHEE__EE_Front_Controller__construct__done', $this); |
|
95 | - } |
|
96 | - |
|
97 | - |
|
98 | - /** |
|
99 | - * @return EE_Request_Handler |
|
100 | - * @deprecated 4.10.14.p |
|
101 | - */ |
|
102 | - public function Request_Handler() |
|
103 | - { |
|
104 | - if (! $this->Request_Handler instanceof EE_Request_Handler) { |
|
105 | - $this->Request_Handler = LoaderFactory::getLoader()->getShared('EE_Request_Handler'); |
|
106 | - } |
|
107 | - return $this->Request_Handler; |
|
108 | - } |
|
109 | - |
|
110 | - |
|
111 | - /** |
|
112 | - * @return EE_Module_Request_Router |
|
113 | - */ |
|
114 | - public function Module_Request_Router() |
|
115 | - { |
|
116 | - return $this->Module_Request_Router; |
|
117 | - } |
|
118 | - |
|
119 | - |
|
120 | - /** |
|
121 | - * @return LegacyShortcodesManager |
|
122 | - * @deprecated 4.10.14.p |
|
123 | - */ |
|
124 | - public function getLegacyShortcodesManager() |
|
125 | - { |
|
126 | - return EE_Config::getLegacyShortcodesManager(); |
|
127 | - } |
|
128 | - |
|
129 | - |
|
130 | - |
|
131 | - |
|
132 | - |
|
133 | - /*********************************************** INIT ACTION HOOK ***********************************************/ |
|
134 | - /** |
|
135 | - * filter_wp_comments |
|
136 | - * This simply makes sure that any "private" EE CPTs do not have their comments show up in any wp comment |
|
137 | - * widgets/queries done on frontend |
|
138 | - * |
|
139 | - * @param array $clauses array of comment clauses setup by WP_Comment_Query |
|
140 | - * @return array array of comment clauses with modifications. |
|
141 | - * @throws InvalidArgumentException |
|
142 | - * @throws InvalidDataTypeException |
|
143 | - * @throws InvalidInterfaceException |
|
144 | - */ |
|
145 | - public function filter_wp_comments($clauses) |
|
146 | - { |
|
147 | - global $wpdb; |
|
148 | - if (strpos($clauses['join'], $wpdb->posts) !== false) { |
|
149 | - /** @var EventEspresso\core\domain\entities\custom_post_types\CustomPostTypeDefinitions $custom_post_types */ |
|
150 | - $custom_post_types = LoaderFactory::getLoader()->getShared( |
|
151 | - 'EventEspresso\core\domain\entities\custom_post_types\CustomPostTypeDefinitions' |
|
152 | - ); |
|
153 | - $cpts = $custom_post_types->getPrivateCustomPostTypes(); |
|
154 | - foreach ($cpts as $cpt => $details) { |
|
155 | - $clauses['where'] .= $wpdb->prepare(" AND $wpdb->posts.post_type != %s", $cpt); |
|
156 | - } |
|
157 | - } |
|
158 | - return $clauses; |
|
159 | - } |
|
160 | - |
|
161 | - |
|
162 | - /** |
|
163 | - * this just makes sure that if the site is using ssl that we force that for any admin ajax calls from frontend |
|
164 | - * |
|
165 | - * @param string $url incoming url |
|
166 | - * @return string final assembled url |
|
167 | - */ |
|
168 | - public function maybe_force_admin_ajax_ssl($url) |
|
169 | - { |
|
170 | - if (is_ssl() && preg_match('/admin-ajax.php/', $url)) { |
|
171 | - $url = str_replace('http://', 'https://', $url); |
|
172 | - } |
|
173 | - return $url; |
|
174 | - } |
|
175 | - |
|
176 | - |
|
177 | - |
|
178 | - |
|
179 | - |
|
180 | - |
|
181 | - /*********************************************** WP_LOADED ACTION HOOK ***********************************************/ |
|
182 | - |
|
183 | - |
|
184 | - /** |
|
185 | - * wp_loaded - should fire after shortcode, module, addon, or other plugin's have been registered and their |
|
186 | - * default priority init phases have run |
|
187 | - * |
|
188 | - * @access public |
|
189 | - * @return void |
|
190 | - */ |
|
191 | - public function wp_loaded() |
|
192 | - { |
|
193 | - } |
|
194 | - |
|
195 | - |
|
196 | - |
|
197 | - |
|
198 | - |
|
199 | - /*********************************************** PARSE_REQUEST HOOK ***********************************************/ |
|
200 | - /** |
|
201 | - * _get_request |
|
202 | - * |
|
203 | - * @access public |
|
204 | - * @param WP $WP |
|
205 | - * @return void |
|
206 | - */ |
|
207 | - public function get_request(WP $WP) |
|
208 | - { |
|
209 | - do_action('AHEE__EE_Front_Controller__get_request__start'); |
|
210 | - $this->current_page->parseQueryVars($WP); |
|
211 | - do_action('AHEE__EE_Front_Controller__get_request__complete'); |
|
212 | - remove_action('parse_request', [$this, 'get_request'], 1); |
|
213 | - } |
|
214 | - |
|
215 | - |
|
216 | - /** |
|
217 | - * pre_get_posts - basically a module factory for instantiating modules and selecting the final view template |
|
218 | - * |
|
219 | - * @access public |
|
220 | - * @param WP_Query $WP_Query |
|
221 | - * @return void |
|
222 | - * @throws EE_Error |
|
223 | - * @throws ReflectionException |
|
224 | - */ |
|
225 | - public function pre_get_posts($WP_Query) |
|
226 | - { |
|
227 | - // only load Module_Request_Router if this is the main query |
|
228 | - if ( |
|
229 | - $this->Module_Request_Router instanceof EE_Module_Request_Router |
|
230 | - && $WP_Query->is_main_query() |
|
231 | - ) { |
|
232 | - // cycle thru module routes |
|
233 | - while ($route = $this->Module_Request_Router->get_route($WP_Query)) { |
|
234 | - // determine module and method for route |
|
235 | - $module = $this->Module_Request_Router->resolve_route($route[0], $route[1]); |
|
236 | - if ($module instanceof EED_Module) { |
|
237 | - // get registered view for route |
|
238 | - $this->_template_path = $this->Module_Request_Router->get_view($route); |
|
239 | - // grab module name |
|
240 | - $module_name = $module->module_name(); |
|
241 | - // map the module to the module objects |
|
242 | - $this->Registry->modules->{$module_name} = $module; |
|
243 | - } |
|
244 | - } |
|
245 | - } |
|
246 | - } |
|
247 | - |
|
248 | - |
|
249 | - |
|
250 | - |
|
251 | - |
|
252 | - /*********************************************** WP HOOK ***********************************************/ |
|
253 | - |
|
254 | - |
|
255 | - /** |
|
256 | - * wp - basically last chance to do stuff before headers sent |
|
257 | - * |
|
258 | - * @access public |
|
259 | - * @return void |
|
260 | - */ |
|
261 | - public function wp() |
|
262 | - { |
|
263 | - AriaLiveAnnouncer::setHooks(); |
|
264 | - } |
|
265 | - |
|
266 | - |
|
267 | - |
|
268 | - /*********************** GET_HEADER && WP_HEAD HOOK ***********************/ |
|
269 | - |
|
270 | - |
|
271 | - /** |
|
272 | - * callback for the "template_redirect" hook point |
|
273 | - * checks sidebars for EE widgets |
|
274 | - * loads resources and assets accordingly |
|
275 | - * |
|
276 | - * @return void |
|
277 | - */ |
|
278 | - public function templateRedirect() |
|
279 | - { |
|
280 | - global $wp_query; |
|
281 | - if (empty($wp_query->posts)) { |
|
282 | - return; |
|
283 | - } |
|
284 | - // if we already know this is an espresso page, then load assets |
|
285 | - $load_assets = $this->current_page->isEspressoPage(); |
|
286 | - // if we are already loading assets then just move along, otherwise check for widgets |
|
287 | - $load_assets = $load_assets || $this->espresso_widgets_in_active_sidebars(); |
|
288 | - if ($load_assets) { |
|
289 | - add_action('wp_enqueue_scripts', [$this, 'enqueueStyle']); |
|
290 | - add_action('wp_enqueue_scripts', [$this, 'enqueueScripts']); |
|
291 | - } |
|
292 | - |
|
293 | - if (is_singular(EspressoPostType::EVENTS)) { |
|
294 | - new FilterNextPreviousEventPostQuery(); |
|
295 | - } |
|
296 | - } |
|
297 | - |
|
298 | - |
|
299 | - /** |
|
300 | - * builds list of active widgets then scans active sidebars looking for them |
|
301 | - * returns true is an EE widget is found in an active sidebar |
|
302 | - * Please Note: this does NOT mean that the sidebar or widget |
|
303 | - * is actually in use in a given template, as that is unfortunately not known |
|
304 | - * until a sidebar and it's widgets are actually loaded |
|
305 | - * |
|
306 | - * @return boolean |
|
307 | - */ |
|
308 | - private function espresso_widgets_in_active_sidebars() |
|
309 | - { |
|
310 | - $espresso_widgets = []; |
|
311 | - foreach ($this->Registry->widgets as $widget_class => $widget) { |
|
312 | - $id_base = EspressoWidget::getIdBase($widget_class); |
|
313 | - if (is_active_widget(false, false, $id_base)) { |
|
314 | - $espresso_widgets[] = $id_base; |
|
315 | - } |
|
316 | - } |
|
317 | - $all_sidebar_widgets = wp_get_sidebars_widgets(); |
|
318 | - foreach ($all_sidebar_widgets as $sidebar_widgets) { |
|
319 | - if (is_array($sidebar_widgets) && ! empty($sidebar_widgets)) { |
|
320 | - foreach ($sidebar_widgets as $sidebar_widget) { |
|
321 | - foreach ($espresso_widgets as $espresso_widget) { |
|
322 | - if (strpos($sidebar_widget, $espresso_widget) !== false) { |
|
323 | - return true; |
|
324 | - } |
|
325 | - } |
|
326 | - } |
|
327 | - } |
|
328 | - } |
|
329 | - return false; |
|
330 | - } |
|
331 | - |
|
332 | - |
|
333 | - /** |
|
334 | - * header_meta_tag |
|
335 | - * |
|
336 | - * @access public |
|
337 | - * @return void |
|
338 | - */ |
|
339 | - public function header_meta_tag() |
|
340 | - { |
|
341 | - print( |
|
342 | - apply_filters( |
|
343 | - 'FHEE__EE_Front_Controller__header_meta_tag', |
|
344 | - '<meta name="generator" content="Event Espresso Version ' . EVENT_ESPRESSO_VERSION . "\" />\n" |
|
345 | - ) |
|
346 | - ); |
|
347 | - |
|
348 | - // let's exclude all event type taxonomy term archive pages from search engine indexing |
|
349 | - // @see https://events.codebasehq.com/projects/event-espresso/tickets/10249 |
|
350 | - // also exclude all critical pages from indexing |
|
351 | - if ( |
|
352 | - ( |
|
353 | - is_tax('espresso_event_type') |
|
354 | - && get_option('blog_public') !== '0' |
|
355 | - ) |
|
356 | - || is_page(EE_Registry::instance()->CFG->core->get_critical_pages_array()) |
|
357 | - ) { |
|
358 | - print( |
|
359 | - apply_filters( |
|
360 | - 'FHEE__EE_Front_Controller__header_meta_tag__noindex_for_event_type', |
|
361 | - '<meta name="robots" content="noindex,follow" />' . "\n" |
|
362 | - ) |
|
363 | - ); |
|
364 | - } |
|
365 | - } |
|
366 | - |
|
367 | - |
|
368 | - /** |
|
369 | - * wp_print_scripts |
|
370 | - * |
|
371 | - * @return void |
|
372 | - * @throws EE_Error |
|
373 | - */ |
|
374 | - public function wp_print_scripts() |
|
375 | - { |
|
376 | - global $post; |
|
377 | - if ( |
|
378 | - isset($post->EE_Event) |
|
379 | - && $post->EE_Event instanceof EE_Event |
|
380 | - && get_post_type() === EspressoPostType::EVENTS |
|
381 | - && is_singular() |
|
382 | - ) { |
|
383 | - EEH_Schema::add_json_linked_data_for_event($post->EE_Event); |
|
384 | - } |
|
385 | - } |
|
386 | - |
|
387 | - |
|
388 | - public function enqueueStyle() |
|
389 | - { |
|
390 | - wp_enqueue_style('espresso_default'); |
|
391 | - wp_enqueue_style('espresso_custom_css'); |
|
392 | - } |
|
393 | - |
|
394 | - |
|
395 | - /*********************************************** WP_FOOTER ***********************************************/ |
|
396 | - |
|
397 | - |
|
398 | - public function enqueueScripts() |
|
399 | - { |
|
400 | - wp_enqueue_script('espresso_core'); |
|
401 | - } |
|
402 | - |
|
403 | - |
|
404 | - /** |
|
405 | - * @param WP_Query $query |
|
406 | - * @return void |
|
407 | - * @throws DomainException |
|
408 | - */ |
|
409 | - public function display_errors(WP_Query $query) |
|
410 | - { |
|
411 | - if (! $query->is_main_query()) { |
|
412 | - return; |
|
413 | - } |
|
414 | - static $shown_already = false; |
|
415 | - do_action('AHEE__EE_Front_Controller__display_errors__begin'); |
|
416 | - if ( |
|
417 | - ! $shown_already |
|
418 | - && apply_filters('FHEE__EE_Front_Controller__display_errors', true) |
|
419 | - && is_main_query() |
|
420 | - && ! is_feed() |
|
421 | - && in_the_loop() |
|
422 | - && $this->current_page->isEspressoPage() |
|
423 | - ) { |
|
424 | - $shown_already = true; |
|
425 | - if (did_action('wp_head')) { |
|
426 | - echo wp_kses($this->printNotices(), AllowedTags::getAllowedTags()); |
|
427 | - } else { |
|
428 | - // block enabled themes run their query loop before headers are sent |
|
429 | - // so we need to add our notices onto the beginning of the content |
|
430 | - add_filter('the_content', [$this, 'prependNotices'], 1); |
|
431 | - } |
|
432 | - } |
|
433 | - do_action('AHEE__EE_Front_Controller__display_errors__end'); |
|
434 | - } |
|
435 | - |
|
436 | - |
|
437 | - /** |
|
438 | - * @param string $the_content |
|
439 | - * @return string |
|
440 | - * @since 4.10.30.p |
|
441 | - */ |
|
442 | - public function prependNotices($the_content) |
|
443 | - { |
|
444 | - $notices = $this->printNotices(); |
|
445 | - return $notices ? $notices . $the_content : $the_content; |
|
446 | - } |
|
447 | - |
|
448 | - |
|
449 | - /** |
|
450 | - * @return false|string |
|
451 | - * @since 4.10.30.p |
|
452 | - */ |
|
453 | - public function printNotices() |
|
454 | - { |
|
455 | - ob_start(); |
|
456 | - echo wp_kses(EE_Error::get_notices(), AllowedTags::getWithFormTags()); |
|
457 | - EEH_Template::display_template(EE_TEMPLATES . 'espresso-ajax-notices.template.php'); |
|
458 | - return ob_get_clean(); |
|
459 | - } |
|
460 | - |
|
461 | - |
|
462 | - |
|
463 | - /*********************************************** UTILITIES ***********************************************/ |
|
464 | - |
|
465 | - |
|
466 | - /** |
|
467 | - * @param bool|string $template_include_path |
|
468 | - * @return string |
|
469 | - * @throws EE_Error |
|
470 | - * @throws ReflectionException |
|
471 | - */ |
|
472 | - public function template_include($template_include_path = '') |
|
473 | - { |
|
474 | - if ($this->current_page->isEspressoPage()) { |
|
475 | - // despite all helpers having autoloaders set, we need to manually load the template loader |
|
476 | - // because there are some side effects in that class for triggering template tag functions |
|
477 | - $this->Registry->load_helper('EEH_Template'); |
|
478 | - $this->_template_path = ! empty($this->_template_path) |
|
479 | - ? basename($this->_template_path) |
|
480 | - : basename((string) $template_include_path); |
|
481 | - $template_path = EEH_Template::locate_template($this->_template_path, [], false); |
|
482 | - $this->_template_path = ! empty($template_path) ? $template_path : $template_include_path; |
|
483 | - $this->_template = basename($this->_template_path); |
|
484 | - return $this->_template_path; |
|
485 | - } |
|
486 | - return $template_include_path; |
|
487 | - } |
|
488 | - |
|
489 | - |
|
490 | - /** |
|
491 | - * @param bool $with_path |
|
492 | - * @return string |
|
493 | - */ |
|
494 | - public function get_selected_template($with_path = false) |
|
495 | - { |
|
496 | - return $with_path ? $this->_template_path : $this->_template; |
|
497 | - } |
|
498 | - |
|
499 | - /** |
|
500 | - * @param string $shortcode_class |
|
501 | - * @param WP $wp |
|
502 | - * @throws ReflectionException |
|
503 | - * @deprecated 4.9.26 |
|
504 | - */ |
|
505 | - public function initialize_shortcode($shortcode_class = '', WP $wp = null) |
|
506 | - { |
|
507 | - EE_Error::doing_it_wrong( |
|
508 | - __METHOD__, |
|
509 | - esc_html__( |
|
510 | - 'Usage is deprecated. Please use \EventEspresso\core\services\shortcodes\LegacyShortcodesManager::initializeShortcode() instead.', |
|
511 | - 'event_espresso' |
|
512 | - ), |
|
513 | - '4.9.26' |
|
514 | - ); |
|
515 | - $this->getLegacyShortcodesManager()->initializeShortcode($shortcode_class, $wp); |
|
516 | - } |
|
517 | - |
|
518 | - |
|
519 | - /** |
|
520 | - * @return void |
|
521 | - * @deprecated 4.9.57.p |
|
522 | - */ |
|
523 | - public function loadPersistentAdminNoticeManager() |
|
524 | - { |
|
525 | - } |
|
526 | - |
|
527 | - |
|
528 | - /** |
|
529 | - * @return void |
|
530 | - * @deprecated 4.9.64.p |
|
531 | - */ |
|
532 | - public function employ_CPT_Strategy() |
|
533 | - { |
|
534 | - } |
|
23 | + /** |
|
24 | + * @var string |
|
25 | + */ |
|
26 | + private $_template_path; |
|
27 | + |
|
28 | + /** |
|
29 | + * @var string |
|
30 | + */ |
|
31 | + private $_template; |
|
32 | + |
|
33 | + /** |
|
34 | + * @type EE_Registry |
|
35 | + */ |
|
36 | + protected $Registry; |
|
37 | + |
|
38 | + /** |
|
39 | + * @type EE_Request_Handler |
|
40 | + */ |
|
41 | + protected $Request_Handler; |
|
42 | + |
|
43 | + /** |
|
44 | + * @type EE_Module_Request_Router |
|
45 | + */ |
|
46 | + protected $Module_Request_Router; |
|
47 | + |
|
48 | + /** |
|
49 | + * @type CurrentPage |
|
50 | + */ |
|
51 | + protected $current_page; |
|
52 | + |
|
53 | + |
|
54 | + /** |
|
55 | + * class constructor |
|
56 | + * should fire after shortcode, module, addon, or other plugin's default priority init phases have run |
|
57 | + * |
|
58 | + * @access public |
|
59 | + * @param EE_Registry $Registry |
|
60 | + * @param CurrentPage $EspressoPage |
|
61 | + * @param EE_Module_Request_Router $Module_Request_Router |
|
62 | + */ |
|
63 | + public function __construct( |
|
64 | + EE_Registry $Registry, |
|
65 | + CurrentPage $EspressoPage, |
|
66 | + EE_Module_Request_Router $Module_Request_Router |
|
67 | + ) { |
|
68 | + $this->Registry = $Registry; |
|
69 | + $this->current_page = $EspressoPage; |
|
70 | + $this->Module_Request_Router = $Module_Request_Router; |
|
71 | + // load other resources and begin to actually run shortcodes and modules |
|
72 | + // analyse the incoming WP request |
|
73 | + add_action('parse_request', [$this, 'get_request'], 1); |
|
74 | + // process request with module factory |
|
75 | + add_action('pre_get_posts', [$this, 'pre_get_posts']); |
|
76 | + // before headers sent |
|
77 | + add_action('wp', [$this, 'wp'], 5); |
|
78 | + // primarily used to process any content shortcodes |
|
79 | + add_action('template_redirect', [$this, 'templateRedirect'], 999); |
|
80 | + // header |
|
81 | + add_action('wp_head', [$this, 'header_meta_tag'], 5); |
|
82 | + add_action('wp_print_scripts', [$this, 'wp_print_scripts']); |
|
83 | + add_filter('template_include', [$this, 'template_include'], 1); |
|
84 | + // display errors |
|
85 | + add_action('loop_start', [$this, 'display_errors'], 2); |
|
86 | + // the content |
|
87 | + // add_filter( 'the_content', array( $this, 'the_content' ), 5, 1 ); |
|
88 | + // exclude our private cpt comments |
|
89 | + add_filter('comments_clauses', [$this, 'filter_wp_comments']); |
|
90 | + // make sure any ajax requests will respect the url schema |
|
91 | + // when requests are made against admin-ajax.php (http:// or https://) |
|
92 | + add_filter('admin_url', [$this, 'maybe_force_admin_ajax_ssl'], 200); |
|
93 | + // action hook EE |
|
94 | + do_action('AHEE__EE_Front_Controller__construct__done', $this); |
|
95 | + } |
|
96 | + |
|
97 | + |
|
98 | + /** |
|
99 | + * @return EE_Request_Handler |
|
100 | + * @deprecated 4.10.14.p |
|
101 | + */ |
|
102 | + public function Request_Handler() |
|
103 | + { |
|
104 | + if (! $this->Request_Handler instanceof EE_Request_Handler) { |
|
105 | + $this->Request_Handler = LoaderFactory::getLoader()->getShared('EE_Request_Handler'); |
|
106 | + } |
|
107 | + return $this->Request_Handler; |
|
108 | + } |
|
109 | + |
|
110 | + |
|
111 | + /** |
|
112 | + * @return EE_Module_Request_Router |
|
113 | + */ |
|
114 | + public function Module_Request_Router() |
|
115 | + { |
|
116 | + return $this->Module_Request_Router; |
|
117 | + } |
|
118 | + |
|
119 | + |
|
120 | + /** |
|
121 | + * @return LegacyShortcodesManager |
|
122 | + * @deprecated 4.10.14.p |
|
123 | + */ |
|
124 | + public function getLegacyShortcodesManager() |
|
125 | + { |
|
126 | + return EE_Config::getLegacyShortcodesManager(); |
|
127 | + } |
|
128 | + |
|
129 | + |
|
130 | + |
|
131 | + |
|
132 | + |
|
133 | + /*********************************************** INIT ACTION HOOK ***********************************************/ |
|
134 | + /** |
|
135 | + * filter_wp_comments |
|
136 | + * This simply makes sure that any "private" EE CPTs do not have their comments show up in any wp comment |
|
137 | + * widgets/queries done on frontend |
|
138 | + * |
|
139 | + * @param array $clauses array of comment clauses setup by WP_Comment_Query |
|
140 | + * @return array array of comment clauses with modifications. |
|
141 | + * @throws InvalidArgumentException |
|
142 | + * @throws InvalidDataTypeException |
|
143 | + * @throws InvalidInterfaceException |
|
144 | + */ |
|
145 | + public function filter_wp_comments($clauses) |
|
146 | + { |
|
147 | + global $wpdb; |
|
148 | + if (strpos($clauses['join'], $wpdb->posts) !== false) { |
|
149 | + /** @var EventEspresso\core\domain\entities\custom_post_types\CustomPostTypeDefinitions $custom_post_types */ |
|
150 | + $custom_post_types = LoaderFactory::getLoader()->getShared( |
|
151 | + 'EventEspresso\core\domain\entities\custom_post_types\CustomPostTypeDefinitions' |
|
152 | + ); |
|
153 | + $cpts = $custom_post_types->getPrivateCustomPostTypes(); |
|
154 | + foreach ($cpts as $cpt => $details) { |
|
155 | + $clauses['where'] .= $wpdb->prepare(" AND $wpdb->posts.post_type != %s", $cpt); |
|
156 | + } |
|
157 | + } |
|
158 | + return $clauses; |
|
159 | + } |
|
160 | + |
|
161 | + |
|
162 | + /** |
|
163 | + * this just makes sure that if the site is using ssl that we force that for any admin ajax calls from frontend |
|
164 | + * |
|
165 | + * @param string $url incoming url |
|
166 | + * @return string final assembled url |
|
167 | + */ |
|
168 | + public function maybe_force_admin_ajax_ssl($url) |
|
169 | + { |
|
170 | + if (is_ssl() && preg_match('/admin-ajax.php/', $url)) { |
|
171 | + $url = str_replace('http://', 'https://', $url); |
|
172 | + } |
|
173 | + return $url; |
|
174 | + } |
|
175 | + |
|
176 | + |
|
177 | + |
|
178 | + |
|
179 | + |
|
180 | + |
|
181 | + /*********************************************** WP_LOADED ACTION HOOK ***********************************************/ |
|
182 | + |
|
183 | + |
|
184 | + /** |
|
185 | + * wp_loaded - should fire after shortcode, module, addon, or other plugin's have been registered and their |
|
186 | + * default priority init phases have run |
|
187 | + * |
|
188 | + * @access public |
|
189 | + * @return void |
|
190 | + */ |
|
191 | + public function wp_loaded() |
|
192 | + { |
|
193 | + } |
|
194 | + |
|
195 | + |
|
196 | + |
|
197 | + |
|
198 | + |
|
199 | + /*********************************************** PARSE_REQUEST HOOK ***********************************************/ |
|
200 | + /** |
|
201 | + * _get_request |
|
202 | + * |
|
203 | + * @access public |
|
204 | + * @param WP $WP |
|
205 | + * @return void |
|
206 | + */ |
|
207 | + public function get_request(WP $WP) |
|
208 | + { |
|
209 | + do_action('AHEE__EE_Front_Controller__get_request__start'); |
|
210 | + $this->current_page->parseQueryVars($WP); |
|
211 | + do_action('AHEE__EE_Front_Controller__get_request__complete'); |
|
212 | + remove_action('parse_request', [$this, 'get_request'], 1); |
|
213 | + } |
|
214 | + |
|
215 | + |
|
216 | + /** |
|
217 | + * pre_get_posts - basically a module factory for instantiating modules and selecting the final view template |
|
218 | + * |
|
219 | + * @access public |
|
220 | + * @param WP_Query $WP_Query |
|
221 | + * @return void |
|
222 | + * @throws EE_Error |
|
223 | + * @throws ReflectionException |
|
224 | + */ |
|
225 | + public function pre_get_posts($WP_Query) |
|
226 | + { |
|
227 | + // only load Module_Request_Router if this is the main query |
|
228 | + if ( |
|
229 | + $this->Module_Request_Router instanceof EE_Module_Request_Router |
|
230 | + && $WP_Query->is_main_query() |
|
231 | + ) { |
|
232 | + // cycle thru module routes |
|
233 | + while ($route = $this->Module_Request_Router->get_route($WP_Query)) { |
|
234 | + // determine module and method for route |
|
235 | + $module = $this->Module_Request_Router->resolve_route($route[0], $route[1]); |
|
236 | + if ($module instanceof EED_Module) { |
|
237 | + // get registered view for route |
|
238 | + $this->_template_path = $this->Module_Request_Router->get_view($route); |
|
239 | + // grab module name |
|
240 | + $module_name = $module->module_name(); |
|
241 | + // map the module to the module objects |
|
242 | + $this->Registry->modules->{$module_name} = $module; |
|
243 | + } |
|
244 | + } |
|
245 | + } |
|
246 | + } |
|
247 | + |
|
248 | + |
|
249 | + |
|
250 | + |
|
251 | + |
|
252 | + /*********************************************** WP HOOK ***********************************************/ |
|
253 | + |
|
254 | + |
|
255 | + /** |
|
256 | + * wp - basically last chance to do stuff before headers sent |
|
257 | + * |
|
258 | + * @access public |
|
259 | + * @return void |
|
260 | + */ |
|
261 | + public function wp() |
|
262 | + { |
|
263 | + AriaLiveAnnouncer::setHooks(); |
|
264 | + } |
|
265 | + |
|
266 | + |
|
267 | + |
|
268 | + /*********************** GET_HEADER && WP_HEAD HOOK ***********************/ |
|
269 | + |
|
270 | + |
|
271 | + /** |
|
272 | + * callback for the "template_redirect" hook point |
|
273 | + * checks sidebars for EE widgets |
|
274 | + * loads resources and assets accordingly |
|
275 | + * |
|
276 | + * @return void |
|
277 | + */ |
|
278 | + public function templateRedirect() |
|
279 | + { |
|
280 | + global $wp_query; |
|
281 | + if (empty($wp_query->posts)) { |
|
282 | + return; |
|
283 | + } |
|
284 | + // if we already know this is an espresso page, then load assets |
|
285 | + $load_assets = $this->current_page->isEspressoPage(); |
|
286 | + // if we are already loading assets then just move along, otherwise check for widgets |
|
287 | + $load_assets = $load_assets || $this->espresso_widgets_in_active_sidebars(); |
|
288 | + if ($load_assets) { |
|
289 | + add_action('wp_enqueue_scripts', [$this, 'enqueueStyle']); |
|
290 | + add_action('wp_enqueue_scripts', [$this, 'enqueueScripts']); |
|
291 | + } |
|
292 | + |
|
293 | + if (is_singular(EspressoPostType::EVENTS)) { |
|
294 | + new FilterNextPreviousEventPostQuery(); |
|
295 | + } |
|
296 | + } |
|
297 | + |
|
298 | + |
|
299 | + /** |
|
300 | + * builds list of active widgets then scans active sidebars looking for them |
|
301 | + * returns true is an EE widget is found in an active sidebar |
|
302 | + * Please Note: this does NOT mean that the sidebar or widget |
|
303 | + * is actually in use in a given template, as that is unfortunately not known |
|
304 | + * until a sidebar and it's widgets are actually loaded |
|
305 | + * |
|
306 | + * @return boolean |
|
307 | + */ |
|
308 | + private function espresso_widgets_in_active_sidebars() |
|
309 | + { |
|
310 | + $espresso_widgets = []; |
|
311 | + foreach ($this->Registry->widgets as $widget_class => $widget) { |
|
312 | + $id_base = EspressoWidget::getIdBase($widget_class); |
|
313 | + if (is_active_widget(false, false, $id_base)) { |
|
314 | + $espresso_widgets[] = $id_base; |
|
315 | + } |
|
316 | + } |
|
317 | + $all_sidebar_widgets = wp_get_sidebars_widgets(); |
|
318 | + foreach ($all_sidebar_widgets as $sidebar_widgets) { |
|
319 | + if (is_array($sidebar_widgets) && ! empty($sidebar_widgets)) { |
|
320 | + foreach ($sidebar_widgets as $sidebar_widget) { |
|
321 | + foreach ($espresso_widgets as $espresso_widget) { |
|
322 | + if (strpos($sidebar_widget, $espresso_widget) !== false) { |
|
323 | + return true; |
|
324 | + } |
|
325 | + } |
|
326 | + } |
|
327 | + } |
|
328 | + } |
|
329 | + return false; |
|
330 | + } |
|
331 | + |
|
332 | + |
|
333 | + /** |
|
334 | + * header_meta_tag |
|
335 | + * |
|
336 | + * @access public |
|
337 | + * @return void |
|
338 | + */ |
|
339 | + public function header_meta_tag() |
|
340 | + { |
|
341 | + print( |
|
342 | + apply_filters( |
|
343 | + 'FHEE__EE_Front_Controller__header_meta_tag', |
|
344 | + '<meta name="generator" content="Event Espresso Version ' . EVENT_ESPRESSO_VERSION . "\" />\n" |
|
345 | + ) |
|
346 | + ); |
|
347 | + |
|
348 | + // let's exclude all event type taxonomy term archive pages from search engine indexing |
|
349 | + // @see https://events.codebasehq.com/projects/event-espresso/tickets/10249 |
|
350 | + // also exclude all critical pages from indexing |
|
351 | + if ( |
|
352 | + ( |
|
353 | + is_tax('espresso_event_type') |
|
354 | + && get_option('blog_public') !== '0' |
|
355 | + ) |
|
356 | + || is_page(EE_Registry::instance()->CFG->core->get_critical_pages_array()) |
|
357 | + ) { |
|
358 | + print( |
|
359 | + apply_filters( |
|
360 | + 'FHEE__EE_Front_Controller__header_meta_tag__noindex_for_event_type', |
|
361 | + '<meta name="robots" content="noindex,follow" />' . "\n" |
|
362 | + ) |
|
363 | + ); |
|
364 | + } |
|
365 | + } |
|
366 | + |
|
367 | + |
|
368 | + /** |
|
369 | + * wp_print_scripts |
|
370 | + * |
|
371 | + * @return void |
|
372 | + * @throws EE_Error |
|
373 | + */ |
|
374 | + public function wp_print_scripts() |
|
375 | + { |
|
376 | + global $post; |
|
377 | + if ( |
|
378 | + isset($post->EE_Event) |
|
379 | + && $post->EE_Event instanceof EE_Event |
|
380 | + && get_post_type() === EspressoPostType::EVENTS |
|
381 | + && is_singular() |
|
382 | + ) { |
|
383 | + EEH_Schema::add_json_linked_data_for_event($post->EE_Event); |
|
384 | + } |
|
385 | + } |
|
386 | + |
|
387 | + |
|
388 | + public function enqueueStyle() |
|
389 | + { |
|
390 | + wp_enqueue_style('espresso_default'); |
|
391 | + wp_enqueue_style('espresso_custom_css'); |
|
392 | + } |
|
393 | + |
|
394 | + |
|
395 | + /*********************************************** WP_FOOTER ***********************************************/ |
|
396 | + |
|
397 | + |
|
398 | + public function enqueueScripts() |
|
399 | + { |
|
400 | + wp_enqueue_script('espresso_core'); |
|
401 | + } |
|
402 | + |
|
403 | + |
|
404 | + /** |
|
405 | + * @param WP_Query $query |
|
406 | + * @return void |
|
407 | + * @throws DomainException |
|
408 | + */ |
|
409 | + public function display_errors(WP_Query $query) |
|
410 | + { |
|
411 | + if (! $query->is_main_query()) { |
|
412 | + return; |
|
413 | + } |
|
414 | + static $shown_already = false; |
|
415 | + do_action('AHEE__EE_Front_Controller__display_errors__begin'); |
|
416 | + if ( |
|
417 | + ! $shown_already |
|
418 | + && apply_filters('FHEE__EE_Front_Controller__display_errors', true) |
|
419 | + && is_main_query() |
|
420 | + && ! is_feed() |
|
421 | + && in_the_loop() |
|
422 | + && $this->current_page->isEspressoPage() |
|
423 | + ) { |
|
424 | + $shown_already = true; |
|
425 | + if (did_action('wp_head')) { |
|
426 | + echo wp_kses($this->printNotices(), AllowedTags::getAllowedTags()); |
|
427 | + } else { |
|
428 | + // block enabled themes run their query loop before headers are sent |
|
429 | + // so we need to add our notices onto the beginning of the content |
|
430 | + add_filter('the_content', [$this, 'prependNotices'], 1); |
|
431 | + } |
|
432 | + } |
|
433 | + do_action('AHEE__EE_Front_Controller__display_errors__end'); |
|
434 | + } |
|
435 | + |
|
436 | + |
|
437 | + /** |
|
438 | + * @param string $the_content |
|
439 | + * @return string |
|
440 | + * @since 4.10.30.p |
|
441 | + */ |
|
442 | + public function prependNotices($the_content) |
|
443 | + { |
|
444 | + $notices = $this->printNotices(); |
|
445 | + return $notices ? $notices . $the_content : $the_content; |
|
446 | + } |
|
447 | + |
|
448 | + |
|
449 | + /** |
|
450 | + * @return false|string |
|
451 | + * @since 4.10.30.p |
|
452 | + */ |
|
453 | + public function printNotices() |
|
454 | + { |
|
455 | + ob_start(); |
|
456 | + echo wp_kses(EE_Error::get_notices(), AllowedTags::getWithFormTags()); |
|
457 | + EEH_Template::display_template(EE_TEMPLATES . 'espresso-ajax-notices.template.php'); |
|
458 | + return ob_get_clean(); |
|
459 | + } |
|
460 | + |
|
461 | + |
|
462 | + |
|
463 | + /*********************************************** UTILITIES ***********************************************/ |
|
464 | + |
|
465 | + |
|
466 | + /** |
|
467 | + * @param bool|string $template_include_path |
|
468 | + * @return string |
|
469 | + * @throws EE_Error |
|
470 | + * @throws ReflectionException |
|
471 | + */ |
|
472 | + public function template_include($template_include_path = '') |
|
473 | + { |
|
474 | + if ($this->current_page->isEspressoPage()) { |
|
475 | + // despite all helpers having autoloaders set, we need to manually load the template loader |
|
476 | + // because there are some side effects in that class for triggering template tag functions |
|
477 | + $this->Registry->load_helper('EEH_Template'); |
|
478 | + $this->_template_path = ! empty($this->_template_path) |
|
479 | + ? basename($this->_template_path) |
|
480 | + : basename((string) $template_include_path); |
|
481 | + $template_path = EEH_Template::locate_template($this->_template_path, [], false); |
|
482 | + $this->_template_path = ! empty($template_path) ? $template_path : $template_include_path; |
|
483 | + $this->_template = basename($this->_template_path); |
|
484 | + return $this->_template_path; |
|
485 | + } |
|
486 | + return $template_include_path; |
|
487 | + } |
|
488 | + |
|
489 | + |
|
490 | + /** |
|
491 | + * @param bool $with_path |
|
492 | + * @return string |
|
493 | + */ |
|
494 | + public function get_selected_template($with_path = false) |
|
495 | + { |
|
496 | + return $with_path ? $this->_template_path : $this->_template; |
|
497 | + } |
|
498 | + |
|
499 | + /** |
|
500 | + * @param string $shortcode_class |
|
501 | + * @param WP $wp |
|
502 | + * @throws ReflectionException |
|
503 | + * @deprecated 4.9.26 |
|
504 | + */ |
|
505 | + public function initialize_shortcode($shortcode_class = '', WP $wp = null) |
|
506 | + { |
|
507 | + EE_Error::doing_it_wrong( |
|
508 | + __METHOD__, |
|
509 | + esc_html__( |
|
510 | + 'Usage is deprecated. Please use \EventEspresso\core\services\shortcodes\LegacyShortcodesManager::initializeShortcode() instead.', |
|
511 | + 'event_espresso' |
|
512 | + ), |
|
513 | + '4.9.26' |
|
514 | + ); |
|
515 | + $this->getLegacyShortcodesManager()->initializeShortcode($shortcode_class, $wp); |
|
516 | + } |
|
517 | + |
|
518 | + |
|
519 | + /** |
|
520 | + * @return void |
|
521 | + * @deprecated 4.9.57.p |
|
522 | + */ |
|
523 | + public function loadPersistentAdminNoticeManager() |
|
524 | + { |
|
525 | + } |
|
526 | + |
|
527 | + |
|
528 | + /** |
|
529 | + * @return void |
|
530 | + * @deprecated 4.9.64.p |
|
531 | + */ |
|
532 | + public function employ_CPT_Strategy() |
|
533 | + { |
|
534 | + } |
|
535 | 535 | } |
@@ -29,512 +29,512 @@ |
||
29 | 29 | */ |
30 | 30 | class SessionStartHandler |
31 | 31 | { |
32 | - const OPTION_NAME_SESSION_SAVE_HANDLER_STATUS = 'ee_session_save_handler_status'; |
|
33 | - |
|
34 | - const REQUEST_PARAM_RETRY_SESSION = 'ee_retry_session'; |
|
35 | - |
|
36 | - const SESSION_SAVE_HANDLER_STATUS_FAILED = 'session_save_handler_failed'; |
|
37 | - |
|
38 | - const SESSION_SAVE_HANDLER_STATUS_SUCCESS = 'session_save_handler_success'; |
|
39 | - |
|
40 | - const SESSION_SAVE_HANDLER_STATUS_UNKNOWN = 'session_save_handler_untested'; |
|
41 | - |
|
42 | - |
|
43 | - protected RequestInterface $request; |
|
44 | - |
|
45 | - /** |
|
46 | - * @var string |
|
47 | - * @since 5.0.47 |
|
48 | - */ |
|
49 | - private string $open_basedir = ''; |
|
50 | - |
|
51 | - /** |
|
52 | - * @var string |
|
53 | - * @since 5.0.47 |
|
54 | - */ |
|
55 | - private string $save_handler = ''; |
|
56 | - |
|
57 | - /** |
|
58 | - * @var string |
|
59 | - * @since 5.0.47 |
|
60 | - */ |
|
61 | - private string $save_path = ''; |
|
62 | - |
|
63 | - |
|
64 | - /** |
|
65 | - * StartSession constructor. |
|
66 | - * |
|
67 | - * @param RequestInterface $request |
|
68 | - */ |
|
69 | - public function __construct(RequestInterface $request) |
|
70 | - { |
|
71 | - $this->request = $request; |
|
72 | - } |
|
73 | - |
|
74 | - |
|
75 | - /** |
|
76 | - * Check if a custom session save handler is in play |
|
77 | - * and attempt to start the PHP session |
|
78 | - * |
|
79 | - * @since 4.9.68.p |
|
80 | - */ |
|
81 | - public function startSession(): int |
|
82 | - { |
|
83 | - // check that session has started |
|
84 | - if (session_id() === '') { |
|
85 | - // clear any previous error |
|
86 | - error_clear_last(); |
|
87 | - |
|
88 | - // convert warnings to ErrorException so we can catch them |
|
89 | - $previous_handler = set_error_handler([$this, 'customErrorHandler'], E_WARNING); |
|
90 | - |
|
91 | - try { |
|
92 | - $this->initializeSessionVars(); |
|
93 | - // starts a new session if one doesn't already exist, or re-initiates an existing one |
|
94 | - if ($this->hasCustomSessionSaveHandler()) { |
|
95 | - $this->checkCustomSessionSaveHandler(); |
|
96 | - } else { |
|
97 | - $this->verifySessionSavePath(); |
|
98 | - $this->sessionStart(); |
|
99 | - } |
|
100 | - } catch (Throwable $error) { |
|
101 | - error_log( |
|
102 | - sprintf( |
|
103 | - '[SessionStartHandler] session_start() warning: %s in %s:%s', |
|
104 | - $error->getMessage(), |
|
105 | - $error->getFile(), |
|
106 | - $error->getLine() |
|
107 | - ) |
|
108 | - ); |
|
109 | - $this->displaySessionErrorNotice( |
|
110 | - $error->getMessage(), |
|
111 | - $error->getFile(), |
|
112 | - __FUNCTION__, |
|
113 | - $error->getLine() |
|
114 | - ); |
|
115 | - } finally { |
|
116 | - $this->restorePreviousErrorHandler($previous_handler); |
|
117 | - } |
|
118 | - } |
|
119 | - return session_status(); |
|
120 | - } |
|
121 | - |
|
122 | - |
|
123 | - /** |
|
124 | - * @return void |
|
125 | - * @since 5.0.47 |
|
126 | - */ |
|
127 | - private function initializeSessionVars(): void |
|
128 | - { |
|
129 | - $this->open_basedir = ini_get('open_basedir') ?: ''; |
|
130 | - $this->save_handler = strtolower((string) ini_get('session.save_handler')); |
|
131 | - $this->save_path = session_save_path() ?: ''; |
|
132 | - } |
|
133 | - |
|
134 | - |
|
135 | - /** |
|
136 | - * @return void |
|
137 | - * @throws Throwable |
|
138 | - * @since 5.0.46 |
|
139 | - */ |
|
140 | - private function sessionStart(): void |
|
141 | - { |
|
142 | - session_start(); |
|
143 | - session_write_close(); |
|
144 | - } |
|
145 | - |
|
146 | - |
|
147 | - /** |
|
148 | - * @return void |
|
149 | - * @throws ErrorException |
|
150 | - * @since 5.0.46 |
|
151 | - */ |
|
152 | - private function verifySessionSavePath(): void |
|
153 | - { |
|
154 | - if (WP_DEBUG) { |
|
155 | - error_log( |
|
156 | - sprintf( |
|
157 | - "[SessionStartHandler] diagnostic: save_handler=%s save_path=%s open_basedir=%s", |
|
158 | - $this->save_handler, |
|
159 | - $this->save_path, |
|
160 | - $this->open_basedir ?: '(none)' |
|
161 | - ) |
|
162 | - ); |
|
163 | - } |
|
164 | - // Only validate session save path as a filesystem directory when PHP is |
|
165 | - // configured to use the 'files' session save handler. Other handlers |
|
166 | - // (memcache, memcached, redis, user, etc.) use different transport |
|
167 | - // formats (hosts, sockets, URIs) and are not filesystem directories. |
|
168 | - if ($this->save_handler !== 'files') { |
|
169 | - // assume the configured handler knows how to interpret the save path |
|
170 | - // (e.g. "unix:///run/memcached/memcached.sock", "127.0.0.1:11211", etc.) |
|
171 | - return; |
|
172 | - } |
|
173 | - $this->save_path = $this->normalizeSessionSavePath($this->save_path); |
|
174 | - // Use @-suppressed checks to avoid PHP warnings while validating. |
|
175 | - if (! @is_dir($this->save_path) || ! @is_writable($this->save_path)) { |
|
176 | - throw new ErrorException( |
|
177 | - sprintf( |
|
178 | - esc_html__('Invalid or missing session save path: %s', 'event_espresso'), |
|
179 | - $this->save_path |
|
180 | - ), |
|
181 | - 0, |
|
182 | - E_WARNING, |
|
183 | - __FILE__, |
|
184 | - __LINE__ |
|
185 | - ); |
|
186 | - } |
|
187 | - } |
|
188 | - |
|
189 | - |
|
190 | - /** |
|
191 | - * @param string $session_save_path |
|
192 | - * @return string |
|
193 | - * @throws ErrorException |
|
194 | - * @since 5.0.47 |
|
195 | - */ |
|
196 | - private function normalizeSessionSavePath(string $session_save_path): string |
|
197 | - { |
|
198 | - // Normalize "N;/path" style values |
|
199 | - if (strpos($session_save_path, ';') !== false) { |
|
200 | - $parts = explode(';', $session_save_path); |
|
201 | - $session_save_path = end($parts); |
|
202 | - } |
|
203 | - $session_save_path = trim((string) $session_save_path); |
|
204 | - if ($session_save_path === '') { |
|
205 | - // fall back to a sane temp dir if PHP reports no explicit session_save_path |
|
206 | - $session_save_path = sys_get_temp_dir(); |
|
207 | - } |
|
208 | - // normalize trailing separators |
|
209 | - $session_save_path = rtrim($session_save_path, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR; |
|
210 | - // For 'files' handler we expect a writable filesystem directory. |
|
211 | - // However, calling realpath() or is_dir() on paths outside of PHP's |
|
212 | - // configured open_basedir can trigger warnings. |
|
213 | - // Handle that case explicitly by checking open_basedir first |
|
214 | - // and avoiding functions that would emit warnings. |
|
215 | - if ($this->open_basedir !== '') { |
|
216 | - $session_save_path = $this->checkPathsOutsideBaseDir($session_save_path); |
|
217 | - } else { |
|
218 | - // No open_basedir restriction; realpath() is safe to use and gives |
|
219 | - // us a canonical path for the directory checks. |
|
220 | - $session_save_path = @realpath($session_save_path) ?: $session_save_path; |
|
221 | - } |
|
222 | - return $session_save_path; |
|
223 | - } |
|
224 | - |
|
225 | - |
|
226 | - /** |
|
227 | - * @param string $session_save_path |
|
228 | - * @return string |
|
229 | - * @throws ErrorException |
|
230 | - * @since 5.0.47 |
|
231 | - */ |
|
232 | - private function checkPathsOutsideBaseDir(string $session_save_path): string |
|
233 | - { |
|
234 | - // open_basedir is set; check whether the configured session path |
|
235 | - // appears to be within one of the allowed paths. |
|
236 | - $allowed_paths = array_filter(array_map('trim', explode(PATH_SEPARATOR, $this->open_basedir))); |
|
237 | - $allowed = false; |
|
238 | - foreach ($allowed_paths as $allowed_path) { |
|
239 | - if ($allowed_path === '') { |
|
240 | - continue; |
|
241 | - } |
|
242 | - // normalize trailing separators for comparison |
|
243 | - $allowed_path_norm = rtrim($allowed_path, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR; |
|
244 | - // compare start of paths for a match |
|
245 | - if (strncmp($session_save_path, $allowed_path_norm, strlen($allowed_path_norm)) === 0) { |
|
246 | - $allowed = true; |
|
247 | - break; |
|
248 | - } |
|
249 | - } |
|
250 | - if ($allowed) { |
|
251 | - return $session_save_path; |
|
252 | - } |
|
253 | - error_log( |
|
254 | - sprintf( |
|
255 | - "[SessionStartHandler] session_save_path outside open_basedir: save_path=%s open_basedir=%s", |
|
256 | - $session_save_path, |
|
257 | - $this->open_basedir |
|
258 | - ) |
|
259 | - ); |
|
260 | - throw new ErrorException( |
|
261 | - sprintf( |
|
262 | - esc_html__( |
|
263 | - 'Session save path "%s" is outside PHP open_basedir allowed paths: %s. Ask your server admin to move session.save_path inside open_basedir or update open_basedir', |
|
264 | - 'event_espresso' |
|
265 | - ), |
|
266 | - $session_save_path, |
|
267 | - $this->open_basedir |
|
268 | - ), |
|
269 | - 0, |
|
270 | - E_WARNING, |
|
271 | - __FILE__, |
|
272 | - __LINE__ |
|
273 | - ); |
|
274 | - } |
|
275 | - |
|
276 | - |
|
277 | - /** |
|
278 | - * Returns `true` if the 'session.save_handler' ini setting matches a known custom handler |
|
279 | - * |
|
280 | - * @return bool |
|
281 | - * @since 4.9.68.p |
|
282 | - */ |
|
283 | - private function hasCustomSessionSaveHandler(): bool |
|
284 | - { |
|
285 | - return $this->save_handler === 'user'; |
|
286 | - } |
|
287 | - |
|
288 | - |
|
289 | - /** |
|
290 | - * Attempt to start the PHP session when a custom Session Save Handler is known to be set. |
|
291 | - * |
|
292 | - * @throws ErrorException |
|
293 | - * @throws Throwable |
|
294 | - * @since 4.9.68.p |
|
295 | - */ |
|
296 | - private function checkCustomSessionSaveHandler(): void |
|
297 | - { |
|
298 | - // If we've already successfully tested the session save handler |
|
299 | - // on a previous request then just start the session |
|
300 | - if ($this->sessionSaveHandlerIsValid()) { |
|
301 | - $this->sessionStart(); |
|
302 | - return; |
|
303 | - } |
|
304 | - // If not, then attempt to deal with any errors, |
|
305 | - // otherwise, try to hobble along without the session |
|
306 | - if (! $this->handleSessionSaveHandlerErrors()) { |
|
307 | - return; |
|
308 | - } |
|
309 | - // there is no record of a fatal error while trying to start the session |
|
310 | - // so let's see if there's a custom session save handler. Proceed with caution |
|
311 | - if ($this->initializeSessionSaveHandlerStatus() === false) { |
|
312 | - throw new ErrorException( |
|
313 | - esc_html__('Failed to initialize session save handler status', 'event_espresso'), |
|
314 | - 0, |
|
315 | - E_WARNING, |
|
316 | - __FILE__, |
|
317 | - __LINE__ |
|
318 | - ); |
|
319 | - } |
|
320 | - // hold your breath, the custom session save handler might cause a fatal here... |
|
321 | - $this->sessionStart(); |
|
322 | - // phew! we made it! the custom session handler is a-ok |
|
323 | - if ($this->setSessionSaveHandlerStatusToValid() === false) { |
|
324 | - throw new ErrorException( |
|
325 | - esc_html__('Failed to set session save handler status to valid', 'event_espresso'), |
|
326 | - 0, |
|
327 | - E_WARNING, |
|
328 | - __FILE__, |
|
329 | - __LINE__ |
|
330 | - ); |
|
331 | - } |
|
332 | - } |
|
333 | - |
|
334 | - |
|
335 | - /** |
|
336 | - * retrieves the value for the 'ee_session_save_handler_status' WP option. |
|
337 | - * default value = 'session_save_handler_untested' |
|
338 | - * |
|
339 | - * @return string |
|
340 | - * @since 4.9.68.p |
|
341 | - */ |
|
342 | - private function getSessionSaveHandlerStatus(): string |
|
343 | - { |
|
344 | - return get_option( |
|
345 | - SessionStartHandler::OPTION_NAME_SESSION_SAVE_HANDLER_STATUS, |
|
346 | - SessionStartHandler::SESSION_SAVE_HANDLER_STATUS_UNKNOWN |
|
347 | - ); |
|
348 | - } |
|
349 | - |
|
350 | - |
|
351 | - /** |
|
352 | - * Sets the 'ee_session_save_handler_status' WP option value to 'session_save_handler_failed' |
|
353 | - * which can then be upgraded is everything works correctly |
|
354 | - * |
|
355 | - * @return bool |
|
356 | - * @since 4.9.68.p |
|
357 | - */ |
|
358 | - private function initializeSessionSaveHandlerStatus(): bool |
|
359 | - { |
|
360 | - return update_option( |
|
361 | - SessionStartHandler::OPTION_NAME_SESSION_SAVE_HANDLER_STATUS, |
|
362 | - SessionStartHandler::SESSION_SAVE_HANDLER_STATUS_FAILED |
|
363 | - ); |
|
364 | - } |
|
365 | - |
|
366 | - |
|
367 | - /** |
|
368 | - * Sets the 'ee_session_save_handler_status' WP option value to 'session_save_handler_success' |
|
369 | - * |
|
370 | - * @return bool |
|
371 | - * @since 4.9.68.p |
|
372 | - */ |
|
373 | - private function setSessionSaveHandlerStatusToValid(): bool |
|
374 | - { |
|
375 | - return update_option( |
|
376 | - SessionStartHandler::OPTION_NAME_SESSION_SAVE_HANDLER_STATUS, |
|
377 | - SessionStartHandler::SESSION_SAVE_HANDLER_STATUS_SUCCESS |
|
378 | - ); |
|
379 | - } |
|
380 | - |
|
381 | - |
|
382 | - /** |
|
383 | - * Sets the 'ee_session_save_handler_status' WP option value to 'session_save_handler_untested' |
|
384 | - * |
|
385 | - * @return bool |
|
386 | - * @since 4.9.68.p |
|
387 | - */ |
|
388 | - private function resetSessionSaveHandlerStatus(): bool |
|
389 | - { |
|
390 | - return update_option( |
|
391 | - SessionStartHandler::OPTION_NAME_SESSION_SAVE_HANDLER_STATUS, |
|
392 | - SessionStartHandler::SESSION_SAVE_HANDLER_STATUS_UNKNOWN |
|
393 | - ); |
|
394 | - } |
|
395 | - |
|
396 | - |
|
397 | - /** |
|
398 | - * Returns `true` if the 'ee_session_save_handler_status' WP option value |
|
399 | - * is equal to 'session_save_handler_success' |
|
400 | - * |
|
401 | - * @return bool |
|
402 | - * @since 4.9.68.p |
|
403 | - */ |
|
404 | - private function sessionSaveHandlerIsValid(): bool |
|
405 | - { |
|
406 | - return $this->getSessionSaveHandlerStatus() === SessionStartHandler::SESSION_SAVE_HANDLER_STATUS_SUCCESS; |
|
407 | - } |
|
408 | - |
|
409 | - |
|
410 | - /** |
|
411 | - * Returns `true` if the 'ee_session_save_handler_status' WP option value |
|
412 | - * is equal to 'session_save_handler_failed' |
|
413 | - * |
|
414 | - * @return bool |
|
415 | - * @since 4.9.68.p |
|
416 | - */ |
|
417 | - private function sessionSaveHandlerFailed(): bool |
|
418 | - { |
|
419 | - return $this->getSessionSaveHandlerStatus() === SessionStartHandler::SESSION_SAVE_HANDLER_STATUS_FAILED; |
|
420 | - } |
|
421 | - |
|
422 | - |
|
423 | - /** |
|
424 | - * @param int $severity |
|
425 | - * @param string $message |
|
426 | - * @param string $file |
|
427 | - * @param int $line |
|
428 | - * @return bool |
|
429 | - * @throws ErrorException |
|
430 | - * @since 5.0.46 |
|
431 | - */ |
|
432 | - public function customErrorHandler(int $severity, string $message, string $file, int $line): bool |
|
433 | - { |
|
434 | - // Only convert warnings we care about |
|
435 | - if (($severity & E_WARNING) === E_WARNING) { |
|
436 | - throw new ErrorException($message, 0, $severity, $file, $line); |
|
437 | - } |
|
438 | - // fallback to PHP's normal handler for other severities |
|
439 | - return false; |
|
440 | - } |
|
441 | - |
|
442 | - |
|
443 | - /** |
|
444 | - * @param callable|null $previous_handler |
|
445 | - * @return void |
|
446 | - * @since 5.0.46 |
|
447 | - */ |
|
448 | - private function restorePreviousErrorHandler(?callable $previous_handler): void |
|
449 | - { |
|
450 | - if ($previous_handler !== null) { |
|
451 | - set_error_handler($previous_handler); |
|
452 | - } else { |
|
453 | - restore_error_handler(); |
|
454 | - } |
|
455 | - } |
|
456 | - |
|
457 | - |
|
458 | - /** |
|
459 | - * Returns `true` if no errors were detected with the session save handler, |
|
460 | - * otherwise attempts to work notify the appropriate authorities |
|
461 | - * with a suggestion for how to fix the issue, and returns `false`. |
|
462 | - * |
|
463 | - * @return bool |
|
464 | - * @throws ErrorException |
|
465 | - * @throws Throwable |
|
466 | - * @since 4.9.68.p |
|
467 | - */ |
|
468 | - private function handleSessionSaveHandlerErrors(): bool |
|
469 | - { |
|
470 | - // Check if we had a fatal error last time while trying to start the session |
|
471 | - if ($this->sessionSaveHandlerFailed()) { |
|
472 | - // apparently, last time we tried using the custom session save handler there was a fatal |
|
473 | - if ($this->request->requestParamIsSet(SessionStartHandler::REQUEST_PARAM_RETRY_SESSION)) { |
|
474 | - if ($this->resetSessionSaveHandlerStatus() === false) { |
|
475 | - throw new ErrorException( |
|
476 | - esc_html__('Failed to reset session save handler status', 'event_espresso'), |
|
477 | - 0, |
|
478 | - E_WARNING, |
|
479 | - __FILE__, |
|
480 | - __LINE__ |
|
481 | - ); |
|
482 | - } |
|
483 | - // remove "ee_retry_session", otherwise if the problem still isn't fixed, |
|
484 | - // we'll just keep getting the fatal error over and over. |
|
485 | - // Better to remove it and redirect, and try on the next request |
|
486 | - EEH_URL::safeRedirectAndExit( |
|
487 | - remove_query_arg( |
|
488 | - [SessionStartHandler::REQUEST_PARAM_RETRY_SESSION], |
|
489 | - EEH_URL::current_url() |
|
490 | - ) |
|
491 | - ); |
|
492 | - } |
|
493 | - // so the session is broken, don't try it again, |
|
494 | - // just show a message to users that can fix it |
|
495 | - $this->displaySessionSaveHandlerErrorNotice(); |
|
496 | - return false; |
|
497 | - } |
|
498 | - return true; |
|
499 | - } |
|
500 | - |
|
501 | - |
|
502 | - /** |
|
503 | - * @since 4.9.68.p |
|
504 | - */ |
|
505 | - private function displaySessionSaveHandlerErrorNotice(): void |
|
506 | - { |
|
507 | - $retry_session_url = add_query_arg( |
|
508 | - [SessionStartHandler::REQUEST_PARAM_RETRY_SESSION => true], |
|
509 | - EEH_URL::current_url() |
|
510 | - ); |
|
511 | - $this->displaySessionErrorNotice( |
|
512 | - sprintf( |
|
513 | - esc_html__( |
|
514 | - 'It appears there was a fatal error while starting the session, so Event Espresso is not able to process registrations normally. Some hosting companies, like Pantheon, require an extra plugin for Event Espresso to work. Please install the %1$sWordPress Native PHP Sessions plugin%2$s, then %3$sclick here to check if the problem is resolved.%2$s', |
|
515 | - 'event_espresso' |
|
516 | - ), |
|
517 | - '<a href="https://wordpress.org/plugins/wp-native-php-sessions/">', |
|
518 | - '</a>', |
|
519 | - '<a href="' . $retry_session_url . '">' |
|
520 | - ), |
|
521 | - __FILE__, |
|
522 | - __FUNCTION__, |
|
523 | - __LINE__ |
|
524 | - ); |
|
525 | - } |
|
526 | - |
|
527 | - |
|
528 | - /** |
|
529 | - * Generates an EE_Error notice regarding the current session woes |
|
530 | - * but only if the current user is an admin with permission to 'install_plugins'. |
|
531 | - * |
|
532 | - * @since 5.0.46 |
|
533 | - */ |
|
534 | - private function displaySessionErrorNotice(string $message, string $file, string $function, int $line): void |
|
535 | - { |
|
536 | - if (current_user_can('install_plugins')) { |
|
537 | - EE_Error::add_error($message, $file, $function, $line); |
|
538 | - } |
|
539 | - } |
|
32 | + const OPTION_NAME_SESSION_SAVE_HANDLER_STATUS = 'ee_session_save_handler_status'; |
|
33 | + |
|
34 | + const REQUEST_PARAM_RETRY_SESSION = 'ee_retry_session'; |
|
35 | + |
|
36 | + const SESSION_SAVE_HANDLER_STATUS_FAILED = 'session_save_handler_failed'; |
|
37 | + |
|
38 | + const SESSION_SAVE_HANDLER_STATUS_SUCCESS = 'session_save_handler_success'; |
|
39 | + |
|
40 | + const SESSION_SAVE_HANDLER_STATUS_UNKNOWN = 'session_save_handler_untested'; |
|
41 | + |
|
42 | + |
|
43 | + protected RequestInterface $request; |
|
44 | + |
|
45 | + /** |
|
46 | + * @var string |
|
47 | + * @since 5.0.47 |
|
48 | + */ |
|
49 | + private string $open_basedir = ''; |
|
50 | + |
|
51 | + /** |
|
52 | + * @var string |
|
53 | + * @since 5.0.47 |
|
54 | + */ |
|
55 | + private string $save_handler = ''; |
|
56 | + |
|
57 | + /** |
|
58 | + * @var string |
|
59 | + * @since 5.0.47 |
|
60 | + */ |
|
61 | + private string $save_path = ''; |
|
62 | + |
|
63 | + |
|
64 | + /** |
|
65 | + * StartSession constructor. |
|
66 | + * |
|
67 | + * @param RequestInterface $request |
|
68 | + */ |
|
69 | + public function __construct(RequestInterface $request) |
|
70 | + { |
|
71 | + $this->request = $request; |
|
72 | + } |
|
73 | + |
|
74 | + |
|
75 | + /** |
|
76 | + * Check if a custom session save handler is in play |
|
77 | + * and attempt to start the PHP session |
|
78 | + * |
|
79 | + * @since 4.9.68.p |
|
80 | + */ |
|
81 | + public function startSession(): int |
|
82 | + { |
|
83 | + // check that session has started |
|
84 | + if (session_id() === '') { |
|
85 | + // clear any previous error |
|
86 | + error_clear_last(); |
|
87 | + |
|
88 | + // convert warnings to ErrorException so we can catch them |
|
89 | + $previous_handler = set_error_handler([$this, 'customErrorHandler'], E_WARNING); |
|
90 | + |
|
91 | + try { |
|
92 | + $this->initializeSessionVars(); |
|
93 | + // starts a new session if one doesn't already exist, or re-initiates an existing one |
|
94 | + if ($this->hasCustomSessionSaveHandler()) { |
|
95 | + $this->checkCustomSessionSaveHandler(); |
|
96 | + } else { |
|
97 | + $this->verifySessionSavePath(); |
|
98 | + $this->sessionStart(); |
|
99 | + } |
|
100 | + } catch (Throwable $error) { |
|
101 | + error_log( |
|
102 | + sprintf( |
|
103 | + '[SessionStartHandler] session_start() warning: %s in %s:%s', |
|
104 | + $error->getMessage(), |
|
105 | + $error->getFile(), |
|
106 | + $error->getLine() |
|
107 | + ) |
|
108 | + ); |
|
109 | + $this->displaySessionErrorNotice( |
|
110 | + $error->getMessage(), |
|
111 | + $error->getFile(), |
|
112 | + __FUNCTION__, |
|
113 | + $error->getLine() |
|
114 | + ); |
|
115 | + } finally { |
|
116 | + $this->restorePreviousErrorHandler($previous_handler); |
|
117 | + } |
|
118 | + } |
|
119 | + return session_status(); |
|
120 | + } |
|
121 | + |
|
122 | + |
|
123 | + /** |
|
124 | + * @return void |
|
125 | + * @since 5.0.47 |
|
126 | + */ |
|
127 | + private function initializeSessionVars(): void |
|
128 | + { |
|
129 | + $this->open_basedir = ini_get('open_basedir') ?: ''; |
|
130 | + $this->save_handler = strtolower((string) ini_get('session.save_handler')); |
|
131 | + $this->save_path = session_save_path() ?: ''; |
|
132 | + } |
|
133 | + |
|
134 | + |
|
135 | + /** |
|
136 | + * @return void |
|
137 | + * @throws Throwable |
|
138 | + * @since 5.0.46 |
|
139 | + */ |
|
140 | + private function sessionStart(): void |
|
141 | + { |
|
142 | + session_start(); |
|
143 | + session_write_close(); |
|
144 | + } |
|
145 | + |
|
146 | + |
|
147 | + /** |
|
148 | + * @return void |
|
149 | + * @throws ErrorException |
|
150 | + * @since 5.0.46 |
|
151 | + */ |
|
152 | + private function verifySessionSavePath(): void |
|
153 | + { |
|
154 | + if (WP_DEBUG) { |
|
155 | + error_log( |
|
156 | + sprintf( |
|
157 | + "[SessionStartHandler] diagnostic: save_handler=%s save_path=%s open_basedir=%s", |
|
158 | + $this->save_handler, |
|
159 | + $this->save_path, |
|
160 | + $this->open_basedir ?: '(none)' |
|
161 | + ) |
|
162 | + ); |
|
163 | + } |
|
164 | + // Only validate session save path as a filesystem directory when PHP is |
|
165 | + // configured to use the 'files' session save handler. Other handlers |
|
166 | + // (memcache, memcached, redis, user, etc.) use different transport |
|
167 | + // formats (hosts, sockets, URIs) and are not filesystem directories. |
|
168 | + if ($this->save_handler !== 'files') { |
|
169 | + // assume the configured handler knows how to interpret the save path |
|
170 | + // (e.g. "unix:///run/memcached/memcached.sock", "127.0.0.1:11211", etc.) |
|
171 | + return; |
|
172 | + } |
|
173 | + $this->save_path = $this->normalizeSessionSavePath($this->save_path); |
|
174 | + // Use @-suppressed checks to avoid PHP warnings while validating. |
|
175 | + if (! @is_dir($this->save_path) || ! @is_writable($this->save_path)) { |
|
176 | + throw new ErrorException( |
|
177 | + sprintf( |
|
178 | + esc_html__('Invalid or missing session save path: %s', 'event_espresso'), |
|
179 | + $this->save_path |
|
180 | + ), |
|
181 | + 0, |
|
182 | + E_WARNING, |
|
183 | + __FILE__, |
|
184 | + __LINE__ |
|
185 | + ); |
|
186 | + } |
|
187 | + } |
|
188 | + |
|
189 | + |
|
190 | + /** |
|
191 | + * @param string $session_save_path |
|
192 | + * @return string |
|
193 | + * @throws ErrorException |
|
194 | + * @since 5.0.47 |
|
195 | + */ |
|
196 | + private function normalizeSessionSavePath(string $session_save_path): string |
|
197 | + { |
|
198 | + // Normalize "N;/path" style values |
|
199 | + if (strpos($session_save_path, ';') !== false) { |
|
200 | + $parts = explode(';', $session_save_path); |
|
201 | + $session_save_path = end($parts); |
|
202 | + } |
|
203 | + $session_save_path = trim((string) $session_save_path); |
|
204 | + if ($session_save_path === '') { |
|
205 | + // fall back to a sane temp dir if PHP reports no explicit session_save_path |
|
206 | + $session_save_path = sys_get_temp_dir(); |
|
207 | + } |
|
208 | + // normalize trailing separators |
|
209 | + $session_save_path = rtrim($session_save_path, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR; |
|
210 | + // For 'files' handler we expect a writable filesystem directory. |
|
211 | + // However, calling realpath() or is_dir() on paths outside of PHP's |
|
212 | + // configured open_basedir can trigger warnings. |
|
213 | + // Handle that case explicitly by checking open_basedir first |
|
214 | + // and avoiding functions that would emit warnings. |
|
215 | + if ($this->open_basedir !== '') { |
|
216 | + $session_save_path = $this->checkPathsOutsideBaseDir($session_save_path); |
|
217 | + } else { |
|
218 | + // No open_basedir restriction; realpath() is safe to use and gives |
|
219 | + // us a canonical path for the directory checks. |
|
220 | + $session_save_path = @realpath($session_save_path) ?: $session_save_path; |
|
221 | + } |
|
222 | + return $session_save_path; |
|
223 | + } |
|
224 | + |
|
225 | + |
|
226 | + /** |
|
227 | + * @param string $session_save_path |
|
228 | + * @return string |
|
229 | + * @throws ErrorException |
|
230 | + * @since 5.0.47 |
|
231 | + */ |
|
232 | + private function checkPathsOutsideBaseDir(string $session_save_path): string |
|
233 | + { |
|
234 | + // open_basedir is set; check whether the configured session path |
|
235 | + // appears to be within one of the allowed paths. |
|
236 | + $allowed_paths = array_filter(array_map('trim', explode(PATH_SEPARATOR, $this->open_basedir))); |
|
237 | + $allowed = false; |
|
238 | + foreach ($allowed_paths as $allowed_path) { |
|
239 | + if ($allowed_path === '') { |
|
240 | + continue; |
|
241 | + } |
|
242 | + // normalize trailing separators for comparison |
|
243 | + $allowed_path_norm = rtrim($allowed_path, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR; |
|
244 | + // compare start of paths for a match |
|
245 | + if (strncmp($session_save_path, $allowed_path_norm, strlen($allowed_path_norm)) === 0) { |
|
246 | + $allowed = true; |
|
247 | + break; |
|
248 | + } |
|
249 | + } |
|
250 | + if ($allowed) { |
|
251 | + return $session_save_path; |
|
252 | + } |
|
253 | + error_log( |
|
254 | + sprintf( |
|
255 | + "[SessionStartHandler] session_save_path outside open_basedir: save_path=%s open_basedir=%s", |
|
256 | + $session_save_path, |
|
257 | + $this->open_basedir |
|
258 | + ) |
|
259 | + ); |
|
260 | + throw new ErrorException( |
|
261 | + sprintf( |
|
262 | + esc_html__( |
|
263 | + 'Session save path "%s" is outside PHP open_basedir allowed paths: %s. Ask your server admin to move session.save_path inside open_basedir or update open_basedir', |
|
264 | + 'event_espresso' |
|
265 | + ), |
|
266 | + $session_save_path, |
|
267 | + $this->open_basedir |
|
268 | + ), |
|
269 | + 0, |
|
270 | + E_WARNING, |
|
271 | + __FILE__, |
|
272 | + __LINE__ |
|
273 | + ); |
|
274 | + } |
|
275 | + |
|
276 | + |
|
277 | + /** |
|
278 | + * Returns `true` if the 'session.save_handler' ini setting matches a known custom handler |
|
279 | + * |
|
280 | + * @return bool |
|
281 | + * @since 4.9.68.p |
|
282 | + */ |
|
283 | + private function hasCustomSessionSaveHandler(): bool |
|
284 | + { |
|
285 | + return $this->save_handler === 'user'; |
|
286 | + } |
|
287 | + |
|
288 | + |
|
289 | + /** |
|
290 | + * Attempt to start the PHP session when a custom Session Save Handler is known to be set. |
|
291 | + * |
|
292 | + * @throws ErrorException |
|
293 | + * @throws Throwable |
|
294 | + * @since 4.9.68.p |
|
295 | + */ |
|
296 | + private function checkCustomSessionSaveHandler(): void |
|
297 | + { |
|
298 | + // If we've already successfully tested the session save handler |
|
299 | + // on a previous request then just start the session |
|
300 | + if ($this->sessionSaveHandlerIsValid()) { |
|
301 | + $this->sessionStart(); |
|
302 | + return; |
|
303 | + } |
|
304 | + // If not, then attempt to deal with any errors, |
|
305 | + // otherwise, try to hobble along without the session |
|
306 | + if (! $this->handleSessionSaveHandlerErrors()) { |
|
307 | + return; |
|
308 | + } |
|
309 | + // there is no record of a fatal error while trying to start the session |
|
310 | + // so let's see if there's a custom session save handler. Proceed with caution |
|
311 | + if ($this->initializeSessionSaveHandlerStatus() === false) { |
|
312 | + throw new ErrorException( |
|
313 | + esc_html__('Failed to initialize session save handler status', 'event_espresso'), |
|
314 | + 0, |
|
315 | + E_WARNING, |
|
316 | + __FILE__, |
|
317 | + __LINE__ |
|
318 | + ); |
|
319 | + } |
|
320 | + // hold your breath, the custom session save handler might cause a fatal here... |
|
321 | + $this->sessionStart(); |
|
322 | + // phew! we made it! the custom session handler is a-ok |
|
323 | + if ($this->setSessionSaveHandlerStatusToValid() === false) { |
|
324 | + throw new ErrorException( |
|
325 | + esc_html__('Failed to set session save handler status to valid', 'event_espresso'), |
|
326 | + 0, |
|
327 | + E_WARNING, |
|
328 | + __FILE__, |
|
329 | + __LINE__ |
|
330 | + ); |
|
331 | + } |
|
332 | + } |
|
333 | + |
|
334 | + |
|
335 | + /** |
|
336 | + * retrieves the value for the 'ee_session_save_handler_status' WP option. |
|
337 | + * default value = 'session_save_handler_untested' |
|
338 | + * |
|
339 | + * @return string |
|
340 | + * @since 4.9.68.p |
|
341 | + */ |
|
342 | + private function getSessionSaveHandlerStatus(): string |
|
343 | + { |
|
344 | + return get_option( |
|
345 | + SessionStartHandler::OPTION_NAME_SESSION_SAVE_HANDLER_STATUS, |
|
346 | + SessionStartHandler::SESSION_SAVE_HANDLER_STATUS_UNKNOWN |
|
347 | + ); |
|
348 | + } |
|
349 | + |
|
350 | + |
|
351 | + /** |
|
352 | + * Sets the 'ee_session_save_handler_status' WP option value to 'session_save_handler_failed' |
|
353 | + * which can then be upgraded is everything works correctly |
|
354 | + * |
|
355 | + * @return bool |
|
356 | + * @since 4.9.68.p |
|
357 | + */ |
|
358 | + private function initializeSessionSaveHandlerStatus(): bool |
|
359 | + { |
|
360 | + return update_option( |
|
361 | + SessionStartHandler::OPTION_NAME_SESSION_SAVE_HANDLER_STATUS, |
|
362 | + SessionStartHandler::SESSION_SAVE_HANDLER_STATUS_FAILED |
|
363 | + ); |
|
364 | + } |
|
365 | + |
|
366 | + |
|
367 | + /** |
|
368 | + * Sets the 'ee_session_save_handler_status' WP option value to 'session_save_handler_success' |
|
369 | + * |
|
370 | + * @return bool |
|
371 | + * @since 4.9.68.p |
|
372 | + */ |
|
373 | + private function setSessionSaveHandlerStatusToValid(): bool |
|
374 | + { |
|
375 | + return update_option( |
|
376 | + SessionStartHandler::OPTION_NAME_SESSION_SAVE_HANDLER_STATUS, |
|
377 | + SessionStartHandler::SESSION_SAVE_HANDLER_STATUS_SUCCESS |
|
378 | + ); |
|
379 | + } |
|
380 | + |
|
381 | + |
|
382 | + /** |
|
383 | + * Sets the 'ee_session_save_handler_status' WP option value to 'session_save_handler_untested' |
|
384 | + * |
|
385 | + * @return bool |
|
386 | + * @since 4.9.68.p |
|
387 | + */ |
|
388 | + private function resetSessionSaveHandlerStatus(): bool |
|
389 | + { |
|
390 | + return update_option( |
|
391 | + SessionStartHandler::OPTION_NAME_SESSION_SAVE_HANDLER_STATUS, |
|
392 | + SessionStartHandler::SESSION_SAVE_HANDLER_STATUS_UNKNOWN |
|
393 | + ); |
|
394 | + } |
|
395 | + |
|
396 | + |
|
397 | + /** |
|
398 | + * Returns `true` if the 'ee_session_save_handler_status' WP option value |
|
399 | + * is equal to 'session_save_handler_success' |
|
400 | + * |
|
401 | + * @return bool |
|
402 | + * @since 4.9.68.p |
|
403 | + */ |
|
404 | + private function sessionSaveHandlerIsValid(): bool |
|
405 | + { |
|
406 | + return $this->getSessionSaveHandlerStatus() === SessionStartHandler::SESSION_SAVE_HANDLER_STATUS_SUCCESS; |
|
407 | + } |
|
408 | + |
|
409 | + |
|
410 | + /** |
|
411 | + * Returns `true` if the 'ee_session_save_handler_status' WP option value |
|
412 | + * is equal to 'session_save_handler_failed' |
|
413 | + * |
|
414 | + * @return bool |
|
415 | + * @since 4.9.68.p |
|
416 | + */ |
|
417 | + private function sessionSaveHandlerFailed(): bool |
|
418 | + { |
|
419 | + return $this->getSessionSaveHandlerStatus() === SessionStartHandler::SESSION_SAVE_HANDLER_STATUS_FAILED; |
|
420 | + } |
|
421 | + |
|
422 | + |
|
423 | + /** |
|
424 | + * @param int $severity |
|
425 | + * @param string $message |
|
426 | + * @param string $file |
|
427 | + * @param int $line |
|
428 | + * @return bool |
|
429 | + * @throws ErrorException |
|
430 | + * @since 5.0.46 |
|
431 | + */ |
|
432 | + public function customErrorHandler(int $severity, string $message, string $file, int $line): bool |
|
433 | + { |
|
434 | + // Only convert warnings we care about |
|
435 | + if (($severity & E_WARNING) === E_WARNING) { |
|
436 | + throw new ErrorException($message, 0, $severity, $file, $line); |
|
437 | + } |
|
438 | + // fallback to PHP's normal handler for other severities |
|
439 | + return false; |
|
440 | + } |
|
441 | + |
|
442 | + |
|
443 | + /** |
|
444 | + * @param callable|null $previous_handler |
|
445 | + * @return void |
|
446 | + * @since 5.0.46 |
|
447 | + */ |
|
448 | + private function restorePreviousErrorHandler(?callable $previous_handler): void |
|
449 | + { |
|
450 | + if ($previous_handler !== null) { |
|
451 | + set_error_handler($previous_handler); |
|
452 | + } else { |
|
453 | + restore_error_handler(); |
|
454 | + } |
|
455 | + } |
|
456 | + |
|
457 | + |
|
458 | + /** |
|
459 | + * Returns `true` if no errors were detected with the session save handler, |
|
460 | + * otherwise attempts to work notify the appropriate authorities |
|
461 | + * with a suggestion for how to fix the issue, and returns `false`. |
|
462 | + * |
|
463 | + * @return bool |
|
464 | + * @throws ErrorException |
|
465 | + * @throws Throwable |
|
466 | + * @since 4.9.68.p |
|
467 | + */ |
|
468 | + private function handleSessionSaveHandlerErrors(): bool |
|
469 | + { |
|
470 | + // Check if we had a fatal error last time while trying to start the session |
|
471 | + if ($this->sessionSaveHandlerFailed()) { |
|
472 | + // apparently, last time we tried using the custom session save handler there was a fatal |
|
473 | + if ($this->request->requestParamIsSet(SessionStartHandler::REQUEST_PARAM_RETRY_SESSION)) { |
|
474 | + if ($this->resetSessionSaveHandlerStatus() === false) { |
|
475 | + throw new ErrorException( |
|
476 | + esc_html__('Failed to reset session save handler status', 'event_espresso'), |
|
477 | + 0, |
|
478 | + E_WARNING, |
|
479 | + __FILE__, |
|
480 | + __LINE__ |
|
481 | + ); |
|
482 | + } |
|
483 | + // remove "ee_retry_session", otherwise if the problem still isn't fixed, |
|
484 | + // we'll just keep getting the fatal error over and over. |
|
485 | + // Better to remove it and redirect, and try on the next request |
|
486 | + EEH_URL::safeRedirectAndExit( |
|
487 | + remove_query_arg( |
|
488 | + [SessionStartHandler::REQUEST_PARAM_RETRY_SESSION], |
|
489 | + EEH_URL::current_url() |
|
490 | + ) |
|
491 | + ); |
|
492 | + } |
|
493 | + // so the session is broken, don't try it again, |
|
494 | + // just show a message to users that can fix it |
|
495 | + $this->displaySessionSaveHandlerErrorNotice(); |
|
496 | + return false; |
|
497 | + } |
|
498 | + return true; |
|
499 | + } |
|
500 | + |
|
501 | + |
|
502 | + /** |
|
503 | + * @since 4.9.68.p |
|
504 | + */ |
|
505 | + private function displaySessionSaveHandlerErrorNotice(): void |
|
506 | + { |
|
507 | + $retry_session_url = add_query_arg( |
|
508 | + [SessionStartHandler::REQUEST_PARAM_RETRY_SESSION => true], |
|
509 | + EEH_URL::current_url() |
|
510 | + ); |
|
511 | + $this->displaySessionErrorNotice( |
|
512 | + sprintf( |
|
513 | + esc_html__( |
|
514 | + 'It appears there was a fatal error while starting the session, so Event Espresso is not able to process registrations normally. Some hosting companies, like Pantheon, require an extra plugin for Event Espresso to work. Please install the %1$sWordPress Native PHP Sessions plugin%2$s, then %3$sclick here to check if the problem is resolved.%2$s', |
|
515 | + 'event_espresso' |
|
516 | + ), |
|
517 | + '<a href="https://wordpress.org/plugins/wp-native-php-sessions/">', |
|
518 | + '</a>', |
|
519 | + '<a href="' . $retry_session_url . '">' |
|
520 | + ), |
|
521 | + __FILE__, |
|
522 | + __FUNCTION__, |
|
523 | + __LINE__ |
|
524 | + ); |
|
525 | + } |
|
526 | + |
|
527 | + |
|
528 | + /** |
|
529 | + * Generates an EE_Error notice regarding the current session woes |
|
530 | + * but only if the current user is an admin with permission to 'install_plugins'. |
|
531 | + * |
|
532 | + * @since 5.0.46 |
|
533 | + */ |
|
534 | + private function displaySessionErrorNotice(string $message, string $file, string $function, int $line): void |
|
535 | + { |
|
536 | + if (current_user_can('install_plugins')) { |
|
537 | + EE_Error::add_error($message, $file, $function, $line); |
|
538 | + } |
|
539 | + } |
|
540 | 540 | } |
@@ -172,7 +172,7 @@ discard block |
||
172 | 172 | } |
173 | 173 | $this->save_path = $this->normalizeSessionSavePath($this->save_path); |
174 | 174 | // Use @-suppressed checks to avoid PHP warnings while validating. |
175 | - if (! @is_dir($this->save_path) || ! @is_writable($this->save_path)) { |
|
175 | + if ( ! @is_dir($this->save_path) || ! @is_writable($this->save_path)) { |
|
176 | 176 | throw new ErrorException( |
177 | 177 | sprintf( |
178 | 178 | esc_html__('Invalid or missing session save path: %s', 'event_espresso'), |
@@ -206,7 +206,7 @@ discard block |
||
206 | 206 | $session_save_path = sys_get_temp_dir(); |
207 | 207 | } |
208 | 208 | // normalize trailing separators |
209 | - $session_save_path = rtrim($session_save_path, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR; |
|
209 | + $session_save_path = rtrim($session_save_path, DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR; |
|
210 | 210 | // For 'files' handler we expect a writable filesystem directory. |
211 | 211 | // However, calling realpath() or is_dir() on paths outside of PHP's |
212 | 212 | // configured open_basedir can trigger warnings. |
@@ -240,7 +240,7 @@ discard block |
||
240 | 240 | continue; |
241 | 241 | } |
242 | 242 | // normalize trailing separators for comparison |
243 | - $allowed_path_norm = rtrim($allowed_path, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR; |
|
243 | + $allowed_path_norm = rtrim($allowed_path, DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR; |
|
244 | 244 | // compare start of paths for a match |
245 | 245 | if (strncmp($session_save_path, $allowed_path_norm, strlen($allowed_path_norm)) === 0) { |
246 | 246 | $allowed = true; |
@@ -303,7 +303,7 @@ discard block |
||
303 | 303 | } |
304 | 304 | // If not, then attempt to deal with any errors, |
305 | 305 | // otherwise, try to hobble along without the session |
306 | - if (! $this->handleSessionSaveHandlerErrors()) { |
|
306 | + if ( ! $this->handleSessionSaveHandlerErrors()) { |
|
307 | 307 | return; |
308 | 308 | } |
309 | 309 | // there is no record of a fatal error while trying to start the session |
@@ -516,7 +516,7 @@ discard block |
||
516 | 516 | ), |
517 | 517 | '<a href="https://wordpress.org/plugins/wp-native-php-sessions/">', |
518 | 518 | '</a>', |
519 | - '<a href="' . $retry_session_url . '">' |
|
519 | + '<a href="'.$retry_session_url.'">' |
|
520 | 520 | ), |
521 | 521 | __FILE__, |
522 | 522 | __FUNCTION__, |
@@ -13,19 +13,19 @@ |
||
13 | 13 | class AriaLiveAnnouncer |
14 | 14 | { |
15 | 15 | |
16 | - public static function setHooks() { |
|
17 | - add_action('wp_footer', [AriaLiveAnnouncer::class, 'ariaLiveRegion'], 9999); |
|
18 | - } |
|
16 | + public static function setHooks() { |
|
17 | + add_action('wp_footer', [AriaLiveAnnouncer::class, 'ariaLiveRegion'], 9999); |
|
18 | + } |
|
19 | 19 | |
20 | 20 | |
21 | - public static function ariaLiveRegion() |
|
22 | - { |
|
23 | - echo ' |
|
21 | + public static function ariaLiveRegion() |
|
22 | + { |
|
23 | + echo ' |
|
24 | 24 | <div id="espresso-aria-live-region" |
25 | 25 | class="screen-reader-text" |
26 | 26 | aria-live="polite" |
27 | 27 | aria-atomic="true" |
28 | 28 | ></div>'; |
29 | - } |
|
29 | + } |
|
30 | 30 | |
31 | 31 | } |
@@ -6,84 +6,84 @@ |
||
6 | 6 | |
7 | 7 | class IncompatibleAddonHandler |
8 | 8 | { |
9 | - public function deactivateIncompatibleAddons(): void |
|
10 | - { |
|
11 | - static $done = false; |
|
12 | - if ($done) { |
|
13 | - return; |
|
14 | - } |
|
15 | - $this->deactivateIncompatibleAddon( |
|
16 | - 'Wait Lists', |
|
17 | - 'EE_WAIT_LISTS_VERSION', |
|
18 | - '1.0.0.beta.074', |
|
19 | - 'load_espresso_wait_lists', |
|
20 | - 'EE_WAIT_LISTS_PLUGIN_FILE' |
|
21 | - ); |
|
22 | - $this->deactivateIncompatibleAddon( |
|
23 | - 'Automated Upcoming Event Notifications', |
|
24 | - 'EE_AUTOMATED_UPCOMING_EVENT_NOTIFICATION_VERSION', |
|
25 | - '1.0.0.beta.091', |
|
26 | - 'load_espresso_automated_upcoming_event_notification', |
|
27 | - 'EE_AUTOMATED_UPCOMING_EVENT_NOTIFICATION_PLUGIN_FILE' |
|
28 | - ); |
|
29 | - $this->deactivateIncompatibleAddon( |
|
30 | - 'Mailchimp Integration', |
|
31 | - 'ESPRESSO_MAILCHIMP_VERSION', |
|
32 | - '2.5.1.rc.009', |
|
33 | - 'load_ee4_espresso_mailchimp_class', |
|
34 | - 'ESPRESSO_MAILCHIMP_MAIN_FILE' |
|
35 | - ); |
|
36 | - // $this->deactivateIncompatibleAddon( |
|
37 | - // 'WP Users Integration', |
|
38 | - // 'EE_WPUSERS_VERSION', |
|
39 | - // '2.1.0.rc.003', |
|
40 | - // 'load_ee_core_wpusers', |
|
41 | - // 'EE_WPUSERS_PLUGIN_FILE' |
|
42 | - // ); |
|
43 | - $done = true; |
|
44 | - } |
|
9 | + public function deactivateIncompatibleAddons(): void |
|
10 | + { |
|
11 | + static $done = false; |
|
12 | + if ($done) { |
|
13 | + return; |
|
14 | + } |
|
15 | + $this->deactivateIncompatibleAddon( |
|
16 | + 'Wait Lists', |
|
17 | + 'EE_WAIT_LISTS_VERSION', |
|
18 | + '1.0.0.beta.074', |
|
19 | + 'load_espresso_wait_lists', |
|
20 | + 'EE_WAIT_LISTS_PLUGIN_FILE' |
|
21 | + ); |
|
22 | + $this->deactivateIncompatibleAddon( |
|
23 | + 'Automated Upcoming Event Notifications', |
|
24 | + 'EE_AUTOMATED_UPCOMING_EVENT_NOTIFICATION_VERSION', |
|
25 | + '1.0.0.beta.091', |
|
26 | + 'load_espresso_automated_upcoming_event_notification', |
|
27 | + 'EE_AUTOMATED_UPCOMING_EVENT_NOTIFICATION_PLUGIN_FILE' |
|
28 | + ); |
|
29 | + $this->deactivateIncompatibleAddon( |
|
30 | + 'Mailchimp Integration', |
|
31 | + 'ESPRESSO_MAILCHIMP_VERSION', |
|
32 | + '2.5.1.rc.009', |
|
33 | + 'load_ee4_espresso_mailchimp_class', |
|
34 | + 'ESPRESSO_MAILCHIMP_MAIN_FILE' |
|
35 | + ); |
|
36 | + // $this->deactivateIncompatibleAddon( |
|
37 | + // 'WP Users Integration', |
|
38 | + // 'EE_WPUSERS_VERSION', |
|
39 | + // '2.1.0.rc.003', |
|
40 | + // 'load_ee_core_wpusers', |
|
41 | + // 'EE_WPUSERS_PLUGIN_FILE' |
|
42 | + // ); |
|
43 | + $done = true; |
|
44 | + } |
|
45 | 45 | |
46 | 46 | |
47 | - /** |
|
48 | - * @param string $addon_name |
|
49 | - * @param string $version_constant |
|
50 | - * @param string $min_version_required |
|
51 | - * @param string $load_callback |
|
52 | - * @param string $plugin_file_constant |
|
53 | - * @return void |
|
54 | - */ |
|
55 | - private function deactivateIncompatibleAddon( |
|
56 | - string $addon_name, |
|
57 | - string $version_constant, |
|
58 | - string $min_version_required, |
|
59 | - string $load_callback, |
|
60 | - string $plugin_file_constant |
|
61 | - ): void { |
|
62 | - if (! defined($version_constant)) { |
|
63 | - return; |
|
64 | - } |
|
65 | - $addon_version = constant($version_constant); |
|
66 | - if ($addon_version && version_compare($addon_version, $min_version_required, '<')) { |
|
67 | - remove_action('AHEE__EE_System__load_espresso_addons', $load_callback); |
|
68 | - if (! function_exists('deactivate_plugins')) { |
|
69 | - require_once ABSPATH . 'wp-admin/includes/plugin.php'; |
|
70 | - } |
|
71 | - deactivate_plugins(plugin_basename(constant($plugin_file_constant))); |
|
72 | - unset($_GET['activate'], $_REQUEST['activate'], $_GET['activate-multi'], $_REQUEST['activate-multi']); |
|
73 | - EE_Error::add_error( |
|
74 | - sprintf( |
|
75 | - esc_html__( |
|
76 | - 'We\'re sorry, but the Event Espresso %1$s addon was deactivated because version %2$s or higher is required with this version of Event Espresso core.', |
|
77 | - 'event_espresso' |
|
78 | - ), |
|
79 | - $addon_name, |
|
80 | - $min_version_required |
|
81 | - ), |
|
82 | - __FILE__, |
|
83 | - __FUNCTION__ . "($addon_name)", |
|
84 | - __LINE__ |
|
85 | - ); |
|
86 | - EE_Error::get_notices(false, true); |
|
87 | - } |
|
88 | - } |
|
47 | + /** |
|
48 | + * @param string $addon_name |
|
49 | + * @param string $version_constant |
|
50 | + * @param string $min_version_required |
|
51 | + * @param string $load_callback |
|
52 | + * @param string $plugin_file_constant |
|
53 | + * @return void |
|
54 | + */ |
|
55 | + private function deactivateIncompatibleAddon( |
|
56 | + string $addon_name, |
|
57 | + string $version_constant, |
|
58 | + string $min_version_required, |
|
59 | + string $load_callback, |
|
60 | + string $plugin_file_constant |
|
61 | + ): void { |
|
62 | + if (! defined($version_constant)) { |
|
63 | + return; |
|
64 | + } |
|
65 | + $addon_version = constant($version_constant); |
|
66 | + if ($addon_version && version_compare($addon_version, $min_version_required, '<')) { |
|
67 | + remove_action('AHEE__EE_System__load_espresso_addons', $load_callback); |
|
68 | + if (! function_exists('deactivate_plugins')) { |
|
69 | + require_once ABSPATH . 'wp-admin/includes/plugin.php'; |
|
70 | + } |
|
71 | + deactivate_plugins(plugin_basename(constant($plugin_file_constant))); |
|
72 | + unset($_GET['activate'], $_REQUEST['activate'], $_GET['activate-multi'], $_REQUEST['activate-multi']); |
|
73 | + EE_Error::add_error( |
|
74 | + sprintf( |
|
75 | + esc_html__( |
|
76 | + 'We\'re sorry, but the Event Espresso %1$s addon was deactivated because version %2$s or higher is required with this version of Event Espresso core.', |
|
77 | + 'event_espresso' |
|
78 | + ), |
|
79 | + $addon_name, |
|
80 | + $min_version_required |
|
81 | + ), |
|
82 | + __FILE__, |
|
83 | + __FUNCTION__ . "($addon_name)", |
|
84 | + __LINE__ |
|
85 | + ); |
|
86 | + EE_Error::get_notices(false, true); |
|
87 | + } |
|
88 | + } |
|
89 | 89 | } |