@@ -116,7 +116,7 @@ discard block |
||
116 | 116 | $attributes['limit'] = (int) $attributes['limit']; |
117 | 117 | $display_on_archives = filter_var($attributes['display_on_archives'], FILTER_VALIDATE_BOOLEAN); |
118 | 118 | // don't display on archives unless 'display_on_archives' is true |
119 | - if ($attributes['limit'] === 0 || (! $display_on_archives && is_archive())) { |
|
119 | + if ($attributes['limit'] === 0 || ( ! $display_on_archives && is_archive())) { |
|
120 | 120 | return ''; |
121 | 121 | } |
122 | 122 | try { |
@@ -317,7 +317,7 @@ discard block |
||
317 | 317 | */ |
318 | 318 | private function getDatetime(array $attributes) |
319 | 319 | { |
320 | - if (! empty($attributes['datetime_id'])) { |
|
320 | + if ( ! empty($attributes['datetime_id'])) { |
|
321 | 321 | $datetime = EEM_Datetime::instance()->get_one_by_ID($attributes['datetime_id']); |
322 | 322 | if ($datetime instanceof EE_Datetime) { |
323 | 323 | return $datetime; |
@@ -337,7 +337,7 @@ discard block |
||
337 | 337 | */ |
338 | 338 | private function getTicket(array $attributes) |
339 | 339 | { |
340 | - if (! empty($attributes['ticket_id'])) { |
|
340 | + if ( ! empty($attributes['ticket_id'])) { |
|
341 | 341 | $ticket = EEM_Ticket::instance()->get_one_by_ID($attributes['ticket_id']); |
342 | 342 | if ($ticket instanceof EE_Ticket) { |
343 | 343 | return $ticket; |
@@ -354,7 +354,7 @@ discard block |
||
354 | 354 | private function setAdditionalQueryParams(array $attributes) |
355 | 355 | { |
356 | 356 | $reg_status_array = EEM_Registration::reg_status_array(); |
357 | - if (isset($reg_status_array[ $attributes['status'] ])) { |
|
357 | + if (isset($reg_status_array[$attributes['status']])) { |
|
358 | 358 | $this->query_params[0]['Registration.STS_ID'] = $attributes['status']; |
359 | 359 | } |
360 | 360 | if (absint($attributes['limit'])) { |
@@ -30,339 +30,339 @@ |
||
30 | 30 | */ |
31 | 31 | class EspressoEventAttendees extends EspressoShortcode |
32 | 32 | { |
33 | - private $query_params = array( |
|
34 | - 0 => array(), |
|
35 | - ); |
|
33 | + private $query_params = array( |
|
34 | + 0 => array(), |
|
35 | + ); |
|
36 | 36 | |
37 | - private $template_args = array( |
|
38 | - 'contacts' => array(), |
|
39 | - 'event' => null, |
|
40 | - 'datetime' => null, |
|
41 | - 'ticket' => null, |
|
42 | - ); |
|
37 | + private $template_args = array( |
|
38 | + 'contacts' => array(), |
|
39 | + 'event' => null, |
|
40 | + 'datetime' => null, |
|
41 | + 'ticket' => null, |
|
42 | + ); |
|
43 | 43 | |
44 | - /** |
|
45 | - * the actual shortcode tag that gets registered with WordPress |
|
46 | - * |
|
47 | - * @return string |
|
48 | - */ |
|
49 | - public function getTag() |
|
50 | - { |
|
51 | - return 'ESPRESSO_EVENT_ATTENDEES'; |
|
52 | - } |
|
44 | + /** |
|
45 | + * the actual shortcode tag that gets registered with WordPress |
|
46 | + * |
|
47 | + * @return string |
|
48 | + */ |
|
49 | + public function getTag() |
|
50 | + { |
|
51 | + return 'ESPRESSO_EVENT_ATTENDEES'; |
|
52 | + } |
|
53 | 53 | |
54 | 54 | |
55 | - /** |
|
56 | - * the time in seconds to cache the results of the processShortcode() method |
|
57 | - * 0 means the processShortcode() results will NOT be cached at all |
|
58 | - * |
|
59 | - * @return int |
|
60 | - */ |
|
61 | - public function cacheExpiration() |
|
62 | - { |
|
63 | - return 0; |
|
64 | - } |
|
55 | + /** |
|
56 | + * the time in seconds to cache the results of the processShortcode() method |
|
57 | + * 0 means the processShortcode() results will NOT be cached at all |
|
58 | + * |
|
59 | + * @return int |
|
60 | + */ |
|
61 | + public function cacheExpiration() |
|
62 | + { |
|
63 | + return 0; |
|
64 | + } |
|
65 | 65 | |
66 | 66 | |
67 | - /** |
|
68 | - * a place for adding any initialization code that needs to run prior to wp_header(). |
|
69 | - * this may be required for shortcodes that utilize a corresponding module, |
|
70 | - * and need to enqueue assets for that module |
|
71 | - * |
|
72 | - * @return void |
|
73 | - */ |
|
74 | - public function initializeShortcode() |
|
75 | - { |
|
76 | - $this->shortcodeHasBeenInitialized(); |
|
77 | - } |
|
67 | + /** |
|
68 | + * a place for adding any initialization code that needs to run prior to wp_header(). |
|
69 | + * this may be required for shortcodes that utilize a corresponding module, |
|
70 | + * and need to enqueue assets for that module |
|
71 | + * |
|
72 | + * @return void |
|
73 | + */ |
|
74 | + public function initializeShortcode() |
|
75 | + { |
|
76 | + $this->shortcodeHasBeenInitialized(); |
|
77 | + } |
|
78 | 78 | |
79 | 79 | |
80 | - /** |
|
81 | - * process_shortcode - ESPRESSO_EVENT_ATTENDEES - Returns a list of attendees to an event. |
|
82 | - * [ESPRESSO_EVENT_ATTENDEES] |
|
83 | - * - defaults to attendees for earliest active event, or earliest upcoming event. |
|
84 | - * [ESPRESSO_EVENT_ATTENDEES event_id=123] |
|
85 | - * - attendees for specific event. |
|
86 | - * [ESPRESSO_EVENT_ATTENDEES datetime_id=245] |
|
87 | - * - attendees for a specific datetime. |
|
88 | - * [ESPRESSO_EVENT_ATTENDEES ticket_id=123] |
|
89 | - * - attendees for a specific ticket. |
|
90 | - * [ESPRESSO_EVENT_ATTENDEES status=all] |
|
91 | - * - specific registration status (use status id) or all for all attendees regardless of status. |
|
92 | - * Note default is to only return approved attendees |
|
93 | - * [ESPRESSO_EVENT_ATTENDEES show_gravatar=true] |
|
94 | - * - default is to not return gravatar. Otherwise if this is set then return gravatar for email address given. |
|
95 | - * [ESPRESSO_EVENT_ATTENDEES display_on_archives=true] |
|
96 | - * - default is to not display attendees list on archive pages. |
|
97 | - * Note: because of the relationship between event_id, ticket_id, and datetime_id: |
|
98 | - * If more than one of those params is included, then preference is given to the following: |
|
99 | - * - event_id is used whenever its present and any others are ignored. |
|
100 | - * - if no event_id then datetime is used whenever its present and any others are ignored. |
|
101 | - * - otherwise ticket_id is used if present. |
|
102 | - * |
|
103 | - * @param array $attributes |
|
104 | - * @return string |
|
105 | - * @throws EE_Error |
|
106 | - * @throws InvalidDataTypeException |
|
107 | - * @throws InvalidInterfaceException |
|
108 | - * @throws InvalidArgumentException |
|
109 | - * @throws DomainException |
|
110 | - */ |
|
111 | - public function processShortcode($attributes = array()) |
|
112 | - { |
|
113 | - // grab attributes and merge with defaults |
|
114 | - $attributes = $this->getAttributes((array) $attributes); |
|
115 | - $attributes['limit'] = (int) $attributes['limit']; |
|
116 | - $display_on_archives = filter_var($attributes['display_on_archives'], FILTER_VALIDATE_BOOLEAN); |
|
117 | - // don't display on archives unless 'display_on_archives' is true |
|
118 | - if ($attributes['limit'] === 0 || (! $display_on_archives && is_archive())) { |
|
119 | - return ''; |
|
120 | - } |
|
121 | - try { |
|
122 | - $this->setBaseTemplateArguments($attributes); |
|
123 | - $this->validateEntities($attributes); |
|
124 | - $this->setBaseQueryParams(); |
|
125 | - } catch (EntityNotFoundException $e) { |
|
126 | - if (WP_DEBUG) { |
|
127 | - return '<div class="important-notice ee-error">' |
|
128 | - . $e->getMessage() |
|
129 | - . '</div>'; |
|
130 | - } |
|
131 | - return ''; |
|
132 | - } |
|
133 | - $this->setAdditionalQueryParams($attributes); |
|
134 | - // get contacts! |
|
135 | - $this->template_args['contacts'] = EEM_Attendee::instance()->get_all($this->query_params); |
|
136 | - // all set let's load up the template and return. |
|
137 | - return EEH_Template::locate_template( |
|
138 | - 'loop-espresso_event_attendees.php', |
|
139 | - $this->template_args |
|
140 | - ); |
|
141 | - } |
|
80 | + /** |
|
81 | + * process_shortcode - ESPRESSO_EVENT_ATTENDEES - Returns a list of attendees to an event. |
|
82 | + * [ESPRESSO_EVENT_ATTENDEES] |
|
83 | + * - defaults to attendees for earliest active event, or earliest upcoming event. |
|
84 | + * [ESPRESSO_EVENT_ATTENDEES event_id=123] |
|
85 | + * - attendees for specific event. |
|
86 | + * [ESPRESSO_EVENT_ATTENDEES datetime_id=245] |
|
87 | + * - attendees for a specific datetime. |
|
88 | + * [ESPRESSO_EVENT_ATTENDEES ticket_id=123] |
|
89 | + * - attendees for a specific ticket. |
|
90 | + * [ESPRESSO_EVENT_ATTENDEES status=all] |
|
91 | + * - specific registration status (use status id) or all for all attendees regardless of status. |
|
92 | + * Note default is to only return approved attendees |
|
93 | + * [ESPRESSO_EVENT_ATTENDEES show_gravatar=true] |
|
94 | + * - default is to not return gravatar. Otherwise if this is set then return gravatar for email address given. |
|
95 | + * [ESPRESSO_EVENT_ATTENDEES display_on_archives=true] |
|
96 | + * - default is to not display attendees list on archive pages. |
|
97 | + * Note: because of the relationship between event_id, ticket_id, and datetime_id: |
|
98 | + * If more than one of those params is included, then preference is given to the following: |
|
99 | + * - event_id is used whenever its present and any others are ignored. |
|
100 | + * - if no event_id then datetime is used whenever its present and any others are ignored. |
|
101 | + * - otherwise ticket_id is used if present. |
|
102 | + * |
|
103 | + * @param array $attributes |
|
104 | + * @return string |
|
105 | + * @throws EE_Error |
|
106 | + * @throws InvalidDataTypeException |
|
107 | + * @throws InvalidInterfaceException |
|
108 | + * @throws InvalidArgumentException |
|
109 | + * @throws DomainException |
|
110 | + */ |
|
111 | + public function processShortcode($attributes = array()) |
|
112 | + { |
|
113 | + // grab attributes and merge with defaults |
|
114 | + $attributes = $this->getAttributes((array) $attributes); |
|
115 | + $attributes['limit'] = (int) $attributes['limit']; |
|
116 | + $display_on_archives = filter_var($attributes['display_on_archives'], FILTER_VALIDATE_BOOLEAN); |
|
117 | + // don't display on archives unless 'display_on_archives' is true |
|
118 | + if ($attributes['limit'] === 0 || (! $display_on_archives && is_archive())) { |
|
119 | + return ''; |
|
120 | + } |
|
121 | + try { |
|
122 | + $this->setBaseTemplateArguments($attributes); |
|
123 | + $this->validateEntities($attributes); |
|
124 | + $this->setBaseQueryParams(); |
|
125 | + } catch (EntityNotFoundException $e) { |
|
126 | + if (WP_DEBUG) { |
|
127 | + return '<div class="important-notice ee-error">' |
|
128 | + . $e->getMessage() |
|
129 | + . '</div>'; |
|
130 | + } |
|
131 | + return ''; |
|
132 | + } |
|
133 | + $this->setAdditionalQueryParams($attributes); |
|
134 | + // get contacts! |
|
135 | + $this->template_args['contacts'] = EEM_Attendee::instance()->get_all($this->query_params); |
|
136 | + // all set let's load up the template and return. |
|
137 | + return EEH_Template::locate_template( |
|
138 | + 'loop-espresso_event_attendees.php', |
|
139 | + $this->template_args |
|
140 | + ); |
|
141 | + } |
|
142 | 142 | |
143 | 143 | |
144 | - /** |
|
145 | - * merge incoming attributes with filtered defaults |
|
146 | - * |
|
147 | - * @param array $attributes |
|
148 | - * @return array |
|
149 | - */ |
|
150 | - private function getAttributes(array $attributes) |
|
151 | - { |
|
152 | - return (array) apply_filters( |
|
153 | - 'EES_Espresso_Event_Attendees__process_shortcode__default_shortcode_atts', |
|
154 | - $attributes + array( |
|
155 | - 'event_id' => null, |
|
156 | - 'datetime_id' => null, |
|
157 | - 'ticket_id' => null, |
|
158 | - 'status' => EEM_Registration::status_id_approved, |
|
159 | - 'show_gravatar' => false, |
|
160 | - 'display_on_archives' => false, |
|
161 | - 'limit' => 999, |
|
162 | - ) |
|
163 | - ); |
|
164 | - } |
|
144 | + /** |
|
145 | + * merge incoming attributes with filtered defaults |
|
146 | + * |
|
147 | + * @param array $attributes |
|
148 | + * @return array |
|
149 | + */ |
|
150 | + private function getAttributes(array $attributes) |
|
151 | + { |
|
152 | + return (array) apply_filters( |
|
153 | + 'EES_Espresso_Event_Attendees__process_shortcode__default_shortcode_atts', |
|
154 | + $attributes + array( |
|
155 | + 'event_id' => null, |
|
156 | + 'datetime_id' => null, |
|
157 | + 'ticket_id' => null, |
|
158 | + 'status' => EEM_Registration::status_id_approved, |
|
159 | + 'show_gravatar' => false, |
|
160 | + 'display_on_archives' => false, |
|
161 | + 'limit' => 999, |
|
162 | + ) |
|
163 | + ); |
|
164 | + } |
|
165 | 165 | |
166 | 166 | |
167 | - /** |
|
168 | - * Set all the base template arguments from the incoming attributes. |
|
169 | - * * Note: because of the relationship between event_id, ticket_id, and datetime_id: |
|
170 | - * If more than one of those params is included, then preference is given to the following: |
|
171 | - * - event_id is used whenever its present and any others are ignored. |
|
172 | - * - if no event_id then datetime is used whenever its present and any others are ignored. |
|
173 | - * - otherwise ticket_id is used if present. |
|
174 | - * |
|
175 | - * @param array $attributes |
|
176 | - * @throws EE_Error |
|
177 | - * @throws InvalidDataTypeException |
|
178 | - * @throws InvalidInterfaceException |
|
179 | - * @throws InvalidArgumentException |
|
180 | - */ |
|
181 | - private function setBaseTemplateArguments(array $attributes) |
|
182 | - { |
|
183 | - $this->template_args['show_gravatar'] = $attributes['show_gravatar']; |
|
184 | - $this->template_args['event'] = $this->getEvent($attributes); |
|
185 | - $this->template_args['datetime'] = empty($attributes['event_id']) |
|
186 | - ? $this->getDatetime($attributes) |
|
187 | - : null; |
|
188 | - $this->template_args['ticket'] = empty($attributes['datetime_id']) && empty($attributes['event_id']) |
|
189 | - ? $this->getTicket($attributes) |
|
190 | - : null; |
|
191 | - } |
|
167 | + /** |
|
168 | + * Set all the base template arguments from the incoming attributes. |
|
169 | + * * Note: because of the relationship between event_id, ticket_id, and datetime_id: |
|
170 | + * If more than one of those params is included, then preference is given to the following: |
|
171 | + * - event_id is used whenever its present and any others are ignored. |
|
172 | + * - if no event_id then datetime is used whenever its present and any others are ignored. |
|
173 | + * - otherwise ticket_id is used if present. |
|
174 | + * |
|
175 | + * @param array $attributes |
|
176 | + * @throws EE_Error |
|
177 | + * @throws InvalidDataTypeException |
|
178 | + * @throws InvalidInterfaceException |
|
179 | + * @throws InvalidArgumentException |
|
180 | + */ |
|
181 | + private function setBaseTemplateArguments(array $attributes) |
|
182 | + { |
|
183 | + $this->template_args['show_gravatar'] = $attributes['show_gravatar']; |
|
184 | + $this->template_args['event'] = $this->getEvent($attributes); |
|
185 | + $this->template_args['datetime'] = empty($attributes['event_id']) |
|
186 | + ? $this->getDatetime($attributes) |
|
187 | + : null; |
|
188 | + $this->template_args['ticket'] = empty($attributes['datetime_id']) && empty($attributes['event_id']) |
|
189 | + ? $this->getTicket($attributes) |
|
190 | + : null; |
|
191 | + } |
|
192 | 192 | |
193 | 193 | |
194 | - /** |
|
195 | - * Validates the presence of entities for the given attribute values. |
|
196 | - * |
|
197 | - * @param array $attributes |
|
198 | - * @throws EntityNotFoundException |
|
199 | - */ |
|
200 | - private function validateEntities(array $attributes) |
|
201 | - { |
|
202 | - if ( |
|
203 | - ! $this->template_args['event'] instanceof EE_Event |
|
204 | - || ( |
|
205 | - empty($attributes['event_id']) |
|
206 | - && $attributes['datetime_id'] |
|
207 | - && ! $this->template_args['datetime'] instanceof EE_Datetime |
|
208 | - ) |
|
209 | - || ( |
|
210 | - empty($attributes['event_id']) |
|
211 | - && empty($attributes['datetime_id']) |
|
212 | - && $attributes['ticket_id'] |
|
213 | - && ! $this->template_args['ticket'] instanceof EE_Ticket |
|
214 | - ) |
|
215 | - ) { |
|
216 | - throw new EntityNotFoundException( |
|
217 | - '', |
|
218 | - '', |
|
219 | - esc_html__( |
|
220 | - 'The [ESPRESSO_EVENT_ATTENDEES] shortcode has been used incorrectly. Please double check the arguments you used for any typos. In the case of ID type arguments, its possible the given ID does not correspond to existing data in the database.', |
|
221 | - 'event_espresso' |
|
222 | - ) |
|
223 | - ); |
|
224 | - } |
|
225 | - } |
|
194 | + /** |
|
195 | + * Validates the presence of entities for the given attribute values. |
|
196 | + * |
|
197 | + * @param array $attributes |
|
198 | + * @throws EntityNotFoundException |
|
199 | + */ |
|
200 | + private function validateEntities(array $attributes) |
|
201 | + { |
|
202 | + if ( |
|
203 | + ! $this->template_args['event'] instanceof EE_Event |
|
204 | + || ( |
|
205 | + empty($attributes['event_id']) |
|
206 | + && $attributes['datetime_id'] |
|
207 | + && ! $this->template_args['datetime'] instanceof EE_Datetime |
|
208 | + ) |
|
209 | + || ( |
|
210 | + empty($attributes['event_id']) |
|
211 | + && empty($attributes['datetime_id']) |
|
212 | + && $attributes['ticket_id'] |
|
213 | + && ! $this->template_args['ticket'] instanceof EE_Ticket |
|
214 | + ) |
|
215 | + ) { |
|
216 | + throw new EntityNotFoundException( |
|
217 | + '', |
|
218 | + '', |
|
219 | + esc_html__( |
|
220 | + 'The [ESPRESSO_EVENT_ATTENDEES] shortcode has been used incorrectly. Please double check the arguments you used for any typos. In the case of ID type arguments, its possible the given ID does not correspond to existing data in the database.', |
|
221 | + 'event_espresso' |
|
222 | + ) |
|
223 | + ); |
|
224 | + } |
|
225 | + } |
|
226 | 226 | |
227 | 227 | |
228 | - /** |
|
229 | - * Sets the query params for the base query elements. |
|
230 | - */ |
|
231 | - private function setBaseQueryParams() |
|
232 | - { |
|
233 | - switch (true) { |
|
234 | - case $this->template_args['datetime'] instanceof EE_Datetime: |
|
235 | - $this->query_params = array( |
|
236 | - 0 => array( |
|
237 | - 'Registration.Ticket.Datetime.DTT_ID' => $this->template_args['datetime']->ID(), |
|
238 | - ), |
|
239 | - 'default_where_conditions' => 'this_model_only', |
|
240 | - ); |
|
241 | - break; |
|
242 | - case $this->template_args['ticket'] instanceof EE_Ticket: |
|
243 | - $this->query_params[0] = array( |
|
244 | - 'Registration.TKT_ID' => $this->template_args['ticket']->ID(), |
|
245 | - ); |
|
246 | - break; |
|
247 | - case $this->template_args['event'] instanceof EE_Event: |
|
248 | - $this->query_params[0] = array( |
|
249 | - 'Registration.EVT_ID' => $this->template_args['event']->ID(), |
|
250 | - ); |
|
251 | - break; |
|
252 | - } |
|
253 | - } |
|
228 | + /** |
|
229 | + * Sets the query params for the base query elements. |
|
230 | + */ |
|
231 | + private function setBaseQueryParams() |
|
232 | + { |
|
233 | + switch (true) { |
|
234 | + case $this->template_args['datetime'] instanceof EE_Datetime: |
|
235 | + $this->query_params = array( |
|
236 | + 0 => array( |
|
237 | + 'Registration.Ticket.Datetime.DTT_ID' => $this->template_args['datetime']->ID(), |
|
238 | + ), |
|
239 | + 'default_where_conditions' => 'this_model_only', |
|
240 | + ); |
|
241 | + break; |
|
242 | + case $this->template_args['ticket'] instanceof EE_Ticket: |
|
243 | + $this->query_params[0] = array( |
|
244 | + 'Registration.TKT_ID' => $this->template_args['ticket']->ID(), |
|
245 | + ); |
|
246 | + break; |
|
247 | + case $this->template_args['event'] instanceof EE_Event: |
|
248 | + $this->query_params[0] = array( |
|
249 | + 'Registration.EVT_ID' => $this->template_args['event']->ID(), |
|
250 | + ); |
|
251 | + break; |
|
252 | + } |
|
253 | + } |
|
254 | 254 | |
255 | 255 | |
256 | - /** |
|
257 | - * @param array $attributes |
|
258 | - * @return EE_Event|null |
|
259 | - * @throws EE_Error |
|
260 | - * @throws InvalidDataTypeException |
|
261 | - * @throws InvalidInterfaceException |
|
262 | - * @throws InvalidArgumentException |
|
263 | - */ |
|
264 | - private function getEvent(array $attributes) |
|
265 | - { |
|
266 | - switch (true) { |
|
267 | - case ! empty($attributes['event_id']): |
|
268 | - $event = EEM_Event::instance()->get_one_by_ID($attributes['event_id']); |
|
269 | - break; |
|
270 | - case ! empty($attributes['datetime_id']): |
|
271 | - $event = EEM_Event::instance()->get_one(array( |
|
272 | - array( |
|
273 | - 'Datetime.DTT_ID' => $attributes['datetime_id'], |
|
274 | - ), |
|
275 | - )); |
|
276 | - break; |
|
277 | - case ! empty($attributes['ticket_id']): |
|
278 | - $event = EEM_Event::instance()->get_one(array( |
|
279 | - array( |
|
280 | - 'Datetime.Ticket.TKT_ID' => $attributes['ticket_id'], |
|
281 | - ), |
|
282 | - 'default_where_conditions' => 'none' |
|
283 | - )); |
|
284 | - break; |
|
285 | - case is_espresso_event(): |
|
286 | - $event = EEH_Event_View::get_event(); |
|
287 | - break; |
|
288 | - default: |
|
289 | - // one last shot... |
|
290 | - // try getting the earliest active event |
|
291 | - $events = EEM_Event::instance()->get_active_events(array( |
|
292 | - 'limit' => 1, |
|
293 | - 'order_by' => array('Datetime.DTT_EVT_start' => 'ASC'), |
|
294 | - )); |
|
295 | - // if none then get the next upcoming |
|
296 | - $events = empty($events) |
|
297 | - ? EEM_Event::instance()->get_upcoming_events(array( |
|
298 | - 'limit' => 1, |
|
299 | - 'order_by' => array('Datetime.DTT_EVT_start' => 'ASC'), |
|
300 | - )) |
|
301 | - : $events; |
|
302 | - $event = reset($events); |
|
303 | - } |
|
256 | + /** |
|
257 | + * @param array $attributes |
|
258 | + * @return EE_Event|null |
|
259 | + * @throws EE_Error |
|
260 | + * @throws InvalidDataTypeException |
|
261 | + * @throws InvalidInterfaceException |
|
262 | + * @throws InvalidArgumentException |
|
263 | + */ |
|
264 | + private function getEvent(array $attributes) |
|
265 | + { |
|
266 | + switch (true) { |
|
267 | + case ! empty($attributes['event_id']): |
|
268 | + $event = EEM_Event::instance()->get_one_by_ID($attributes['event_id']); |
|
269 | + break; |
|
270 | + case ! empty($attributes['datetime_id']): |
|
271 | + $event = EEM_Event::instance()->get_one(array( |
|
272 | + array( |
|
273 | + 'Datetime.DTT_ID' => $attributes['datetime_id'], |
|
274 | + ), |
|
275 | + )); |
|
276 | + break; |
|
277 | + case ! empty($attributes['ticket_id']): |
|
278 | + $event = EEM_Event::instance()->get_one(array( |
|
279 | + array( |
|
280 | + 'Datetime.Ticket.TKT_ID' => $attributes['ticket_id'], |
|
281 | + ), |
|
282 | + 'default_where_conditions' => 'none' |
|
283 | + )); |
|
284 | + break; |
|
285 | + case is_espresso_event(): |
|
286 | + $event = EEH_Event_View::get_event(); |
|
287 | + break; |
|
288 | + default: |
|
289 | + // one last shot... |
|
290 | + // try getting the earliest active event |
|
291 | + $events = EEM_Event::instance()->get_active_events(array( |
|
292 | + 'limit' => 1, |
|
293 | + 'order_by' => array('Datetime.DTT_EVT_start' => 'ASC'), |
|
294 | + )); |
|
295 | + // if none then get the next upcoming |
|
296 | + $events = empty($events) |
|
297 | + ? EEM_Event::instance()->get_upcoming_events(array( |
|
298 | + 'limit' => 1, |
|
299 | + 'order_by' => array('Datetime.DTT_EVT_start' => 'ASC'), |
|
300 | + )) |
|
301 | + : $events; |
|
302 | + $event = reset($events); |
|
303 | + } |
|
304 | 304 | |
305 | - return $event instanceof EE_Event ? $event : null; |
|
306 | - } |
|
305 | + return $event instanceof EE_Event ? $event : null; |
|
306 | + } |
|
307 | 307 | |
308 | 308 | |
309 | - /** |
|
310 | - * @param array $attributes |
|
311 | - * @return EE_Datetime|null |
|
312 | - * @throws EE_Error |
|
313 | - * @throws InvalidDataTypeException |
|
314 | - * @throws InvalidInterfaceException |
|
315 | - * @throws InvalidArgumentException |
|
316 | - */ |
|
317 | - private function getDatetime(array $attributes) |
|
318 | - { |
|
319 | - if (! empty($attributes['datetime_id'])) { |
|
320 | - $datetime = EEM_Datetime::instance()->get_one_by_ID($attributes['datetime_id']); |
|
321 | - if ($datetime instanceof EE_Datetime) { |
|
322 | - return $datetime; |
|
323 | - } |
|
324 | - } |
|
325 | - return null; |
|
326 | - } |
|
309 | + /** |
|
310 | + * @param array $attributes |
|
311 | + * @return EE_Datetime|null |
|
312 | + * @throws EE_Error |
|
313 | + * @throws InvalidDataTypeException |
|
314 | + * @throws InvalidInterfaceException |
|
315 | + * @throws InvalidArgumentException |
|
316 | + */ |
|
317 | + private function getDatetime(array $attributes) |
|
318 | + { |
|
319 | + if (! empty($attributes['datetime_id'])) { |
|
320 | + $datetime = EEM_Datetime::instance()->get_one_by_ID($attributes['datetime_id']); |
|
321 | + if ($datetime instanceof EE_Datetime) { |
|
322 | + return $datetime; |
|
323 | + } |
|
324 | + } |
|
325 | + return null; |
|
326 | + } |
|
327 | 327 | |
328 | 328 | |
329 | - /** |
|
330 | - * @param array $attributes |
|
331 | - * @return \EE_Base_Class|EE_Ticket|null |
|
332 | - * @throws EE_Error |
|
333 | - * @throws InvalidDataTypeException |
|
334 | - * @throws InvalidInterfaceException |
|
335 | - * @throws InvalidArgumentException |
|
336 | - */ |
|
337 | - private function getTicket(array $attributes) |
|
338 | - { |
|
339 | - if (! empty($attributes['ticket_id'])) { |
|
340 | - $ticket = EEM_Ticket::instance()->get_one_by_ID($attributes['ticket_id']); |
|
341 | - if ($ticket instanceof EE_Ticket) { |
|
342 | - return $ticket; |
|
343 | - } |
|
344 | - } |
|
345 | - return null; |
|
346 | - } |
|
329 | + /** |
|
330 | + * @param array $attributes |
|
331 | + * @return \EE_Base_Class|EE_Ticket|null |
|
332 | + * @throws EE_Error |
|
333 | + * @throws InvalidDataTypeException |
|
334 | + * @throws InvalidInterfaceException |
|
335 | + * @throws InvalidArgumentException |
|
336 | + */ |
|
337 | + private function getTicket(array $attributes) |
|
338 | + { |
|
339 | + if (! empty($attributes['ticket_id'])) { |
|
340 | + $ticket = EEM_Ticket::instance()->get_one_by_ID($attributes['ticket_id']); |
|
341 | + if ($ticket instanceof EE_Ticket) { |
|
342 | + return $ticket; |
|
343 | + } |
|
344 | + } |
|
345 | + return null; |
|
346 | + } |
|
347 | 347 | |
348 | 348 | |
349 | - /** |
|
350 | - * @param array $attributes |
|
351 | - * @throws EE_Error |
|
352 | - */ |
|
353 | - private function setAdditionalQueryParams(array $attributes) |
|
354 | - { |
|
355 | - $reg_status_array = EEM_Registration::reg_status_array(); |
|
356 | - if (isset($reg_status_array[ $attributes['status'] ])) { |
|
357 | - $this->query_params[0]['Registration.STS_ID'] = $attributes['status']; |
|
358 | - } |
|
359 | - if (absint($attributes['limit'])) { |
|
360 | - $this->query_params['limit'] = $attributes['limit']; |
|
361 | - } |
|
362 | - $this->query_params['group_by'] = array('ATT_ID'); |
|
363 | - $this->query_params['order_by'] = (array) apply_filters( |
|
364 | - 'FHEE__EES_Espresso_Event_Attendees__process_shortcode__order_by', |
|
365 | - array('ATT_lname' => 'ASC', 'ATT_fname' => 'ASC') |
|
366 | - ); |
|
367 | - } |
|
349 | + /** |
|
350 | + * @param array $attributes |
|
351 | + * @throws EE_Error |
|
352 | + */ |
|
353 | + private function setAdditionalQueryParams(array $attributes) |
|
354 | + { |
|
355 | + $reg_status_array = EEM_Registration::reg_status_array(); |
|
356 | + if (isset($reg_status_array[ $attributes['status'] ])) { |
|
357 | + $this->query_params[0]['Registration.STS_ID'] = $attributes['status']; |
|
358 | + } |
|
359 | + if (absint($attributes['limit'])) { |
|
360 | + $this->query_params['limit'] = $attributes['limit']; |
|
361 | + } |
|
362 | + $this->query_params['group_by'] = array('ATT_ID'); |
|
363 | + $this->query_params['order_by'] = (array) apply_filters( |
|
364 | + 'FHEE__EES_Espresso_Event_Attendees__process_shortcode__order_by', |
|
365 | + array('ATT_lname' => 'ASC', 'ATT_fname' => 'ASC') |
|
366 | + ); |
|
367 | + } |
|
368 | 368 | } |
@@ -128,7 +128,7 @@ discard block |
||
128 | 128 | if (is_array($this->_CPTs)) { |
129 | 129 | foreach ($this->_CPTs as $CPT_type => $CPT) { |
130 | 130 | if (isset($CPT['plural_slug'])) { |
131 | - $_CPT_endpoints [ (string) $CPT['plural_slug'] ] = $CPT_type; |
|
131 | + $_CPT_endpoints [(string) $CPT['plural_slug']] = $CPT_type; |
|
132 | 132 | } |
133 | 133 | } |
134 | 134 | } |
@@ -151,7 +151,7 @@ discard block |
||
151 | 151 | public function pre_get_posts($WP_Query) |
152 | 152 | { |
153 | 153 | // check that post-type is set |
154 | - if (! $WP_Query instanceof WP_Query) { |
|
154 | + if ( ! $WP_Query instanceof WP_Query) { |
|
155 | 155 | return; |
156 | 156 | } |
157 | 157 | // add our conditionals |
@@ -195,7 +195,7 @@ discard block |
||
195 | 195 | $terms = EEM_Term::instance()->get_all_CPT_post_tags(); |
196 | 196 | foreach ($terms as $term) { |
197 | 197 | if ($term instanceof EE_Term) { |
198 | - $this->_CPT_terms[ $term->slug() ] = $term; |
|
198 | + $this->_CPT_terms[$term->slug()] = $term; |
|
199 | 199 | } |
200 | 200 | } |
201 | 201 | } |
@@ -260,7 +260,7 @@ discard block |
||
260 | 260 | // loop thru our taxonomies |
261 | 261 | foreach ($this->_CPT_taxonomies as $CPT_taxonomy => $CPT_taxonomy_details) { |
262 | 262 | // check if one of our taxonomies is set as a query var |
263 | - if (isset($WP_Query->query[ $CPT_taxonomy ])) { |
|
263 | + if (isset($WP_Query->query[$CPT_taxonomy])) { |
|
264 | 264 | // but which CPT does that correspond to??? hmmm... guess we gotta go looping |
265 | 265 | foreach ($this->_CPTs as $post_type => $CPT) { |
266 | 266 | // verify our CPT has args, is public and has taxonomies set |
@@ -284,7 +284,7 @@ discard block |
||
284 | 284 | break; |
285 | 285 | default: |
286 | 286 | do_action( |
287 | - 'AHEE__EE_CPT_Strategy___set_CPT_taxonomies_on_WP_Query__for_' . $post_type . '_post_type', |
|
287 | + 'AHEE__EE_CPT_Strategy___set_CPT_taxonomies_on_WP_Query__for_'.$post_type.'_post_type', |
|
288 | 288 | $WP_Query, |
289 | 289 | $this |
290 | 290 | ); |
@@ -309,11 +309,11 @@ discard block |
||
309 | 309 | // loop thru post_types as array |
310 | 310 | foreach ((array) $WP_Query->query_vars['post_type'] as $post_type) { |
311 | 311 | // is current query for an EE CPT ? |
312 | - if (isset($this->_CPTs[ $post_type ])) { |
|
312 | + if (isset($this->_CPTs[$post_type])) { |
|
313 | 313 | // is EE on or off ? |
314 | 314 | if (EE_Maintenance_Mode::instance()->level()) { |
315 | 315 | // reroute CPT template view to maintenance_mode.template.php |
316 | - if (! has_filter('template_include', array('EE_Maintenance_Mode', 'template_include'))) { |
|
316 | + if ( ! has_filter('template_include', array('EE_Maintenance_Mode', 'template_include'))) { |
|
317 | 317 | add_filter('template_include', array('EE_Maintenance_Mode', 'template_include'), 99999); |
318 | 318 | } |
319 | 319 | if (has_filter('the_content', array(EE_Maintenance_Mode::instance(), 'the_content'))) { |
@@ -341,7 +341,7 @@ discard block |
||
341 | 341 | 'EventEspresso\core\CPTs\CptQueryModifier', |
342 | 342 | array( |
343 | 343 | $post_type, |
344 | - $this->_CPTs[ $post_type ], |
|
344 | + $this->_CPTs[$post_type], |
|
345 | 345 | $WP_Query, |
346 | 346 | ) |
347 | 347 | ); |
@@ -15,449 +15,449 @@ |
||
15 | 15 | */ |
16 | 16 | class EE_CPT_Strategy extends EE_Base |
17 | 17 | { |
18 | - /** |
|
19 | - * @var EE_CPT_Strategy $_instance |
|
20 | - */ |
|
21 | - private static $_instance; |
|
22 | - |
|
23 | - /** |
|
24 | - * the current page, if it utilizes CPTs |
|
25 | - * |
|
26 | - * @var array $CPT |
|
27 | - */ |
|
28 | - protected $CPT; |
|
29 | - |
|
30 | - /** |
|
31 | - * return value from CustomPostTypeDefinitions::getDefinitions() |
|
32 | - * |
|
33 | - * @var array $_CPTs |
|
34 | - */ |
|
35 | - protected $_CPTs = array(); |
|
36 | - |
|
37 | - /** |
|
38 | - * @var array $_CPT_taxonomies |
|
39 | - */ |
|
40 | - protected $_CPT_taxonomies = array(); |
|
41 | - |
|
42 | - /** |
|
43 | - * @var array $_CPT_terms |
|
44 | - */ |
|
45 | - protected $_CPT_terms = array(); |
|
46 | - |
|
47 | - /** |
|
48 | - * @var array $_CPT_endpoints |
|
49 | - */ |
|
50 | - protected $_CPT_endpoints = array(); |
|
51 | - |
|
52 | - /** |
|
53 | - * @var EEM_Base $CPT_model |
|
54 | - */ |
|
55 | - protected $CPT_model; |
|
56 | - |
|
57 | - /** |
|
58 | - * @var EventEspresso\Core\CPTs\CptQueryModifier $query_modifier |
|
59 | - */ |
|
60 | - protected $query_modifier; |
|
61 | - |
|
62 | - |
|
63 | - /** |
|
64 | - * @singleton method used to instantiate class object |
|
65 | - * @param CustomPostTypeDefinitions|null $custom_post_types |
|
66 | - * @param CustomTaxonomyDefinitions|null $taxonomies |
|
67 | - * @return EE_CPT_Strategy |
|
68 | - */ |
|
69 | - public static function instance( |
|
70 | - CustomPostTypeDefinitions $custom_post_types = null, |
|
71 | - CustomTaxonomyDefinitions $taxonomies = null |
|
72 | - ) { |
|
73 | - // check if class object is instantiated |
|
74 | - if ( |
|
75 | - ! self::$_instance instanceof EE_CPT_Strategy |
|
76 | - && $custom_post_types instanceof CustomPostTypeDefinitions |
|
77 | - && $taxonomies instanceof CustomTaxonomyDefinitions |
|
78 | - ) { |
|
79 | - self::$_instance = new self($custom_post_types, $taxonomies); |
|
80 | - } |
|
81 | - return self::$_instance; |
|
82 | - } |
|
83 | - |
|
84 | - |
|
85 | - /** |
|
86 | - * @param CustomPostTypeDefinitions $custom_post_types |
|
87 | - * @param CustomTaxonomyDefinitions $taxonomies |
|
88 | - */ |
|
89 | - protected function __construct( |
|
90 | - CustomPostTypeDefinitions $custom_post_types, |
|
91 | - CustomTaxonomyDefinitions $taxonomies |
|
92 | - ) { |
|
93 | - // get CPT data |
|
94 | - $this->_CPTs = $custom_post_types->getDefinitions(); |
|
95 | - $this->_CPT_endpoints = $this->_set_CPT_endpoints(); |
|
96 | - $this->_CPT_taxonomies = $taxonomies->getCustomTaxonomyDefinitions(); |
|
97 | - add_action('pre_get_posts', array($this, 'pre_get_posts'), 5); |
|
98 | - } |
|
99 | - |
|
100 | - |
|
101 | - /** |
|
102 | - * @return array |
|
103 | - */ |
|
104 | - public function get_CPT_endpoints() |
|
105 | - { |
|
106 | - return $this->_CPT_endpoints; |
|
107 | - } |
|
108 | - |
|
109 | - |
|
110 | - /** |
|
111 | - * @return array |
|
112 | - */ |
|
113 | - public function get_CPT_taxonomies() |
|
114 | - { |
|
115 | - return $this->_CPT_taxonomies; |
|
116 | - } |
|
117 | - |
|
118 | - |
|
119 | - /** |
|
120 | - * add CPT "slugs" to array of default espresso "pages" |
|
121 | - * |
|
122 | - * @return array |
|
123 | - */ |
|
124 | - private function _set_CPT_endpoints() |
|
125 | - { |
|
126 | - $_CPT_endpoints = array(); |
|
127 | - if (is_array($this->_CPTs)) { |
|
128 | - foreach ($this->_CPTs as $CPT_type => $CPT) { |
|
129 | - if (isset($CPT['plural_slug'])) { |
|
130 | - $_CPT_endpoints [ (string) $CPT['plural_slug'] ] = $CPT_type; |
|
131 | - } |
|
132 | - } |
|
133 | - } |
|
134 | - return $_CPT_endpoints; |
|
135 | - } |
|
136 | - |
|
137 | - |
|
138 | - /** |
|
139 | - * If this query (not just "main" queries (ie, for WP's infamous "loop")) is for an EE CPT, then we want to |
|
140 | - * supercharge the get_posts query to add our EE stuff (like joining to our tables, selecting extra columns, and |
|
141 | - * adding EE objects to the post to facilitate further querying of related data etc) |
|
142 | - * |
|
143 | - * @param WP_Query $WP_Query |
|
144 | - * @return void |
|
145 | - * @throws \EE_Error |
|
146 | - * @throws \InvalidArgumentException |
|
147 | - * @throws \EventEspresso\core\exceptions\InvalidInterfaceException |
|
148 | - * @throws \EventEspresso\core\exceptions\InvalidDataTypeException |
|
149 | - */ |
|
150 | - public function pre_get_posts($WP_Query) |
|
151 | - { |
|
152 | - // check that post-type is set |
|
153 | - if (! $WP_Query instanceof WP_Query) { |
|
154 | - return; |
|
155 | - } |
|
156 | - // add our conditionals |
|
157 | - $this->_set_EE_tags_on_WP_Query($WP_Query); |
|
158 | - // check for terms |
|
159 | - $this->_set_post_type_for_terms($WP_Query); |
|
160 | - // make sure paging is always set |
|
161 | - $this->_set_paging($WP_Query); |
|
162 | - // is a taxonomy set ? |
|
163 | - $this->_set_CPT_taxonomies_on_WP_Query($WP_Query); |
|
164 | - // loop thru post_types if set |
|
165 | - $this->_process_WP_Query_post_types($WP_Query); |
|
166 | - } |
|
167 | - |
|
168 | - |
|
169 | - /** |
|
170 | - * @param WP_Query $WP_Query |
|
171 | - * @return void |
|
172 | - */ |
|
173 | - private function _set_EE_tags_on_WP_Query(WP_Query $WP_Query) |
|
174 | - { |
|
175 | - $WP_Query->is_espresso_event_single = false; |
|
176 | - $WP_Query->is_espresso_event_archive = false; |
|
177 | - $WP_Query->is_espresso_event_taxonomy = false; |
|
178 | - $WP_Query->is_espresso_venue_single = false; |
|
179 | - $WP_Query->is_espresso_venue_archive = false; |
|
180 | - $WP_Query->is_espresso_venue_taxonomy = false; |
|
181 | - } |
|
182 | - |
|
183 | - |
|
184 | - /** |
|
185 | - * @return void |
|
186 | - * @throws EE_Error |
|
187 | - * @throws InvalidArgumentException |
|
188 | - * @throws InvalidDataTypeException |
|
189 | - * @throws InvalidInterfaceException |
|
190 | - */ |
|
191 | - private function _set_CPT_terms() |
|
192 | - { |
|
193 | - if (empty($this->_CPT_terms)) { |
|
194 | - $terms = EEM_Term::instance()->get_all_CPT_post_tags(); |
|
195 | - foreach ($terms as $term) { |
|
196 | - if ($term instanceof EE_Term) { |
|
197 | - $this->_CPT_terms[ $term->slug() ] = $term; |
|
198 | - } |
|
199 | - } |
|
200 | - } |
|
201 | - } |
|
202 | - |
|
203 | - |
|
204 | - /** |
|
205 | - * @param WP_Query $WP_Query |
|
206 | - * @return void |
|
207 | - * @throws EE_Error |
|
208 | - * @throws InvalidArgumentException |
|
209 | - * @throws InvalidDataTypeException |
|
210 | - * @throws InvalidInterfaceException |
|
211 | - */ |
|
212 | - private function _set_post_type_for_terms(WP_Query $WP_Query) |
|
213 | - { |
|
214 | - // is a tag set ? |
|
215 | - if (isset($WP_Query->query['tag'])) { |
|
216 | - // get term for tag |
|
217 | - $term = EEM_Term::instance()->get_post_tag_for_event_or_venue($WP_Query->query['tag']); |
|
218 | - // verify the term |
|
219 | - if ($term instanceof EE_Term) { |
|
220 | - $term->post_type = array_merge(array('post', 'page'), (array) $term->post_type); |
|
221 | - $term->post_type = apply_filters( |
|
222 | - 'FHEE__EE_CPT_Strategy___set_post_type_for_terms__term_post_type', |
|
223 | - $term->post_type, |
|
224 | - $term |
|
225 | - ); |
|
226 | - // if a post type is already set |
|
227 | - if (isset($WP_Query->query_vars['post_type'])) { |
|
228 | - // add to existing array |
|
229 | - $term->post_type = array_merge((array) $WP_Query->query_vars['post_type'], $term->post_type); |
|
230 | - } |
|
231 | - // just set post_type to our CPT |
|
232 | - $WP_Query->set('post_type', array_unique($term->post_type)); |
|
233 | - } |
|
234 | - } |
|
235 | - } |
|
236 | - |
|
237 | - |
|
238 | - /** |
|
239 | - * @param WP_Query $WP_Query |
|
240 | - * @return void |
|
241 | - */ |
|
242 | - public function _set_paging($WP_Query) |
|
243 | - { |
|
244 | - if ($WP_Query->is_main_query() && apply_filters('FHEE__EE_CPT_Strategy___set_paging', true)) { |
|
245 | - $page = get_query_var('page') ? get_query_var('page') : null; |
|
246 | - $paged = get_query_var('paged') ? get_query_var('paged') : $page; |
|
247 | - $WP_Query->set('paged', $paged); |
|
248 | - } |
|
249 | - } |
|
250 | - |
|
251 | - |
|
252 | - /** |
|
253 | - * @param \WP_Query $WP_Query |
|
254 | - */ |
|
255 | - protected function _set_CPT_taxonomies_on_WP_Query(WP_Query $WP_Query) |
|
256 | - { |
|
257 | - // is a taxonomy set ? |
|
258 | - if ($WP_Query->is_tax) { |
|
259 | - // loop thru our taxonomies |
|
260 | - foreach ($this->_CPT_taxonomies as $CPT_taxonomy => $CPT_taxonomy_details) { |
|
261 | - // check if one of our taxonomies is set as a query var |
|
262 | - if (isset($WP_Query->query[ $CPT_taxonomy ])) { |
|
263 | - // but which CPT does that correspond to??? hmmm... guess we gotta go looping |
|
264 | - foreach ($this->_CPTs as $post_type => $CPT) { |
|
265 | - // verify our CPT has args, is public and has taxonomies set |
|
266 | - if ( |
|
267 | - isset($CPT['args']['public']) |
|
268 | - && $CPT['args']['public'] |
|
269 | - && ! empty($CPT['args']['taxonomies']) |
|
270 | - && in_array($CPT_taxonomy, $CPT['args']['taxonomies'], true) |
|
271 | - ) { |
|
272 | - // if so, then add this CPT post_type to the current query's array of post_types' |
|
273 | - $WP_Query->query_vars['post_type'] = isset($WP_Query->query_vars['post_type']) |
|
274 | - ? (array) $WP_Query->query_vars['post_type'] |
|
275 | - : array(); |
|
276 | - $WP_Query->query_vars['post_type'][] = $post_type; |
|
277 | - switch ($post_type) { |
|
278 | - case 'espresso_events': |
|
279 | - $WP_Query->is_espresso_event_taxonomy = true; |
|
280 | - break; |
|
281 | - case 'espresso_venues': |
|
282 | - $WP_Query->is_espresso_venue_taxonomy = true; |
|
283 | - break; |
|
284 | - default: |
|
285 | - do_action( |
|
286 | - 'AHEE__EE_CPT_Strategy___set_CPT_taxonomies_on_WP_Query__for_' . $post_type . '_post_type', |
|
287 | - $WP_Query, |
|
288 | - $this |
|
289 | - ); |
|
290 | - } |
|
291 | - } |
|
292 | - } |
|
293 | - } |
|
294 | - } |
|
295 | - } |
|
296 | - } |
|
297 | - |
|
298 | - |
|
299 | - /** |
|
300 | - * @param \WP_Query $WP_Query |
|
301 | - * @throws InvalidArgumentException |
|
302 | - * @throws InvalidDataTypeException |
|
303 | - * @throws InvalidInterfaceException |
|
304 | - */ |
|
305 | - protected function _process_WP_Query_post_types(WP_Query $WP_Query) |
|
306 | - { |
|
307 | - if (isset($WP_Query->query_vars['post_type'])) { |
|
308 | - // loop thru post_types as array |
|
309 | - foreach ((array) $WP_Query->query_vars['post_type'] as $post_type) { |
|
310 | - // is current query for an EE CPT ? |
|
311 | - if (isset($this->_CPTs[ $post_type ])) { |
|
312 | - // is EE on or off ? |
|
313 | - if (EE_Maintenance_Mode::instance()->level()) { |
|
314 | - // reroute CPT template view to maintenance_mode.template.php |
|
315 | - if (! has_filter('template_include', array('EE_Maintenance_Mode', 'template_include'))) { |
|
316 | - add_filter('template_include', array('EE_Maintenance_Mode', 'template_include'), 99999); |
|
317 | - } |
|
318 | - if (has_filter('the_content', array(EE_Maintenance_Mode::instance(), 'the_content'))) { |
|
319 | - add_filter('the_content', array($this, 'inject_EE_shortcode_placeholder'), 1); |
|
320 | - } |
|
321 | - return; |
|
322 | - } |
|
323 | - $this->_generate_CptQueryModifier($WP_Query, $post_type); |
|
324 | - } |
|
325 | - } |
|
326 | - } |
|
327 | - } |
|
328 | - |
|
329 | - |
|
330 | - /** |
|
331 | - * @param \WP_Query $WP_Query |
|
332 | - * @param string $post_type |
|
333 | - * @throws InvalidArgumentException |
|
334 | - * @throws InvalidDataTypeException |
|
335 | - * @throws InvalidInterfaceException |
|
336 | - */ |
|
337 | - protected function _generate_CptQueryModifier(WP_Query $WP_Query, $post_type) |
|
338 | - { |
|
339 | - $this->query_modifier = LoaderFactory::getLoader()->getShared( |
|
340 | - 'EventEspresso\core\CPTs\CptQueryModifier', |
|
341 | - array( |
|
342 | - $post_type, |
|
343 | - $this->_CPTs[ $post_type ], |
|
344 | - $WP_Query, |
|
345 | - ) |
|
346 | - ); |
|
347 | - $this->_CPT_taxonomies = $this->query_modifier->taxonomies(); |
|
348 | - } |
|
349 | - |
|
350 | - |
|
351 | - /** |
|
352 | - * inject_EE_shortcode_placeholder |
|
353 | - * in order to display the M-Mode notice on our CPT routes, |
|
354 | - * we need to first inject what looks like one of our shortcodes, |
|
355 | - * so that it can be replaced with the actual M-Mode notice |
|
356 | - * |
|
357 | - * @return string |
|
358 | - */ |
|
359 | - public function inject_EE_shortcode_placeholder() |
|
360 | - { |
|
361 | - return '[ESPRESSO_'; |
|
362 | - } |
|
363 | - |
|
364 | - |
|
365 | - /** |
|
366 | - * @deprecated |
|
367 | - * @since 4.8.41 |
|
368 | - * @return void |
|
369 | - */ |
|
370 | - public function _possibly_set_ee_request_var() |
|
371 | - { |
|
372 | - $this->query_modifier->setRequestVarsIfCpt(); |
|
373 | - } |
|
374 | - |
|
375 | - |
|
376 | - /** |
|
377 | - * @deprecated |
|
378 | - * @since 4.8.41 |
|
379 | - * @param $SQL |
|
380 | - * @return string |
|
381 | - */ |
|
382 | - public function posts_fields($SQL) |
|
383 | - { |
|
384 | - if ($this->query_modifier instanceof EventEspresso\Core\CPTs\CptQueryModifier) { |
|
385 | - return $this->query_modifier->postsFields($SQL); |
|
386 | - } |
|
387 | - return $SQL; |
|
388 | - } |
|
389 | - |
|
390 | - |
|
391 | - /** |
|
392 | - * @deprecated |
|
393 | - * @since 4.8.41 |
|
394 | - * @param $SQL |
|
395 | - * @return string |
|
396 | - */ |
|
397 | - public function posts_join($SQL) |
|
398 | - { |
|
399 | - if ($this->query_modifier instanceof EventEspresso\Core\CPTs\CptQueryModifier) { |
|
400 | - return $this->query_modifier->postsJoin($SQL); |
|
401 | - } |
|
402 | - return $SQL; |
|
403 | - } |
|
404 | - |
|
405 | - |
|
406 | - /** |
|
407 | - * @deprecated |
|
408 | - * @since 4.8.41 |
|
409 | - * @param \WP_Post[] $posts |
|
410 | - * @return \WP_Post[] |
|
411 | - */ |
|
412 | - public function the_posts($posts) |
|
413 | - { |
|
414 | - if ($this->query_modifier instanceof EventEspresso\Core\CPTs\CptQueryModifier) { |
|
415 | - $this->query_modifier->thePosts($posts); |
|
416 | - } |
|
417 | - return $posts; |
|
418 | - } |
|
419 | - |
|
420 | - |
|
421 | - /** |
|
422 | - * @deprecated |
|
423 | - * @since 4.8.41 |
|
424 | - * @param $url |
|
425 | - * @param $ID |
|
426 | - * @return string |
|
427 | - */ |
|
428 | - public function get_edit_post_link($url, $ID) |
|
429 | - { |
|
430 | - if ($this->query_modifier instanceof EventEspresso\Core\CPTs\CptQueryModifier) { |
|
431 | - return $this->query_modifier->getEditPostLink($url, $ID); |
|
432 | - } |
|
433 | - return ''; |
|
434 | - } |
|
435 | - |
|
436 | - |
|
437 | - /** |
|
438 | - * @deprecated |
|
439 | - * @since 4.8.41 |
|
440 | - * @param null $WP_Query |
|
441 | - */ |
|
442 | - protected function _do_template_filters($WP_Query = null) |
|
443 | - { |
|
444 | - if ($this->query_modifier instanceof EventEspresso\Core\CPTs\CptQueryModifier) { |
|
445 | - $this->query_modifier->addTemplateFilters(); |
|
446 | - } |
|
447 | - } |
|
448 | - |
|
449 | - |
|
450 | - /** |
|
451 | - * @deprecated |
|
452 | - * @since 4.8.41 |
|
453 | - * @param string $current_template Existing default template path derived for this page call. |
|
454 | - * @return string the path to the full template file. |
|
455 | - */ |
|
456 | - public function single_cpt_template($current_template) |
|
457 | - { |
|
458 | - if ($this->query_modifier instanceof EventEspresso\Core\CPTs\CptQueryModifier) { |
|
459 | - return $this->query_modifier->singleCptTemplate($current_template); |
|
460 | - } |
|
461 | - return $current_template; |
|
462 | - } |
|
18 | + /** |
|
19 | + * @var EE_CPT_Strategy $_instance |
|
20 | + */ |
|
21 | + private static $_instance; |
|
22 | + |
|
23 | + /** |
|
24 | + * the current page, if it utilizes CPTs |
|
25 | + * |
|
26 | + * @var array $CPT |
|
27 | + */ |
|
28 | + protected $CPT; |
|
29 | + |
|
30 | + /** |
|
31 | + * return value from CustomPostTypeDefinitions::getDefinitions() |
|
32 | + * |
|
33 | + * @var array $_CPTs |
|
34 | + */ |
|
35 | + protected $_CPTs = array(); |
|
36 | + |
|
37 | + /** |
|
38 | + * @var array $_CPT_taxonomies |
|
39 | + */ |
|
40 | + protected $_CPT_taxonomies = array(); |
|
41 | + |
|
42 | + /** |
|
43 | + * @var array $_CPT_terms |
|
44 | + */ |
|
45 | + protected $_CPT_terms = array(); |
|
46 | + |
|
47 | + /** |
|
48 | + * @var array $_CPT_endpoints |
|
49 | + */ |
|
50 | + protected $_CPT_endpoints = array(); |
|
51 | + |
|
52 | + /** |
|
53 | + * @var EEM_Base $CPT_model |
|
54 | + */ |
|
55 | + protected $CPT_model; |
|
56 | + |
|
57 | + /** |
|
58 | + * @var EventEspresso\Core\CPTs\CptQueryModifier $query_modifier |
|
59 | + */ |
|
60 | + protected $query_modifier; |
|
61 | + |
|
62 | + |
|
63 | + /** |
|
64 | + * @singleton method used to instantiate class object |
|
65 | + * @param CustomPostTypeDefinitions|null $custom_post_types |
|
66 | + * @param CustomTaxonomyDefinitions|null $taxonomies |
|
67 | + * @return EE_CPT_Strategy |
|
68 | + */ |
|
69 | + public static function instance( |
|
70 | + CustomPostTypeDefinitions $custom_post_types = null, |
|
71 | + CustomTaxonomyDefinitions $taxonomies = null |
|
72 | + ) { |
|
73 | + // check if class object is instantiated |
|
74 | + if ( |
|
75 | + ! self::$_instance instanceof EE_CPT_Strategy |
|
76 | + && $custom_post_types instanceof CustomPostTypeDefinitions |
|
77 | + && $taxonomies instanceof CustomTaxonomyDefinitions |
|
78 | + ) { |
|
79 | + self::$_instance = new self($custom_post_types, $taxonomies); |
|
80 | + } |
|
81 | + return self::$_instance; |
|
82 | + } |
|
83 | + |
|
84 | + |
|
85 | + /** |
|
86 | + * @param CustomPostTypeDefinitions $custom_post_types |
|
87 | + * @param CustomTaxonomyDefinitions $taxonomies |
|
88 | + */ |
|
89 | + protected function __construct( |
|
90 | + CustomPostTypeDefinitions $custom_post_types, |
|
91 | + CustomTaxonomyDefinitions $taxonomies |
|
92 | + ) { |
|
93 | + // get CPT data |
|
94 | + $this->_CPTs = $custom_post_types->getDefinitions(); |
|
95 | + $this->_CPT_endpoints = $this->_set_CPT_endpoints(); |
|
96 | + $this->_CPT_taxonomies = $taxonomies->getCustomTaxonomyDefinitions(); |
|
97 | + add_action('pre_get_posts', array($this, 'pre_get_posts'), 5); |
|
98 | + } |
|
99 | + |
|
100 | + |
|
101 | + /** |
|
102 | + * @return array |
|
103 | + */ |
|
104 | + public function get_CPT_endpoints() |
|
105 | + { |
|
106 | + return $this->_CPT_endpoints; |
|
107 | + } |
|
108 | + |
|
109 | + |
|
110 | + /** |
|
111 | + * @return array |
|
112 | + */ |
|
113 | + public function get_CPT_taxonomies() |
|
114 | + { |
|
115 | + return $this->_CPT_taxonomies; |
|
116 | + } |
|
117 | + |
|
118 | + |
|
119 | + /** |
|
120 | + * add CPT "slugs" to array of default espresso "pages" |
|
121 | + * |
|
122 | + * @return array |
|
123 | + */ |
|
124 | + private function _set_CPT_endpoints() |
|
125 | + { |
|
126 | + $_CPT_endpoints = array(); |
|
127 | + if (is_array($this->_CPTs)) { |
|
128 | + foreach ($this->_CPTs as $CPT_type => $CPT) { |
|
129 | + if (isset($CPT['plural_slug'])) { |
|
130 | + $_CPT_endpoints [ (string) $CPT['plural_slug'] ] = $CPT_type; |
|
131 | + } |
|
132 | + } |
|
133 | + } |
|
134 | + return $_CPT_endpoints; |
|
135 | + } |
|
136 | + |
|
137 | + |
|
138 | + /** |
|
139 | + * If this query (not just "main" queries (ie, for WP's infamous "loop")) is for an EE CPT, then we want to |
|
140 | + * supercharge the get_posts query to add our EE stuff (like joining to our tables, selecting extra columns, and |
|
141 | + * adding EE objects to the post to facilitate further querying of related data etc) |
|
142 | + * |
|
143 | + * @param WP_Query $WP_Query |
|
144 | + * @return void |
|
145 | + * @throws \EE_Error |
|
146 | + * @throws \InvalidArgumentException |
|
147 | + * @throws \EventEspresso\core\exceptions\InvalidInterfaceException |
|
148 | + * @throws \EventEspresso\core\exceptions\InvalidDataTypeException |
|
149 | + */ |
|
150 | + public function pre_get_posts($WP_Query) |
|
151 | + { |
|
152 | + // check that post-type is set |
|
153 | + if (! $WP_Query instanceof WP_Query) { |
|
154 | + return; |
|
155 | + } |
|
156 | + // add our conditionals |
|
157 | + $this->_set_EE_tags_on_WP_Query($WP_Query); |
|
158 | + // check for terms |
|
159 | + $this->_set_post_type_for_terms($WP_Query); |
|
160 | + // make sure paging is always set |
|
161 | + $this->_set_paging($WP_Query); |
|
162 | + // is a taxonomy set ? |
|
163 | + $this->_set_CPT_taxonomies_on_WP_Query($WP_Query); |
|
164 | + // loop thru post_types if set |
|
165 | + $this->_process_WP_Query_post_types($WP_Query); |
|
166 | + } |
|
167 | + |
|
168 | + |
|
169 | + /** |
|
170 | + * @param WP_Query $WP_Query |
|
171 | + * @return void |
|
172 | + */ |
|
173 | + private function _set_EE_tags_on_WP_Query(WP_Query $WP_Query) |
|
174 | + { |
|
175 | + $WP_Query->is_espresso_event_single = false; |
|
176 | + $WP_Query->is_espresso_event_archive = false; |
|
177 | + $WP_Query->is_espresso_event_taxonomy = false; |
|
178 | + $WP_Query->is_espresso_venue_single = false; |
|
179 | + $WP_Query->is_espresso_venue_archive = false; |
|
180 | + $WP_Query->is_espresso_venue_taxonomy = false; |
|
181 | + } |
|
182 | + |
|
183 | + |
|
184 | + /** |
|
185 | + * @return void |
|
186 | + * @throws EE_Error |
|
187 | + * @throws InvalidArgumentException |
|
188 | + * @throws InvalidDataTypeException |
|
189 | + * @throws InvalidInterfaceException |
|
190 | + */ |
|
191 | + private function _set_CPT_terms() |
|
192 | + { |
|
193 | + if (empty($this->_CPT_terms)) { |
|
194 | + $terms = EEM_Term::instance()->get_all_CPT_post_tags(); |
|
195 | + foreach ($terms as $term) { |
|
196 | + if ($term instanceof EE_Term) { |
|
197 | + $this->_CPT_terms[ $term->slug() ] = $term; |
|
198 | + } |
|
199 | + } |
|
200 | + } |
|
201 | + } |
|
202 | + |
|
203 | + |
|
204 | + /** |
|
205 | + * @param WP_Query $WP_Query |
|
206 | + * @return void |
|
207 | + * @throws EE_Error |
|
208 | + * @throws InvalidArgumentException |
|
209 | + * @throws InvalidDataTypeException |
|
210 | + * @throws InvalidInterfaceException |
|
211 | + */ |
|
212 | + private function _set_post_type_for_terms(WP_Query $WP_Query) |
|
213 | + { |
|
214 | + // is a tag set ? |
|
215 | + if (isset($WP_Query->query['tag'])) { |
|
216 | + // get term for tag |
|
217 | + $term = EEM_Term::instance()->get_post_tag_for_event_or_venue($WP_Query->query['tag']); |
|
218 | + // verify the term |
|
219 | + if ($term instanceof EE_Term) { |
|
220 | + $term->post_type = array_merge(array('post', 'page'), (array) $term->post_type); |
|
221 | + $term->post_type = apply_filters( |
|
222 | + 'FHEE__EE_CPT_Strategy___set_post_type_for_terms__term_post_type', |
|
223 | + $term->post_type, |
|
224 | + $term |
|
225 | + ); |
|
226 | + // if a post type is already set |
|
227 | + if (isset($WP_Query->query_vars['post_type'])) { |
|
228 | + // add to existing array |
|
229 | + $term->post_type = array_merge((array) $WP_Query->query_vars['post_type'], $term->post_type); |
|
230 | + } |
|
231 | + // just set post_type to our CPT |
|
232 | + $WP_Query->set('post_type', array_unique($term->post_type)); |
|
233 | + } |
|
234 | + } |
|
235 | + } |
|
236 | + |
|
237 | + |
|
238 | + /** |
|
239 | + * @param WP_Query $WP_Query |
|
240 | + * @return void |
|
241 | + */ |
|
242 | + public function _set_paging($WP_Query) |
|
243 | + { |
|
244 | + if ($WP_Query->is_main_query() && apply_filters('FHEE__EE_CPT_Strategy___set_paging', true)) { |
|
245 | + $page = get_query_var('page') ? get_query_var('page') : null; |
|
246 | + $paged = get_query_var('paged') ? get_query_var('paged') : $page; |
|
247 | + $WP_Query->set('paged', $paged); |
|
248 | + } |
|
249 | + } |
|
250 | + |
|
251 | + |
|
252 | + /** |
|
253 | + * @param \WP_Query $WP_Query |
|
254 | + */ |
|
255 | + protected function _set_CPT_taxonomies_on_WP_Query(WP_Query $WP_Query) |
|
256 | + { |
|
257 | + // is a taxonomy set ? |
|
258 | + if ($WP_Query->is_tax) { |
|
259 | + // loop thru our taxonomies |
|
260 | + foreach ($this->_CPT_taxonomies as $CPT_taxonomy => $CPT_taxonomy_details) { |
|
261 | + // check if one of our taxonomies is set as a query var |
|
262 | + if (isset($WP_Query->query[ $CPT_taxonomy ])) { |
|
263 | + // but which CPT does that correspond to??? hmmm... guess we gotta go looping |
|
264 | + foreach ($this->_CPTs as $post_type => $CPT) { |
|
265 | + // verify our CPT has args, is public and has taxonomies set |
|
266 | + if ( |
|
267 | + isset($CPT['args']['public']) |
|
268 | + && $CPT['args']['public'] |
|
269 | + && ! empty($CPT['args']['taxonomies']) |
|
270 | + && in_array($CPT_taxonomy, $CPT['args']['taxonomies'], true) |
|
271 | + ) { |
|
272 | + // if so, then add this CPT post_type to the current query's array of post_types' |
|
273 | + $WP_Query->query_vars['post_type'] = isset($WP_Query->query_vars['post_type']) |
|
274 | + ? (array) $WP_Query->query_vars['post_type'] |
|
275 | + : array(); |
|
276 | + $WP_Query->query_vars['post_type'][] = $post_type; |
|
277 | + switch ($post_type) { |
|
278 | + case 'espresso_events': |
|
279 | + $WP_Query->is_espresso_event_taxonomy = true; |
|
280 | + break; |
|
281 | + case 'espresso_venues': |
|
282 | + $WP_Query->is_espresso_venue_taxonomy = true; |
|
283 | + break; |
|
284 | + default: |
|
285 | + do_action( |
|
286 | + 'AHEE__EE_CPT_Strategy___set_CPT_taxonomies_on_WP_Query__for_' . $post_type . '_post_type', |
|
287 | + $WP_Query, |
|
288 | + $this |
|
289 | + ); |
|
290 | + } |
|
291 | + } |
|
292 | + } |
|
293 | + } |
|
294 | + } |
|
295 | + } |
|
296 | + } |
|
297 | + |
|
298 | + |
|
299 | + /** |
|
300 | + * @param \WP_Query $WP_Query |
|
301 | + * @throws InvalidArgumentException |
|
302 | + * @throws InvalidDataTypeException |
|
303 | + * @throws InvalidInterfaceException |
|
304 | + */ |
|
305 | + protected function _process_WP_Query_post_types(WP_Query $WP_Query) |
|
306 | + { |
|
307 | + if (isset($WP_Query->query_vars['post_type'])) { |
|
308 | + // loop thru post_types as array |
|
309 | + foreach ((array) $WP_Query->query_vars['post_type'] as $post_type) { |
|
310 | + // is current query for an EE CPT ? |
|
311 | + if (isset($this->_CPTs[ $post_type ])) { |
|
312 | + // is EE on or off ? |
|
313 | + if (EE_Maintenance_Mode::instance()->level()) { |
|
314 | + // reroute CPT template view to maintenance_mode.template.php |
|
315 | + if (! has_filter('template_include', array('EE_Maintenance_Mode', 'template_include'))) { |
|
316 | + add_filter('template_include', array('EE_Maintenance_Mode', 'template_include'), 99999); |
|
317 | + } |
|
318 | + if (has_filter('the_content', array(EE_Maintenance_Mode::instance(), 'the_content'))) { |
|
319 | + add_filter('the_content', array($this, 'inject_EE_shortcode_placeholder'), 1); |
|
320 | + } |
|
321 | + return; |
|
322 | + } |
|
323 | + $this->_generate_CptQueryModifier($WP_Query, $post_type); |
|
324 | + } |
|
325 | + } |
|
326 | + } |
|
327 | + } |
|
328 | + |
|
329 | + |
|
330 | + /** |
|
331 | + * @param \WP_Query $WP_Query |
|
332 | + * @param string $post_type |
|
333 | + * @throws InvalidArgumentException |
|
334 | + * @throws InvalidDataTypeException |
|
335 | + * @throws InvalidInterfaceException |
|
336 | + */ |
|
337 | + protected function _generate_CptQueryModifier(WP_Query $WP_Query, $post_type) |
|
338 | + { |
|
339 | + $this->query_modifier = LoaderFactory::getLoader()->getShared( |
|
340 | + 'EventEspresso\core\CPTs\CptQueryModifier', |
|
341 | + array( |
|
342 | + $post_type, |
|
343 | + $this->_CPTs[ $post_type ], |
|
344 | + $WP_Query, |
|
345 | + ) |
|
346 | + ); |
|
347 | + $this->_CPT_taxonomies = $this->query_modifier->taxonomies(); |
|
348 | + } |
|
349 | + |
|
350 | + |
|
351 | + /** |
|
352 | + * inject_EE_shortcode_placeholder |
|
353 | + * in order to display the M-Mode notice on our CPT routes, |
|
354 | + * we need to first inject what looks like one of our shortcodes, |
|
355 | + * so that it can be replaced with the actual M-Mode notice |
|
356 | + * |
|
357 | + * @return string |
|
358 | + */ |
|
359 | + public function inject_EE_shortcode_placeholder() |
|
360 | + { |
|
361 | + return '[ESPRESSO_'; |
|
362 | + } |
|
363 | + |
|
364 | + |
|
365 | + /** |
|
366 | + * @deprecated |
|
367 | + * @since 4.8.41 |
|
368 | + * @return void |
|
369 | + */ |
|
370 | + public function _possibly_set_ee_request_var() |
|
371 | + { |
|
372 | + $this->query_modifier->setRequestVarsIfCpt(); |
|
373 | + } |
|
374 | + |
|
375 | + |
|
376 | + /** |
|
377 | + * @deprecated |
|
378 | + * @since 4.8.41 |
|
379 | + * @param $SQL |
|
380 | + * @return string |
|
381 | + */ |
|
382 | + public function posts_fields($SQL) |
|
383 | + { |
|
384 | + if ($this->query_modifier instanceof EventEspresso\Core\CPTs\CptQueryModifier) { |
|
385 | + return $this->query_modifier->postsFields($SQL); |
|
386 | + } |
|
387 | + return $SQL; |
|
388 | + } |
|
389 | + |
|
390 | + |
|
391 | + /** |
|
392 | + * @deprecated |
|
393 | + * @since 4.8.41 |
|
394 | + * @param $SQL |
|
395 | + * @return string |
|
396 | + */ |
|
397 | + public function posts_join($SQL) |
|
398 | + { |
|
399 | + if ($this->query_modifier instanceof EventEspresso\Core\CPTs\CptQueryModifier) { |
|
400 | + return $this->query_modifier->postsJoin($SQL); |
|
401 | + } |
|
402 | + return $SQL; |
|
403 | + } |
|
404 | + |
|
405 | + |
|
406 | + /** |
|
407 | + * @deprecated |
|
408 | + * @since 4.8.41 |
|
409 | + * @param \WP_Post[] $posts |
|
410 | + * @return \WP_Post[] |
|
411 | + */ |
|
412 | + public function the_posts($posts) |
|
413 | + { |
|
414 | + if ($this->query_modifier instanceof EventEspresso\Core\CPTs\CptQueryModifier) { |
|
415 | + $this->query_modifier->thePosts($posts); |
|
416 | + } |
|
417 | + return $posts; |
|
418 | + } |
|
419 | + |
|
420 | + |
|
421 | + /** |
|
422 | + * @deprecated |
|
423 | + * @since 4.8.41 |
|
424 | + * @param $url |
|
425 | + * @param $ID |
|
426 | + * @return string |
|
427 | + */ |
|
428 | + public function get_edit_post_link($url, $ID) |
|
429 | + { |
|
430 | + if ($this->query_modifier instanceof EventEspresso\Core\CPTs\CptQueryModifier) { |
|
431 | + return $this->query_modifier->getEditPostLink($url, $ID); |
|
432 | + } |
|
433 | + return ''; |
|
434 | + } |
|
435 | + |
|
436 | + |
|
437 | + /** |
|
438 | + * @deprecated |
|
439 | + * @since 4.8.41 |
|
440 | + * @param null $WP_Query |
|
441 | + */ |
|
442 | + protected function _do_template_filters($WP_Query = null) |
|
443 | + { |
|
444 | + if ($this->query_modifier instanceof EventEspresso\Core\CPTs\CptQueryModifier) { |
|
445 | + $this->query_modifier->addTemplateFilters(); |
|
446 | + } |
|
447 | + } |
|
448 | + |
|
449 | + |
|
450 | + /** |
|
451 | + * @deprecated |
|
452 | + * @since 4.8.41 |
|
453 | + * @param string $current_template Existing default template path derived for this page call. |
|
454 | + * @return string the path to the full template file. |
|
455 | + */ |
|
456 | + public function single_cpt_template($current_template) |
|
457 | + { |
|
458 | + if ($this->query_modifier instanceof EventEspresso\Core\CPTs\CptQueryModifier) { |
|
459 | + return $this->query_modifier->singleCptTemplate($current_template); |
|
460 | + } |
|
461 | + return $current_template; |
|
462 | + } |
|
463 | 463 | } |
@@ -122,13 +122,13 @@ discard block |
||
122 | 122 | ) |
123 | 123 | ) { |
124 | 124 | // adds something like ", wp_esp_datetime.* " to WP Query SELECT statement |
125 | - $SQL .= ', ' . EEM_Datetime::instance()->table() . '.* '; |
|
125 | + $SQL .= ', '.EEM_Datetime::instance()->table().'.* '; |
|
126 | 126 | if ($wp_query->is_espresso_event_archive || $wp_query->is_espresso_event_taxonomy) { |
127 | 127 | // because we only want to retrieve the next upcoming datetime for each event: |
128 | 128 | // add something like: |
129 | 129 | // ", MIN( wp_esp_datetime.DTT_EVT_start ) as event_start_date " |
130 | 130 | // to WP Query SELECT statement |
131 | - $SQL .= ', MIN( ' . EEM_Datetime::instance()->table() . '.DTT_EVT_start ) as event_start_date '; |
|
131 | + $SQL .= ', MIN( '.EEM_Datetime::instance()->table().'.DTT_EVT_start ) as event_start_date '; |
|
132 | 132 | } |
133 | 133 | } |
134 | 134 | return $SQL; |
@@ -158,9 +158,9 @@ discard block |
||
158 | 158 | // adds something like: |
159 | 159 | // " LEFT JOIN wp_esp_datetime ON ( wp_esp_datetime.EVT_ID = wp_posts.ID ) " |
160 | 160 | // to WP Query JOIN statement |
161 | - $SQL .= ' INNER JOIN ' . EEM_Datetime::instance()->table() . ' ON ( ' . EEM_Event::instance()->table() |
|
162 | - . '.ID = ' . EEM_Datetime::instance()->table() . '.' |
|
163 | - . EEM_Event::instance()->primary_key_name() . ' ) '; |
|
161 | + $SQL .= ' INNER JOIN '.EEM_Datetime::instance()->table().' ON ( '.EEM_Event::instance()->table() |
|
162 | + . '.ID = '.EEM_Datetime::instance()->table().'.' |
|
163 | + . EEM_Event::instance()->primary_key_name().' ) '; |
|
164 | 164 | } |
165 | 165 | return $SQL; |
166 | 166 | } |
@@ -190,8 +190,8 @@ discard block |
||
190 | 190 | || ! isset(EE_Registry::instance()->CFG->template_settings->EED_Events_Archive->display_expired_events) |
191 | 191 | || ! EE_Registry::instance()->CFG->template_settings->EED_Events_Archive->display_expired_events |
192 | 192 | ) { |
193 | - $SQL .= ' AND ' . EEM_Datetime::instance()->table() . ".DTT_EVT_end > '" |
|
194 | - . current_time('mysql', true) . "' "; |
|
193 | + $SQL .= ' AND '.EEM_Datetime::instance()->table().".DTT_EVT_end > '" |
|
194 | + . current_time('mysql', true)."' "; |
|
195 | 195 | } |
196 | 196 | } |
197 | 197 | return $SQL; |
@@ -239,7 +239,7 @@ discard block |
||
239 | 239 | // but we want to only show each event only once |
240 | 240 | // (whereas if we didn't group them by the post's ID, then we would end up with many repeats) |
241 | 241 | global $wpdb; |
242 | - $SQL = $wpdb->posts . '.ID '; |
|
242 | + $SQL = $wpdb->posts.'.ID '; |
|
243 | 243 | } |
244 | 244 | return $SQL; |
245 | 245 | } |
@@ -12,258 +12,258 @@ |
||
12 | 12 | */ |
13 | 13 | class EE_CPT_Event_Strategy |
14 | 14 | { |
15 | - /** |
|
16 | - * the current page, if it utilizes CPTs |
|
17 | - * |
|
18 | - * @var object $CPT |
|
19 | - */ |
|
20 | - protected $CPT; |
|
15 | + /** |
|
16 | + * the current page, if it utilizes CPTs |
|
17 | + * |
|
18 | + * @var object $CPT |
|
19 | + */ |
|
20 | + protected $CPT; |
|
21 | 21 | |
22 | 22 | |
23 | - /** |
|
24 | - * @param WP_Query $wp_query |
|
25 | - * @param array $CPT |
|
26 | - */ |
|
27 | - public function __construct($wp_query, $CPT = array()) |
|
28 | - { |
|
29 | - if ($wp_query instanceof WP_Query) { |
|
30 | - $WP_Query = $wp_query; |
|
31 | - $this->CPT = $CPT; |
|
32 | - } else { |
|
33 | - $WP_Query = isset($wp_query['WP_Query']) ? $wp_query['WP_Query'] : null; |
|
34 | - $this->CPT = isset($wp_query['CPT']) ? $wp_query['CPT'] : null; |
|
35 | - } |
|
36 | - // !!!!!!!!!! IMPORTANT !!!!!!!!!!!! |
|
37 | - // here's the list of available filters in the WP_Query object |
|
38 | - // 'posts_where' |
|
39 | - // 'posts_where_paged' |
|
40 | - // 'posts_groupby' |
|
41 | - // 'posts_join_paged' |
|
42 | - // 'posts_orderby' |
|
43 | - // 'posts_distinct' |
|
44 | - // 'post_limits' |
|
45 | - // 'posts_fields' |
|
46 | - // 'posts_join' |
|
47 | - $this->_add_filters(); |
|
48 | - if ($WP_Query instanceof WP_Query) { |
|
49 | - $WP_Query->is_espresso_event_single = is_singular() |
|
50 | - && isset($WP_Query->query->post_type) |
|
51 | - && $WP_Query->query->post_type === 'espresso_events'; |
|
52 | - $WP_Query->is_espresso_event_archive = is_post_type_archive('espresso_events'); |
|
53 | - $WP_Query->is_espresso_event_taxonomy = is_tax('espresso_event_categories'); |
|
54 | - } |
|
55 | - } |
|
23 | + /** |
|
24 | + * @param WP_Query $wp_query |
|
25 | + * @param array $CPT |
|
26 | + */ |
|
27 | + public function __construct($wp_query, $CPT = array()) |
|
28 | + { |
|
29 | + if ($wp_query instanceof WP_Query) { |
|
30 | + $WP_Query = $wp_query; |
|
31 | + $this->CPT = $CPT; |
|
32 | + } else { |
|
33 | + $WP_Query = isset($wp_query['WP_Query']) ? $wp_query['WP_Query'] : null; |
|
34 | + $this->CPT = isset($wp_query['CPT']) ? $wp_query['CPT'] : null; |
|
35 | + } |
|
36 | + // !!!!!!!!!! IMPORTANT !!!!!!!!!!!! |
|
37 | + // here's the list of available filters in the WP_Query object |
|
38 | + // 'posts_where' |
|
39 | + // 'posts_where_paged' |
|
40 | + // 'posts_groupby' |
|
41 | + // 'posts_join_paged' |
|
42 | + // 'posts_orderby' |
|
43 | + // 'posts_distinct' |
|
44 | + // 'post_limits' |
|
45 | + // 'posts_fields' |
|
46 | + // 'posts_join' |
|
47 | + $this->_add_filters(); |
|
48 | + if ($WP_Query instanceof WP_Query) { |
|
49 | + $WP_Query->is_espresso_event_single = is_singular() |
|
50 | + && isset($WP_Query->query->post_type) |
|
51 | + && $WP_Query->query->post_type === 'espresso_events'; |
|
52 | + $WP_Query->is_espresso_event_archive = is_post_type_archive('espresso_events'); |
|
53 | + $WP_Query->is_espresso_event_taxonomy = is_tax('espresso_event_categories'); |
|
54 | + } |
|
55 | + } |
|
56 | 56 | |
57 | 57 | |
58 | - /** |
|
59 | - * When an instance of this class is created, we add our filters |
|
60 | - * (which will get removed in case the next call to get_posts ISN'T |
|
61 | - * for event CPTs) |
|
62 | - */ |
|
63 | - protected function _add_filters() |
|
64 | - { |
|
65 | - add_filter('posts_fields', array($this, 'posts_fields'), 1, 2); |
|
66 | - add_filter('posts_join', array($this, 'posts_join'), 1, 2); |
|
67 | - add_filter('posts_where', array($this, 'posts_where'), 10, 2); |
|
68 | - // add_filter( 'the_posts', array( $this, 'the_posts' ), 1, 2 ); |
|
69 | - add_filter('posts_orderby', array($this, 'posts_orderby'), 1, 2); |
|
70 | - add_filter('posts_groupby', array($this, 'posts_groupby'), 1, 2); |
|
71 | - add_action('posts_selection', array($this, 'remove_filters')); |
|
72 | - } |
|
58 | + /** |
|
59 | + * When an instance of this class is created, we add our filters |
|
60 | + * (which will get removed in case the next call to get_posts ISN'T |
|
61 | + * for event CPTs) |
|
62 | + */ |
|
63 | + protected function _add_filters() |
|
64 | + { |
|
65 | + add_filter('posts_fields', array($this, 'posts_fields'), 1, 2); |
|
66 | + add_filter('posts_join', array($this, 'posts_join'), 1, 2); |
|
67 | + add_filter('posts_where', array($this, 'posts_where'), 10, 2); |
|
68 | + // add_filter( 'the_posts', array( $this, 'the_posts' ), 1, 2 ); |
|
69 | + add_filter('posts_orderby', array($this, 'posts_orderby'), 1, 2); |
|
70 | + add_filter('posts_groupby', array($this, 'posts_groupby'), 1, 2); |
|
71 | + add_action('posts_selection', array($this, 'remove_filters')); |
|
72 | + } |
|
73 | 73 | |
74 | 74 | |
75 | - /** |
|
76 | - * public access to _remove_filters() |
|
77 | - * |
|
78 | - * @since 4.9.63.p |
|
79 | - */ |
|
80 | - public function remove_filters() |
|
81 | - { |
|
82 | - $this->_remove_filters(); |
|
83 | - } |
|
75 | + /** |
|
76 | + * public access to _remove_filters() |
|
77 | + * |
|
78 | + * @since 4.9.63.p |
|
79 | + */ |
|
80 | + public function remove_filters() |
|
81 | + { |
|
82 | + $this->_remove_filters(); |
|
83 | + } |
|
84 | 84 | |
85 | 85 | |
86 | - /** |
|
87 | - * Should eb called when the last filter or hook is fired for this CPT strategy. |
|
88 | - * This is to avoid applying this CPT strategy for other posts or CPTs (eg, |
|
89 | - * we don't want to join to the datetime table when querying for venues, do we!?) |
|
90 | - */ |
|
91 | - protected function _remove_filters() |
|
92 | - { |
|
93 | - remove_filter('posts_fields', array($this, 'posts_fields'), 1); |
|
94 | - remove_filter('posts_join', array($this, 'posts_join'), 1); |
|
95 | - remove_filter('posts_where', array($this, 'posts_where'), 10); |
|
96 | - // remove_filter( 'the_posts', array( $this, 'the_posts' ), 1 ); |
|
97 | - remove_filter('posts_orderby', array($this, 'posts_orderby'), 1); |
|
98 | - remove_filter('posts_groupby', array($this, 'posts_groupby'), 1); |
|
99 | - remove_action('posts_selection', array($this, 'remove_filters')); |
|
100 | - } |
|
86 | + /** |
|
87 | + * Should eb called when the last filter or hook is fired for this CPT strategy. |
|
88 | + * This is to avoid applying this CPT strategy for other posts or CPTs (eg, |
|
89 | + * we don't want to join to the datetime table when querying for venues, do we!?) |
|
90 | + */ |
|
91 | + protected function _remove_filters() |
|
92 | + { |
|
93 | + remove_filter('posts_fields', array($this, 'posts_fields'), 1); |
|
94 | + remove_filter('posts_join', array($this, 'posts_join'), 1); |
|
95 | + remove_filter('posts_where', array($this, 'posts_where'), 10); |
|
96 | + // remove_filter( 'the_posts', array( $this, 'the_posts' ), 1 ); |
|
97 | + remove_filter('posts_orderby', array($this, 'posts_orderby'), 1); |
|
98 | + remove_filter('posts_groupby', array($this, 'posts_groupby'), 1); |
|
99 | + remove_action('posts_selection', array($this, 'remove_filters')); |
|
100 | + } |
|
101 | 101 | |
102 | 102 | |
103 | - /** |
|
104 | - * @param string $SQL |
|
105 | - * @param WP_Query $wp_query |
|
106 | - * @return string |
|
107 | - * @throws EE_Error |
|
108 | - * @throws InvalidArgumentException |
|
109 | - * @throws InvalidDataTypeException |
|
110 | - * @throws InvalidInterfaceException |
|
111 | - */ |
|
112 | - public function posts_fields($SQL, WP_Query $wp_query) |
|
113 | - { |
|
114 | - if ( |
|
115 | - $wp_query instanceof WP_Query |
|
116 | - && |
|
117 | - ( |
|
118 | - $wp_query->is_espresso_event_single |
|
119 | - || $wp_query->is_espresso_event_archive |
|
120 | - || $wp_query->is_espresso_event_taxonomy |
|
121 | - ) |
|
122 | - ) { |
|
123 | - // adds something like ", wp_esp_datetime.* " to WP Query SELECT statement |
|
124 | - $SQL .= ', ' . EEM_Datetime::instance()->table() . '.* '; |
|
125 | - if ($wp_query->is_espresso_event_archive || $wp_query->is_espresso_event_taxonomy) { |
|
126 | - // because we only want to retrieve the next upcoming datetime for each event: |
|
127 | - // add something like: |
|
128 | - // ", MIN( wp_esp_datetime.DTT_EVT_start ) as event_start_date " |
|
129 | - // to WP Query SELECT statement |
|
130 | - $SQL .= ', MIN( ' . EEM_Datetime::instance()->table() . '.DTT_EVT_start ) as event_start_date '; |
|
131 | - } |
|
132 | - } |
|
133 | - return $SQL; |
|
134 | - } |
|
103 | + /** |
|
104 | + * @param string $SQL |
|
105 | + * @param WP_Query $wp_query |
|
106 | + * @return string |
|
107 | + * @throws EE_Error |
|
108 | + * @throws InvalidArgumentException |
|
109 | + * @throws InvalidDataTypeException |
|
110 | + * @throws InvalidInterfaceException |
|
111 | + */ |
|
112 | + public function posts_fields($SQL, WP_Query $wp_query) |
|
113 | + { |
|
114 | + if ( |
|
115 | + $wp_query instanceof WP_Query |
|
116 | + && |
|
117 | + ( |
|
118 | + $wp_query->is_espresso_event_single |
|
119 | + || $wp_query->is_espresso_event_archive |
|
120 | + || $wp_query->is_espresso_event_taxonomy |
|
121 | + ) |
|
122 | + ) { |
|
123 | + // adds something like ", wp_esp_datetime.* " to WP Query SELECT statement |
|
124 | + $SQL .= ', ' . EEM_Datetime::instance()->table() . '.* '; |
|
125 | + if ($wp_query->is_espresso_event_archive || $wp_query->is_espresso_event_taxonomy) { |
|
126 | + // because we only want to retrieve the next upcoming datetime for each event: |
|
127 | + // add something like: |
|
128 | + // ", MIN( wp_esp_datetime.DTT_EVT_start ) as event_start_date " |
|
129 | + // to WP Query SELECT statement |
|
130 | + $SQL .= ', MIN( ' . EEM_Datetime::instance()->table() . '.DTT_EVT_start ) as event_start_date '; |
|
131 | + } |
|
132 | + } |
|
133 | + return $SQL; |
|
134 | + } |
|
135 | 135 | |
136 | 136 | |
137 | - /** |
|
138 | - * @param string $SQL |
|
139 | - * @param WP_Query $wp_query |
|
140 | - * @return string |
|
141 | - * @throws EE_Error |
|
142 | - * @throws InvalidArgumentException |
|
143 | - * @throws InvalidDataTypeException |
|
144 | - * @throws InvalidInterfaceException |
|
145 | - */ |
|
146 | - public function posts_join($SQL, WP_Query $wp_query) |
|
147 | - { |
|
148 | - if ( |
|
149 | - $wp_query instanceof WP_Query |
|
150 | - && |
|
151 | - ( |
|
152 | - $wp_query->is_espresso_event_single |
|
153 | - || $wp_query->is_espresso_event_archive |
|
154 | - || $wp_query->is_espresso_event_taxonomy |
|
155 | - ) |
|
156 | - ) { |
|
157 | - // adds something like: |
|
158 | - // " LEFT JOIN wp_esp_datetime ON ( wp_esp_datetime.EVT_ID = wp_posts.ID ) " |
|
159 | - // to WP Query JOIN statement |
|
160 | - $SQL .= ' INNER JOIN ' . EEM_Datetime::instance()->table() . ' ON ( ' . EEM_Event::instance()->table() |
|
161 | - . '.ID = ' . EEM_Datetime::instance()->table() . '.' |
|
162 | - . EEM_Event::instance()->primary_key_name() . ' ) '; |
|
163 | - } |
|
164 | - return $SQL; |
|
165 | - } |
|
137 | + /** |
|
138 | + * @param string $SQL |
|
139 | + * @param WP_Query $wp_query |
|
140 | + * @return string |
|
141 | + * @throws EE_Error |
|
142 | + * @throws InvalidArgumentException |
|
143 | + * @throws InvalidDataTypeException |
|
144 | + * @throws InvalidInterfaceException |
|
145 | + */ |
|
146 | + public function posts_join($SQL, WP_Query $wp_query) |
|
147 | + { |
|
148 | + if ( |
|
149 | + $wp_query instanceof WP_Query |
|
150 | + && |
|
151 | + ( |
|
152 | + $wp_query->is_espresso_event_single |
|
153 | + || $wp_query->is_espresso_event_archive |
|
154 | + || $wp_query->is_espresso_event_taxonomy |
|
155 | + ) |
|
156 | + ) { |
|
157 | + // adds something like: |
|
158 | + // " LEFT JOIN wp_esp_datetime ON ( wp_esp_datetime.EVT_ID = wp_posts.ID ) " |
|
159 | + // to WP Query JOIN statement |
|
160 | + $SQL .= ' INNER JOIN ' . EEM_Datetime::instance()->table() . ' ON ( ' . EEM_Event::instance()->table() |
|
161 | + . '.ID = ' . EEM_Datetime::instance()->table() . '.' |
|
162 | + . EEM_Event::instance()->primary_key_name() . ' ) '; |
|
163 | + } |
|
164 | + return $SQL; |
|
165 | + } |
|
166 | 166 | |
167 | 167 | |
168 | - /** |
|
169 | - * @param string $SQL |
|
170 | - * @param WP_Query $wp_query |
|
171 | - * @return string |
|
172 | - * @throws EE_Error |
|
173 | - * @throws InvalidArgumentException |
|
174 | - * @throws InvalidDataTypeException |
|
175 | - * @throws InvalidInterfaceException |
|
176 | - */ |
|
177 | - public function posts_where($SQL, WP_Query $wp_query) |
|
178 | - { |
|
179 | - if ( |
|
180 | - $wp_query instanceof WP_Query |
|
181 | - && |
|
182 | - ( |
|
183 | - $wp_query->is_espresso_event_archive |
|
184 | - || $wp_query->is_espresso_event_taxonomy |
|
185 | - ) |
|
186 | - ) { |
|
187 | - if ( |
|
188 | - ! isset(EE_Registry::instance()->CFG->template_settings->EED_Events_Archive) |
|
189 | - || ! isset(EE_Registry::instance()->CFG->template_settings->EED_Events_Archive->display_expired_events) |
|
190 | - || ! EE_Registry::instance()->CFG->template_settings->EED_Events_Archive->display_expired_events |
|
191 | - ) { |
|
192 | - $SQL .= ' AND ' . EEM_Datetime::instance()->table() . ".DTT_EVT_end > '" |
|
193 | - . current_time('mysql', true) . "' "; |
|
194 | - } |
|
195 | - } |
|
196 | - return $SQL; |
|
197 | - } |
|
168 | + /** |
|
169 | + * @param string $SQL |
|
170 | + * @param WP_Query $wp_query |
|
171 | + * @return string |
|
172 | + * @throws EE_Error |
|
173 | + * @throws InvalidArgumentException |
|
174 | + * @throws InvalidDataTypeException |
|
175 | + * @throws InvalidInterfaceException |
|
176 | + */ |
|
177 | + public function posts_where($SQL, WP_Query $wp_query) |
|
178 | + { |
|
179 | + if ( |
|
180 | + $wp_query instanceof WP_Query |
|
181 | + && |
|
182 | + ( |
|
183 | + $wp_query->is_espresso_event_archive |
|
184 | + || $wp_query->is_espresso_event_taxonomy |
|
185 | + ) |
|
186 | + ) { |
|
187 | + if ( |
|
188 | + ! isset(EE_Registry::instance()->CFG->template_settings->EED_Events_Archive) |
|
189 | + || ! isset(EE_Registry::instance()->CFG->template_settings->EED_Events_Archive->display_expired_events) |
|
190 | + || ! EE_Registry::instance()->CFG->template_settings->EED_Events_Archive->display_expired_events |
|
191 | + ) { |
|
192 | + $SQL .= ' AND ' . EEM_Datetime::instance()->table() . ".DTT_EVT_end > '" |
|
193 | + . current_time('mysql', true) . "' "; |
|
194 | + } |
|
195 | + } |
|
196 | + return $SQL; |
|
197 | + } |
|
198 | 198 | |
199 | 199 | |
200 | - /** |
|
201 | - * @param string $SQL |
|
202 | - * @param WP_Query $wp_query |
|
203 | - * @return string |
|
204 | - */ |
|
205 | - public function posts_orderby($SQL, WP_Query $wp_query) |
|
206 | - { |
|
207 | - if ( |
|
208 | - $wp_query instanceof WP_Query |
|
209 | - && |
|
210 | - ( |
|
211 | - $wp_query->is_espresso_event_archive |
|
212 | - || $wp_query->is_espresso_event_taxonomy |
|
213 | - ) |
|
214 | - ) { |
|
215 | - $SQL = ' event_start_date ASC '; |
|
216 | - } |
|
217 | - return $SQL; |
|
218 | - } |
|
200 | + /** |
|
201 | + * @param string $SQL |
|
202 | + * @param WP_Query $wp_query |
|
203 | + * @return string |
|
204 | + */ |
|
205 | + public function posts_orderby($SQL, WP_Query $wp_query) |
|
206 | + { |
|
207 | + if ( |
|
208 | + $wp_query instanceof WP_Query |
|
209 | + && |
|
210 | + ( |
|
211 | + $wp_query->is_espresso_event_archive |
|
212 | + || $wp_query->is_espresso_event_taxonomy |
|
213 | + ) |
|
214 | + ) { |
|
215 | + $SQL = ' event_start_date ASC '; |
|
216 | + } |
|
217 | + return $SQL; |
|
218 | + } |
|
219 | 219 | |
220 | 220 | |
221 | - /** |
|
222 | - * @param string $SQL |
|
223 | - * @param WP_Query $wp_query |
|
224 | - * @return string |
|
225 | - */ |
|
226 | - public function posts_groupby($SQL, WP_Query $wp_query) |
|
227 | - { |
|
228 | - if ( |
|
229 | - $wp_query instanceof WP_Query |
|
230 | - && |
|
231 | - ( |
|
232 | - $wp_query->is_espresso_event_archive |
|
233 | - || $wp_query->is_espresso_event_taxonomy |
|
234 | - ) |
|
235 | - ) { |
|
236 | - // TODO: add event list option for displaying ALL datetimes in event list or only primary datetime (default) |
|
237 | - // we're joining to the datetimes table, where there can be MANY datetimes for a single event, |
|
238 | - // but we want to only show each event only once |
|
239 | - // (whereas if we didn't group them by the post's ID, then we would end up with many repeats) |
|
240 | - global $wpdb; |
|
241 | - $SQL = $wpdb->posts . '.ID '; |
|
242 | - } |
|
243 | - return $SQL; |
|
244 | - } |
|
221 | + /** |
|
222 | + * @param string $SQL |
|
223 | + * @param WP_Query $wp_query |
|
224 | + * @return string |
|
225 | + */ |
|
226 | + public function posts_groupby($SQL, WP_Query $wp_query) |
|
227 | + { |
|
228 | + if ( |
|
229 | + $wp_query instanceof WP_Query |
|
230 | + && |
|
231 | + ( |
|
232 | + $wp_query->is_espresso_event_archive |
|
233 | + || $wp_query->is_espresso_event_taxonomy |
|
234 | + ) |
|
235 | + ) { |
|
236 | + // TODO: add event list option for displaying ALL datetimes in event list or only primary datetime (default) |
|
237 | + // we're joining to the datetimes table, where there can be MANY datetimes for a single event, |
|
238 | + // but we want to only show each event only once |
|
239 | + // (whereas if we didn't group them by the post's ID, then we would end up with many repeats) |
|
240 | + global $wpdb; |
|
241 | + $SQL = $wpdb->posts . '.ID '; |
|
242 | + } |
|
243 | + return $SQL; |
|
244 | + } |
|
245 | 245 | |
246 | 246 | |
247 | - /** |
|
248 | - * @param array $posts |
|
249 | - * @param WP_Query $wp_query |
|
250 | - * @return array |
|
251 | - */ |
|
252 | - public function the_posts($posts, WP_Query $wp_query) |
|
253 | - { |
|
254 | - return $posts; |
|
255 | - } |
|
247 | + /** |
|
248 | + * @param array $posts |
|
249 | + * @param WP_Query $wp_query |
|
250 | + * @return array |
|
251 | + */ |
|
252 | + public function the_posts($posts, WP_Query $wp_query) |
|
253 | + { |
|
254 | + return $posts; |
|
255 | + } |
|
256 | 256 | |
257 | 257 | |
258 | - /** |
|
259 | - * @param null $meta_value |
|
260 | - * @param $post_id |
|
261 | - * @param $meta_key |
|
262 | - * @param $single |
|
263 | - * @return string |
|
264 | - */ |
|
265 | - public function get_EE_post_type_metadata($meta_value = null, $post_id, $meta_key, $single) |
|
266 | - { |
|
267 | - return $meta_value; |
|
268 | - } |
|
258 | + /** |
|
259 | + * @param null $meta_value |
|
260 | + * @param $post_id |
|
261 | + * @param $meta_key |
|
262 | + * @param $single |
|
263 | + * @return string |
|
264 | + */ |
|
265 | + public function get_EE_post_type_metadata($meta_value = null, $post_id, $meta_key, $single) |
|
266 | + { |
|
267 | + return $meta_value; |
|
268 | + } |
|
269 | 269 | } |
@@ -80,7 +80,7 @@ discard block |
||
80 | 80 | $data = []; |
81 | 81 | if (empty($this->countries)) { |
82 | 82 | $this->data_version = $this->getCountrySubRegionDataVersion(); |
83 | - $data = $this->retrieveJsonData(self::REPO_URL . 'countries.json'); |
|
83 | + $data = $this->retrieveJsonData(self::REPO_URL.'countries.json'); |
|
84 | 84 | } |
85 | 85 | if (empty($data)) { |
86 | 86 | EE_Error::add_error( |
@@ -144,7 +144,7 @@ discard block |
||
144 | 144 | */ |
145 | 145 | private function processCountryData($CNT_ISO, $countries = array()) |
146 | 146 | { |
147 | - if (! empty($countries)) { |
|
147 | + if ( ! empty($countries)) { |
|
148 | 148 | foreach ($countries as $key => $country) { |
149 | 149 | if ( |
150 | 150 | $country instanceof stdClass |
@@ -153,7 +153,7 @@ discard block |
||
153 | 153 | && ! empty($country->filename) |
154 | 154 | ) { |
155 | 155 | $country->sub_regions = $this->retrieveJsonData( |
156 | - self::REPO_URL . 'countries/' . $country->filename . '.json' |
|
156 | + self::REPO_URL.'countries/'.$country->filename.'.json' |
|
157 | 157 | ); |
158 | 158 | return $this->saveSubRegionData($country, $country->sub_regions); |
159 | 159 | } |
@@ -215,7 +215,7 @@ discard block |
||
215 | 215 | foreach ($sub_regions as $sub_region) { |
216 | 216 | // remove country code from sub region code |
217 | 217 | $abbrev = str_replace( |
218 | - $country->code . '-', |
|
218 | + $country->code.'-', |
|
219 | 219 | '', |
220 | 220 | sanitize_text_field($sub_region->code) |
221 | 221 | ); |
@@ -25,252 +25,252 @@ |
||
25 | 25 | */ |
26 | 26 | class CountrySubRegionDao |
27 | 27 | { |
28 | - const REPO_URL = 'https://raw.githubusercontent.com/eventespresso/countries-and-subregions/master/'; |
|
28 | + const REPO_URL = 'https://raw.githubusercontent.com/eventespresso/countries-and-subregions/master/'; |
|
29 | 29 | |
30 | - const OPTION_NAME_COUNTRY_DATA_VERSION = 'espresso-country-sub-region-data-version'; |
|
30 | + const OPTION_NAME_COUNTRY_DATA_VERSION = 'espresso-country-sub-region-data-version'; |
|
31 | 31 | |
32 | - /** |
|
33 | - * @var EEM_State $state_model |
|
34 | - */ |
|
35 | - private $state_model; |
|
32 | + /** |
|
33 | + * @var EEM_State $state_model |
|
34 | + */ |
|
35 | + private $state_model; |
|
36 | 36 | |
37 | - /** |
|
38 | - * @var JsonValidator $json_validator |
|
39 | - */ |
|
40 | - private $json_validator; |
|
37 | + /** |
|
38 | + * @var JsonValidator $json_validator |
|
39 | + */ |
|
40 | + private $json_validator; |
|
41 | 41 | |
42 | - /** |
|
43 | - * @var string $data_version |
|
44 | - */ |
|
45 | - private $data_version; |
|
42 | + /** |
|
43 | + * @var string $data_version |
|
44 | + */ |
|
45 | + private $data_version; |
|
46 | 46 | |
47 | - /** |
|
48 | - * @var array $countries |
|
49 | - */ |
|
50 | - private $countries = array(); |
|
47 | + /** |
|
48 | + * @var array $countries |
|
49 | + */ |
|
50 | + private $countries = array(); |
|
51 | 51 | |
52 | 52 | |
53 | - /** |
|
54 | - * CountrySubRegionDao constructor. |
|
55 | - * |
|
56 | - * @param EEM_State $state_model |
|
57 | - * @param JsonValidator $json_validator |
|
58 | - */ |
|
59 | - public function __construct(EEM_State $state_model, JsonValidator $json_validator) |
|
60 | - { |
|
61 | - $this->state_model = $state_model; |
|
62 | - $this->json_validator = $json_validator; |
|
63 | - } |
|
53 | + /** |
|
54 | + * CountrySubRegionDao constructor. |
|
55 | + * |
|
56 | + * @param EEM_State $state_model |
|
57 | + * @param JsonValidator $json_validator |
|
58 | + */ |
|
59 | + public function __construct(EEM_State $state_model, JsonValidator $json_validator) |
|
60 | + { |
|
61 | + $this->state_model = $state_model; |
|
62 | + $this->json_validator = $json_validator; |
|
63 | + } |
|
64 | 64 | |
65 | 65 | |
66 | - /** |
|
67 | - * @param EE_Country $country_object |
|
68 | - * @return bool |
|
69 | - * @throws EE_Error |
|
70 | - * @throws InvalidArgumentException |
|
71 | - * @throws InvalidDataTypeException |
|
72 | - * @throws InvalidInterfaceException |
|
73 | - * @throws ReflectionException |
|
74 | - */ |
|
75 | - public function saveCountrySubRegions(EE_Country $country_object) |
|
76 | - { |
|
77 | - $CNT_ISO = $country_object->ID(); |
|
78 | - $has_sub_regions = $this->state_model->count(array(array('Country.CNT_ISO' => $CNT_ISO))); |
|
79 | - $data = []; |
|
80 | - if (empty($this->countries)) { |
|
81 | - $this->data_version = $this->getCountrySubRegionDataVersion(); |
|
82 | - $data = $this->retrieveJsonData(self::REPO_URL . 'countries.json'); |
|
83 | - } |
|
84 | - if (empty($data)) { |
|
85 | - EE_Error::add_error( |
|
86 | - 'Country Subregion Data could not be retrieved', |
|
87 | - __FILE__, |
|
88 | - __METHOD__, |
|
89 | - __LINE__ |
|
90 | - ); |
|
91 | - } |
|
92 | - if ( |
|
93 | - ! $has_sub_regions |
|
94 | - || (isset($data->version) && version_compare($data->version, $this->data_version)) |
|
95 | - ) { |
|
96 | - if ( |
|
97 | - isset($data->countries) |
|
98 | - && $this->processCountryData($CNT_ISO, $data->countries) > 0 |
|
99 | - ) { |
|
100 | - $this->countries = $data->countries; |
|
101 | - $this->updateCountrySubRegionDataVersion($data->version); |
|
102 | - return true; |
|
103 | - } |
|
104 | - } |
|
105 | - return false; |
|
106 | - } |
|
66 | + /** |
|
67 | + * @param EE_Country $country_object |
|
68 | + * @return bool |
|
69 | + * @throws EE_Error |
|
70 | + * @throws InvalidArgumentException |
|
71 | + * @throws InvalidDataTypeException |
|
72 | + * @throws InvalidInterfaceException |
|
73 | + * @throws ReflectionException |
|
74 | + */ |
|
75 | + public function saveCountrySubRegions(EE_Country $country_object) |
|
76 | + { |
|
77 | + $CNT_ISO = $country_object->ID(); |
|
78 | + $has_sub_regions = $this->state_model->count(array(array('Country.CNT_ISO' => $CNT_ISO))); |
|
79 | + $data = []; |
|
80 | + if (empty($this->countries)) { |
|
81 | + $this->data_version = $this->getCountrySubRegionDataVersion(); |
|
82 | + $data = $this->retrieveJsonData(self::REPO_URL . 'countries.json'); |
|
83 | + } |
|
84 | + if (empty($data)) { |
|
85 | + EE_Error::add_error( |
|
86 | + 'Country Subregion Data could not be retrieved', |
|
87 | + __FILE__, |
|
88 | + __METHOD__, |
|
89 | + __LINE__ |
|
90 | + ); |
|
91 | + } |
|
92 | + if ( |
|
93 | + ! $has_sub_regions |
|
94 | + || (isset($data->version) && version_compare($data->version, $this->data_version)) |
|
95 | + ) { |
|
96 | + if ( |
|
97 | + isset($data->countries) |
|
98 | + && $this->processCountryData($CNT_ISO, $data->countries) > 0 |
|
99 | + ) { |
|
100 | + $this->countries = $data->countries; |
|
101 | + $this->updateCountrySubRegionDataVersion($data->version); |
|
102 | + return true; |
|
103 | + } |
|
104 | + } |
|
105 | + return false; |
|
106 | + } |
|
107 | 107 | |
108 | 108 | |
109 | - /** |
|
110 | - * @since 4.9.70.p |
|
111 | - * @return string |
|
112 | - */ |
|
113 | - private function getCountrySubRegionDataVersion() |
|
114 | - { |
|
115 | - return get_option(self::OPTION_NAME_COUNTRY_DATA_VERSION, null); |
|
116 | - } |
|
109 | + /** |
|
110 | + * @since 4.9.70.p |
|
111 | + * @return string |
|
112 | + */ |
|
113 | + private function getCountrySubRegionDataVersion() |
|
114 | + { |
|
115 | + return get_option(self::OPTION_NAME_COUNTRY_DATA_VERSION, null); |
|
116 | + } |
|
117 | 117 | |
118 | 118 | |
119 | - /** |
|
120 | - * @param string $version |
|
121 | - */ |
|
122 | - private function updateCountrySubRegionDataVersion($version = '') |
|
123 | - { |
|
124 | - // add version option if it has never been added before, or update existing |
|
125 | - if ($this->data_version === null) { |
|
126 | - add_option(self::OPTION_NAME_COUNTRY_DATA_VERSION, $version, '', false); |
|
127 | - } else { |
|
128 | - update_option(self::OPTION_NAME_COUNTRY_DATA_VERSION, $version); |
|
129 | - } |
|
130 | - } |
|
119 | + /** |
|
120 | + * @param string $version |
|
121 | + */ |
|
122 | + private function updateCountrySubRegionDataVersion($version = '') |
|
123 | + { |
|
124 | + // add version option if it has never been added before, or update existing |
|
125 | + if ($this->data_version === null) { |
|
126 | + add_option(self::OPTION_NAME_COUNTRY_DATA_VERSION, $version, '', false); |
|
127 | + } else { |
|
128 | + update_option(self::OPTION_NAME_COUNTRY_DATA_VERSION, $version); |
|
129 | + } |
|
130 | + } |
|
131 | 131 | |
132 | 132 | |
133 | - /** |
|
134 | - * @param string $CNT_ISO |
|
135 | - * @param array $countries |
|
136 | - * @return int |
|
137 | - * @throws EE_Error |
|
138 | - * @throws InvalidArgumentException |
|
139 | - * @throws InvalidDataTypeException |
|
140 | - * @throws InvalidInterfaceException |
|
141 | - * @throws ReflectionException |
|
142 | - * @since 4.9.70.p |
|
143 | - */ |
|
144 | - private function processCountryData($CNT_ISO, $countries = array()) |
|
145 | - { |
|
146 | - if (! empty($countries)) { |
|
147 | - foreach ($countries as $key => $country) { |
|
148 | - if ( |
|
149 | - $country instanceof stdClass |
|
150 | - && $country->code === $CNT_ISO |
|
151 | - && empty($country->sub_regions) |
|
152 | - && ! empty($country->filename) |
|
153 | - ) { |
|
154 | - $country->sub_regions = $this->retrieveJsonData( |
|
155 | - self::REPO_URL . 'countries/' . $country->filename . '.json' |
|
156 | - ); |
|
157 | - return $this->saveSubRegionData($country, $country->sub_regions); |
|
158 | - } |
|
159 | - } |
|
160 | - } |
|
161 | - return 0; |
|
162 | - } |
|
133 | + /** |
|
134 | + * @param string $CNT_ISO |
|
135 | + * @param array $countries |
|
136 | + * @return int |
|
137 | + * @throws EE_Error |
|
138 | + * @throws InvalidArgumentException |
|
139 | + * @throws InvalidDataTypeException |
|
140 | + * @throws InvalidInterfaceException |
|
141 | + * @throws ReflectionException |
|
142 | + * @since 4.9.70.p |
|
143 | + */ |
|
144 | + private function processCountryData($CNT_ISO, $countries = array()) |
|
145 | + { |
|
146 | + if (! empty($countries)) { |
|
147 | + foreach ($countries as $key => $country) { |
|
148 | + if ( |
|
149 | + $country instanceof stdClass |
|
150 | + && $country->code === $CNT_ISO |
|
151 | + && empty($country->sub_regions) |
|
152 | + && ! empty($country->filename) |
|
153 | + ) { |
|
154 | + $country->sub_regions = $this->retrieveJsonData( |
|
155 | + self::REPO_URL . 'countries/' . $country->filename . '.json' |
|
156 | + ); |
|
157 | + return $this->saveSubRegionData($country, $country->sub_regions); |
|
158 | + } |
|
159 | + } |
|
160 | + } |
|
161 | + return 0; |
|
162 | + } |
|
163 | 163 | |
164 | 164 | |
165 | - /** |
|
166 | - * @param string $url |
|
167 | - * @return array |
|
168 | - */ |
|
169 | - private function retrieveJsonData($url) |
|
170 | - { |
|
171 | - if (empty($url)) { |
|
172 | - EE_Error::add_error( |
|
173 | - 'No URL was provided!', |
|
174 | - __FILE__, |
|
175 | - __METHOD__, |
|
176 | - __LINE__ |
|
177 | - ); |
|
178 | - return array(); |
|
179 | - } |
|
180 | - $request = wp_safe_remote_get($url); |
|
181 | - if ($request instanceof WP_Error) { |
|
182 | - EE_Error::add_error( |
|
183 | - $request->get_error_message(), |
|
184 | - __FILE__, |
|
185 | - __METHOD__, |
|
186 | - __LINE__ |
|
187 | - ); |
|
188 | - return array(); |
|
189 | - } |
|
190 | - $body = wp_remote_retrieve_body($request); |
|
191 | - $json = json_decode($body); |
|
192 | - if ($this->json_validator->isValid(__FILE__, __METHOD__, __LINE__)) { |
|
193 | - return $json; |
|
194 | - } |
|
195 | - return array(); |
|
196 | - } |
|
165 | + /** |
|
166 | + * @param string $url |
|
167 | + * @return array |
|
168 | + */ |
|
169 | + private function retrieveJsonData($url) |
|
170 | + { |
|
171 | + if (empty($url)) { |
|
172 | + EE_Error::add_error( |
|
173 | + 'No URL was provided!', |
|
174 | + __FILE__, |
|
175 | + __METHOD__, |
|
176 | + __LINE__ |
|
177 | + ); |
|
178 | + return array(); |
|
179 | + } |
|
180 | + $request = wp_safe_remote_get($url); |
|
181 | + if ($request instanceof WP_Error) { |
|
182 | + EE_Error::add_error( |
|
183 | + $request->get_error_message(), |
|
184 | + __FILE__, |
|
185 | + __METHOD__, |
|
186 | + __LINE__ |
|
187 | + ); |
|
188 | + return array(); |
|
189 | + } |
|
190 | + $body = wp_remote_retrieve_body($request); |
|
191 | + $json = json_decode($body); |
|
192 | + if ($this->json_validator->isValid(__FILE__, __METHOD__, __LINE__)) { |
|
193 | + return $json; |
|
194 | + } |
|
195 | + return array(); |
|
196 | + } |
|
197 | 197 | |
198 | 198 | |
199 | - /** |
|
200 | - * @param stdClass $country |
|
201 | - * @param array $sub_regions |
|
202 | - * @return int |
|
203 | - * @throws EE_Error |
|
204 | - * @throws InvalidArgumentException |
|
205 | - * @throws InvalidDataTypeException |
|
206 | - * @throws InvalidInterfaceException |
|
207 | - * @throws ReflectionException |
|
208 | - */ |
|
209 | - private function saveSubRegionData(stdClass $country, $sub_regions = array()) |
|
210 | - { |
|
211 | - $results = 0; |
|
212 | - if (is_array($sub_regions)) { |
|
213 | - $existing_sub_regions = $this->getExistingStateAbbreviations($country->code); |
|
214 | - foreach ($sub_regions as $sub_region) { |
|
215 | - // remove country code from sub region code |
|
216 | - $abbrev = str_replace( |
|
217 | - $country->code . '-', |
|
218 | - '', |
|
219 | - sanitize_text_field($sub_region->code) |
|
220 | - ); |
|
221 | - // but NOT if sub region code results in only a number |
|
222 | - if (absint($abbrev) !== 0) { |
|
223 | - $abbrev = sanitize_text_field($sub_region->code); |
|
224 | - } |
|
225 | - if ( |
|
226 | - ! in_array($abbrev, $existing_sub_regions, true) |
|
227 | - && $this->state_model->insert( |
|
228 | - [ |
|
229 | - // STA_ID CNT_ISO STA_abbrev STA_name STA_active |
|
230 | - 'CNT_ISO' => $country->code, |
|
231 | - 'STA_abbrev' => $abbrev, |
|
232 | - 'STA_name' => sanitize_text_field($sub_region->name), |
|
233 | - 'STA_active' => 1, |
|
234 | - ] |
|
235 | - ) |
|
236 | - ) { |
|
237 | - $results++; |
|
238 | - } |
|
239 | - } |
|
240 | - } |
|
241 | - return $results; |
|
242 | - } |
|
199 | + /** |
|
200 | + * @param stdClass $country |
|
201 | + * @param array $sub_regions |
|
202 | + * @return int |
|
203 | + * @throws EE_Error |
|
204 | + * @throws InvalidArgumentException |
|
205 | + * @throws InvalidDataTypeException |
|
206 | + * @throws InvalidInterfaceException |
|
207 | + * @throws ReflectionException |
|
208 | + */ |
|
209 | + private function saveSubRegionData(stdClass $country, $sub_regions = array()) |
|
210 | + { |
|
211 | + $results = 0; |
|
212 | + if (is_array($sub_regions)) { |
|
213 | + $existing_sub_regions = $this->getExistingStateAbbreviations($country->code); |
|
214 | + foreach ($sub_regions as $sub_region) { |
|
215 | + // remove country code from sub region code |
|
216 | + $abbrev = str_replace( |
|
217 | + $country->code . '-', |
|
218 | + '', |
|
219 | + sanitize_text_field($sub_region->code) |
|
220 | + ); |
|
221 | + // but NOT if sub region code results in only a number |
|
222 | + if (absint($abbrev) !== 0) { |
|
223 | + $abbrev = sanitize_text_field($sub_region->code); |
|
224 | + } |
|
225 | + if ( |
|
226 | + ! in_array($abbrev, $existing_sub_regions, true) |
|
227 | + && $this->state_model->insert( |
|
228 | + [ |
|
229 | + // STA_ID CNT_ISO STA_abbrev STA_name STA_active |
|
230 | + 'CNT_ISO' => $country->code, |
|
231 | + 'STA_abbrev' => $abbrev, |
|
232 | + 'STA_name' => sanitize_text_field($sub_region->name), |
|
233 | + 'STA_active' => 1, |
|
234 | + ] |
|
235 | + ) |
|
236 | + ) { |
|
237 | + $results++; |
|
238 | + } |
|
239 | + } |
|
240 | + } |
|
241 | + return $results; |
|
242 | + } |
|
243 | 243 | |
244 | 244 | |
245 | - /** |
|
246 | - * @param string $CNT_ISO |
|
247 | - * @since 4.9.76.p |
|
248 | - * @return array |
|
249 | - * @throws EE_Error |
|
250 | - * @throws InvalidArgumentException |
|
251 | - * @throws InvalidDataTypeException |
|
252 | - * @throws InvalidInterfaceException |
|
253 | - * @throws ReflectionException |
|
254 | - */ |
|
255 | - private function getExistingStateAbbreviations($CNT_ISO) |
|
256 | - { |
|
257 | - $existing_sub_region_IDs = []; |
|
258 | - $existing_sub_regions = $this->state_model->get_all(array( |
|
259 | - array( |
|
260 | - 'Country.CNT_ISO' => array( |
|
261 | - 'IN', |
|
262 | - [$CNT_ISO] |
|
263 | - ) |
|
264 | - ), |
|
265 | - 'order_by' => array('Country.CNT_name' => 'ASC', 'STA_name' => 'ASC') |
|
266 | - )); |
|
267 | - if (is_array($existing_sub_regions)) { |
|
268 | - foreach ($existing_sub_regions as $existing_sub_region) { |
|
269 | - if ($existing_sub_region instanceof EE_State) { |
|
270 | - $existing_sub_region_IDs[] = $existing_sub_region->abbrev(); |
|
271 | - } |
|
272 | - } |
|
273 | - } |
|
274 | - return $existing_sub_region_IDs; |
|
275 | - } |
|
245 | + /** |
|
246 | + * @param string $CNT_ISO |
|
247 | + * @since 4.9.76.p |
|
248 | + * @return array |
|
249 | + * @throws EE_Error |
|
250 | + * @throws InvalidArgumentException |
|
251 | + * @throws InvalidDataTypeException |
|
252 | + * @throws InvalidInterfaceException |
|
253 | + * @throws ReflectionException |
|
254 | + */ |
|
255 | + private function getExistingStateAbbreviations($CNT_ISO) |
|
256 | + { |
|
257 | + $existing_sub_region_IDs = []; |
|
258 | + $existing_sub_regions = $this->state_model->get_all(array( |
|
259 | + array( |
|
260 | + 'Country.CNT_ISO' => array( |
|
261 | + 'IN', |
|
262 | + [$CNT_ISO] |
|
263 | + ) |
|
264 | + ), |
|
265 | + 'order_by' => array('Country.CNT_name' => 'ASC', 'STA_name' => 'ASC') |
|
266 | + )); |
|
267 | + if (is_array($existing_sub_regions)) { |
|
268 | + foreach ($existing_sub_regions as $existing_sub_region) { |
|
269 | + if ($existing_sub_region instanceof EE_State) { |
|
270 | + $existing_sub_region_IDs[] = $existing_sub_region->abbrev(); |
|
271 | + } |
|
272 | + } |
|
273 | + } |
|
274 | + return $existing_sub_region_IDs; |
|
275 | + } |
|
276 | 276 | } |
@@ -20,202 +20,202 @@ |
||
20 | 20 | */ |
21 | 21 | class PayPalSettingsForm extends EE_Payment_Method_Form |
22 | 22 | { |
23 | - /** |
|
24 | - * @var string of HTML being the help tab link |
|
25 | - */ |
|
26 | - protected $helpTabLink; |
|
23 | + /** |
|
24 | + * @var string of HTML being the help tab link |
|
25 | + */ |
|
26 | + protected $helpTabLink; |
|
27 | 27 | |
28 | - public function __construct(array $options_array = array(), $help_tab_link = '') |
|
29 | - { |
|
30 | - $this->helpTabLink = $help_tab_link; |
|
31 | - $options_array = array_replace_recursive( |
|
32 | - array( |
|
33 | - 'extra_meta_inputs' => array( |
|
34 | - 'api_username' => new EE_Text_Input( |
|
35 | - array( |
|
36 | - 'html_label_text' => sprintf( |
|
37 | - // translators: %s link to help doc |
|
38 | - esc_html__('API Username %s', 'event_espresso'), |
|
39 | - $help_tab_link |
|
40 | - ), |
|
41 | - 'required' => true, |
|
42 | - ) |
|
43 | - ), |
|
44 | - 'api_password' => new EE_Text_Input( |
|
45 | - array( |
|
46 | - 'html_label_text' => sprintf( |
|
47 | - // translators: %s link to help doc |
|
48 | - esc_html__('API Password %s', 'event_espresso'), |
|
49 | - $help_tab_link |
|
50 | - ), |
|
51 | - 'required' => true, |
|
52 | - ) |
|
53 | - ), |
|
54 | - 'api_signature' => new EE_Text_Input( |
|
55 | - array( |
|
56 | - 'html_label_text' => sprintf( |
|
57 | - // translators: %s link to help doc |
|
58 | - esc_html__('API Signature %s', 'event_espresso'), |
|
59 | - $help_tab_link |
|
60 | - ), |
|
61 | - 'required' => true, |
|
62 | - ) |
|
63 | - ), |
|
64 | - ) |
|
65 | - ), |
|
66 | - $options_array |
|
67 | - ); |
|
68 | - parent::__construct($options_array); |
|
69 | - } |
|
28 | + public function __construct(array $options_array = array(), $help_tab_link = '') |
|
29 | + { |
|
30 | + $this->helpTabLink = $help_tab_link; |
|
31 | + $options_array = array_replace_recursive( |
|
32 | + array( |
|
33 | + 'extra_meta_inputs' => array( |
|
34 | + 'api_username' => new EE_Text_Input( |
|
35 | + array( |
|
36 | + 'html_label_text' => sprintf( |
|
37 | + // translators: %s link to help doc |
|
38 | + esc_html__('API Username %s', 'event_espresso'), |
|
39 | + $help_tab_link |
|
40 | + ), |
|
41 | + 'required' => true, |
|
42 | + ) |
|
43 | + ), |
|
44 | + 'api_password' => new EE_Text_Input( |
|
45 | + array( |
|
46 | + 'html_label_text' => sprintf( |
|
47 | + // translators: %s link to help doc |
|
48 | + esc_html__('API Password %s', 'event_espresso'), |
|
49 | + $help_tab_link |
|
50 | + ), |
|
51 | + 'required' => true, |
|
52 | + ) |
|
53 | + ), |
|
54 | + 'api_signature' => new EE_Text_Input( |
|
55 | + array( |
|
56 | + 'html_label_text' => sprintf( |
|
57 | + // translators: %s link to help doc |
|
58 | + esc_html__('API Signature %s', 'event_espresso'), |
|
59 | + $help_tab_link |
|
60 | + ), |
|
61 | + 'required' => true, |
|
62 | + ) |
|
63 | + ), |
|
64 | + ) |
|
65 | + ), |
|
66 | + $options_array |
|
67 | + ); |
|
68 | + parent::__construct($options_array); |
|
69 | + } |
|
70 | 70 | |
71 | - /** |
|
72 | - * Tests the the PayPal API credentials work ok |
|
73 | - * @return string of an error using the credentials, otherwise, if the credentials work, returns a blank string |
|
74 | - * @throws EE_Error |
|
75 | - */ |
|
76 | - protected function checkForCredentialsErrors() |
|
77 | - { |
|
78 | - $request_params = array( |
|
79 | - 'METHOD' => 'GetBalance', |
|
80 | - 'VERSION' => '204.0', |
|
81 | - 'USER' => $this->get_input_value('api_username'), |
|
82 | - 'PWD' => $this->get_input_value('api_password'), |
|
83 | - 'SIGNATURE' => $this->get_input_value('api_signature'), |
|
84 | - ); |
|
85 | - $gateway_url = $this->get_input_value('PMD_debug_mode') |
|
86 | - ? 'https://api-3t.sandbox.paypal.com/nvp' |
|
87 | - : 'https://api-3t.paypal.com/nvp'; |
|
88 | - // Request Customer Details. |
|
89 | - $response = wp_remote_post( |
|
90 | - $gateway_url, |
|
91 | - array( |
|
92 | - 'method' => 'POST', |
|
93 | - 'timeout' => 45, |
|
94 | - 'httpversion' => '1.1', |
|
95 | - 'cookies' => array(), |
|
96 | - 'headers' => array(), |
|
97 | - 'body' => http_build_query($request_params, '', '&'), |
|
98 | - ) |
|
99 | - ); |
|
100 | - if (is_wp_error($response) || empty($response['body'])) { |
|
101 | - // If we got here then there was an error in this request. |
|
102 | - // maybe is turned off. We don't know the credentials are invalid |
|
103 | - EE_Error::add_error( |
|
104 | - sprintf( |
|
105 | - // translators: %1$s Error message received from PayPal |
|
106 | - esc_html__( |
|
107 | - // @codingStandardsIgnoreStart |
|
108 | - 'Your PayPal credentials could not be verified. The following error occurred while communicating with PayPal: %1$s', |
|
109 | - // @codingStandardsIgnoreEnd |
|
110 | - 'event_espresso' |
|
111 | - ), |
|
112 | - $response->get_error_message() |
|
113 | - ), |
|
114 | - __FILE__, |
|
115 | - __FUNCTION__, |
|
116 | - __LINE__ |
|
117 | - ); |
|
118 | - } |
|
119 | - $response_args = array(); |
|
120 | - parse_str(urldecode($response['body']), $response_args); |
|
71 | + /** |
|
72 | + * Tests the the PayPal API credentials work ok |
|
73 | + * @return string of an error using the credentials, otherwise, if the credentials work, returns a blank string |
|
74 | + * @throws EE_Error |
|
75 | + */ |
|
76 | + protected function checkForCredentialsErrors() |
|
77 | + { |
|
78 | + $request_params = array( |
|
79 | + 'METHOD' => 'GetBalance', |
|
80 | + 'VERSION' => '204.0', |
|
81 | + 'USER' => $this->get_input_value('api_username'), |
|
82 | + 'PWD' => $this->get_input_value('api_password'), |
|
83 | + 'SIGNATURE' => $this->get_input_value('api_signature'), |
|
84 | + ); |
|
85 | + $gateway_url = $this->get_input_value('PMD_debug_mode') |
|
86 | + ? 'https://api-3t.sandbox.paypal.com/nvp' |
|
87 | + : 'https://api-3t.paypal.com/nvp'; |
|
88 | + // Request Customer Details. |
|
89 | + $response = wp_remote_post( |
|
90 | + $gateway_url, |
|
91 | + array( |
|
92 | + 'method' => 'POST', |
|
93 | + 'timeout' => 45, |
|
94 | + 'httpversion' => '1.1', |
|
95 | + 'cookies' => array(), |
|
96 | + 'headers' => array(), |
|
97 | + 'body' => http_build_query($request_params, '', '&'), |
|
98 | + ) |
|
99 | + ); |
|
100 | + if (is_wp_error($response) || empty($response['body'])) { |
|
101 | + // If we got here then there was an error in this request. |
|
102 | + // maybe is turned off. We don't know the credentials are invalid |
|
103 | + EE_Error::add_error( |
|
104 | + sprintf( |
|
105 | + // translators: %1$s Error message received from PayPal |
|
106 | + esc_html__( |
|
107 | + // @codingStandardsIgnoreStart |
|
108 | + 'Your PayPal credentials could not be verified. The following error occurred while communicating with PayPal: %1$s', |
|
109 | + // @codingStandardsIgnoreEnd |
|
110 | + 'event_espresso' |
|
111 | + ), |
|
112 | + $response->get_error_message() |
|
113 | + ), |
|
114 | + __FILE__, |
|
115 | + __FUNCTION__, |
|
116 | + __LINE__ |
|
117 | + ); |
|
118 | + } |
|
119 | + $response_args = array(); |
|
120 | + parse_str(urldecode($response['body']), $response_args); |
|
121 | 121 | |
122 | - if (empty($response_args['ACK'])) { |
|
123 | - EE_Error::add_error( |
|
124 | - esc_html__( |
|
125 | - 'Your PayPal credentials could not be verified. Part of their response was missing.', |
|
126 | - 'event_espresso' |
|
127 | - ), |
|
128 | - __FILE__, |
|
129 | - __FUNCTION__, |
|
130 | - __LINE__ |
|
131 | - ); |
|
132 | - } |
|
133 | - if ( |
|
134 | - in_array( |
|
135 | - $response_args['ACK'], |
|
136 | - array( |
|
137 | - 'Success', |
|
138 | - 'SuccessWithWarning' |
|
139 | - ), |
|
140 | - true |
|
141 | - ) |
|
142 | - ) { |
|
143 | - return ''; |
|
144 | - } else { |
|
145 | - return sprintf( |
|
146 | - // translators: %1$s: PayPal response message, %2$s: PayPal response code |
|
147 | - esc_html__( |
|
148 | - // @codingStandardsIgnoreStart |
|
149 | - 'Your PayPal API credentials appear to be invalid. PayPal said "%1$s (%2$s)". Please see tips below.', |
|
150 | - // @codingStandardsIgnoreEnd |
|
151 | - 'event_espresso' |
|
152 | - ), |
|
153 | - isset($response_args['L_LONGMESSAGE0']) |
|
154 | - ? $response_args['L_LONGMESSAGE0'] |
|
155 | - : esc_html__('No error message received from PayPal', 'event_espresso'), |
|
156 | - isset($response_args['L_ERRORCODE0']) ? $response_args['L_ERRORCODE0'] : 0 |
|
157 | - ); |
|
158 | - } |
|
159 | - } |
|
122 | + if (empty($response_args['ACK'])) { |
|
123 | + EE_Error::add_error( |
|
124 | + esc_html__( |
|
125 | + 'Your PayPal credentials could not be verified. Part of their response was missing.', |
|
126 | + 'event_espresso' |
|
127 | + ), |
|
128 | + __FILE__, |
|
129 | + __FUNCTION__, |
|
130 | + __LINE__ |
|
131 | + ); |
|
132 | + } |
|
133 | + if ( |
|
134 | + in_array( |
|
135 | + $response_args['ACK'], |
|
136 | + array( |
|
137 | + 'Success', |
|
138 | + 'SuccessWithWarning' |
|
139 | + ), |
|
140 | + true |
|
141 | + ) |
|
142 | + ) { |
|
143 | + return ''; |
|
144 | + } else { |
|
145 | + return sprintf( |
|
146 | + // translators: %1$s: PayPal response message, %2$s: PayPal response code |
|
147 | + esc_html__( |
|
148 | + // @codingStandardsIgnoreStart |
|
149 | + 'Your PayPal API credentials appear to be invalid. PayPal said "%1$s (%2$s)". Please see tips below.', |
|
150 | + // @codingStandardsIgnoreEnd |
|
151 | + 'event_espresso' |
|
152 | + ), |
|
153 | + isset($response_args['L_LONGMESSAGE0']) |
|
154 | + ? $response_args['L_LONGMESSAGE0'] |
|
155 | + : esc_html__('No error message received from PayPal', 'event_espresso'), |
|
156 | + isset($response_args['L_ERRORCODE0']) ? $response_args['L_ERRORCODE0'] : 0 |
|
157 | + ); |
|
158 | + } |
|
159 | + } |
|
160 | 160 | |
161 | - /** |
|
162 | - * Gets the HTML to show the link to the help tab |
|
163 | - * @return string |
|
164 | - */ |
|
165 | - protected function helpTabLink() |
|
166 | - { |
|
167 | - return $this->helpTabLink; |
|
168 | - } |
|
161 | + /** |
|
162 | + * Gets the HTML to show the link to the help tab |
|
163 | + * @return string |
|
164 | + */ |
|
165 | + protected function helpTabLink() |
|
166 | + { |
|
167 | + return $this->helpTabLink; |
|
168 | + } |
|
169 | 169 | |
170 | - /** |
|
171 | - * Does the normal validation, but also verifies the PayPal API credentials work. |
|
172 | - * If they don't, sets a validation error on the entire form, and adds validation errors (which are really more |
|
173 | - * tips) on each of the inputs that could be the cause of the problem. |
|
174 | - * @throws EE_Error |
|
175 | - */ |
|
176 | - public function _validate() |
|
177 | - { |
|
178 | - parent::_validate(); |
|
179 | - $credentials_message = $this->checkForCredentialsErrors(); |
|
180 | - if ($credentials_message !== '') { |
|
181 | - $this->add_validation_error($credentials_message); |
|
182 | - $this->get_input('PMD_debug_mode')->add_validation_error( |
|
183 | - esc_html__( |
|
184 | - // @codingStandardsIgnoreStart |
|
185 | - 'If you are using PayPal Sandbox (test) credentials, Debug mode should be set to "Yes". Otherwise, if you are using live PayPal credentials, set this to "No".', |
|
186 | - // @codingStandardsIgnoreEnd |
|
187 | - 'event_espresso' |
|
188 | - ) |
|
189 | - ); |
|
190 | - $this->get_input('api_username')->add_validation_error( |
|
191 | - sprintf( |
|
192 | - // translators: $1$s HTML for a link to the help tab |
|
193 | - esc_html__( |
|
194 | - 'Are you sure this is your API username, not your login username? %1$s', |
|
195 | - 'event_espresso' |
|
196 | - ), |
|
197 | - $this->helpTabLink() |
|
198 | - ) |
|
199 | - ); |
|
200 | - $this->get_input('api_password')->add_validation_error( |
|
201 | - sprintf( |
|
202 | - // translators: $1$s HTML for a link to the help tab |
|
203 | - esc_html__( |
|
204 | - 'Are you sure this is your API password, not your login password? %1$s', |
|
205 | - 'event_espresso' |
|
206 | - ), |
|
207 | - $this->helpTabLink() |
|
208 | - ) |
|
209 | - ); |
|
210 | - $this->get_input('api_signature')->add_validation_error( |
|
211 | - sprintf( |
|
212 | - // translators: $1$s HTML for a link to the help tab |
|
213 | - esc_html__('Please verify your API signature is correct. %1$s', 'event_espresso'), |
|
214 | - $this->helpTabLink() |
|
215 | - ) |
|
216 | - ); |
|
217 | - } |
|
218 | - } |
|
170 | + /** |
|
171 | + * Does the normal validation, but also verifies the PayPal API credentials work. |
|
172 | + * If they don't, sets a validation error on the entire form, and adds validation errors (which are really more |
|
173 | + * tips) on each of the inputs that could be the cause of the problem. |
|
174 | + * @throws EE_Error |
|
175 | + */ |
|
176 | + public function _validate() |
|
177 | + { |
|
178 | + parent::_validate(); |
|
179 | + $credentials_message = $this->checkForCredentialsErrors(); |
|
180 | + if ($credentials_message !== '') { |
|
181 | + $this->add_validation_error($credentials_message); |
|
182 | + $this->get_input('PMD_debug_mode')->add_validation_error( |
|
183 | + esc_html__( |
|
184 | + // @codingStandardsIgnoreStart |
|
185 | + 'If you are using PayPal Sandbox (test) credentials, Debug mode should be set to "Yes". Otherwise, if you are using live PayPal credentials, set this to "No".', |
|
186 | + // @codingStandardsIgnoreEnd |
|
187 | + 'event_espresso' |
|
188 | + ) |
|
189 | + ); |
|
190 | + $this->get_input('api_username')->add_validation_error( |
|
191 | + sprintf( |
|
192 | + // translators: $1$s HTML for a link to the help tab |
|
193 | + esc_html__( |
|
194 | + 'Are you sure this is your API username, not your login username? %1$s', |
|
195 | + 'event_espresso' |
|
196 | + ), |
|
197 | + $this->helpTabLink() |
|
198 | + ) |
|
199 | + ); |
|
200 | + $this->get_input('api_password')->add_validation_error( |
|
201 | + sprintf( |
|
202 | + // translators: $1$s HTML for a link to the help tab |
|
203 | + esc_html__( |
|
204 | + 'Are you sure this is your API password, not your login password? %1$s', |
|
205 | + 'event_espresso' |
|
206 | + ), |
|
207 | + $this->helpTabLink() |
|
208 | + ) |
|
209 | + ); |
|
210 | + $this->get_input('api_signature')->add_validation_error( |
|
211 | + sprintf( |
|
212 | + // translators: $1$s HTML for a link to the help tab |
|
213 | + esc_html__('Please verify your API signature is correct. %1$s', 'event_espresso'), |
|
214 | + $this->helpTabLink() |
|
215 | + ) |
|
216 | + ); |
|
217 | + } |
|
218 | + } |
|
219 | 219 | } |
220 | 220 | // End of file PayPalSettingsForm.php |
221 | 221 | // Location: ${NAMESPACE}/PayPalSettingsForm.php |
@@ -193,7 +193,7 @@ discard block |
||
193 | 193 | */ |
194 | 194 | protected function setCollectionInterface($collection_interface) |
195 | 195 | { |
196 | - if (! (interface_exists($collection_interface) || class_exists($collection_interface))) { |
|
196 | + if ( ! (interface_exists($collection_interface) || class_exists($collection_interface))) { |
|
197 | 197 | throw new InvalidInterfaceException($collection_interface); |
198 | 198 | } |
199 | 199 | $this->collection_interface = $collection_interface; |
@@ -221,7 +221,7 @@ discard block |
||
221 | 221 | */ |
222 | 222 | protected function setCollectionName($collection_name) |
223 | 223 | { |
224 | - if (! is_string($collection_name)) { |
|
224 | + if ( ! is_string($collection_name)) { |
|
225 | 225 | throw new InvalidDataTypeException('$collection_name', $collection_name, 'string'); |
226 | 226 | } |
227 | 227 | $this->collection_name = str_replace( |
@@ -281,7 +281,7 @@ discard block |
||
281 | 281 | */ |
282 | 282 | protected function setIdentifierCallback($identifier_callback = 'identifier') |
283 | 283 | { |
284 | - if (! is_string($identifier_callback)) { |
|
284 | + if ( ! is_string($identifier_callback)) { |
|
285 | 285 | throw new InvalidDataTypeException('$identifier_callback', $identifier_callback, 'string'); |
286 | 286 | } |
287 | 287 | $this->identifier_callback = $identifier_callback; |
@@ -311,7 +311,7 @@ discard block |
||
311 | 311 | $this->file_mask = ! empty($file_mask) ? $file_mask : '*.php'; |
312 | 312 | // we know our default is a string, so if it's not a string now, |
313 | 313 | // then that means the incoming parameter was something else |
314 | - if (! is_string($this->file_mask)) { |
|
314 | + if ( ! is_string($this->file_mask)) { |
|
315 | 315 | throw new InvalidDataTypeException('$file_mask', $this->file_mask, 'string'); |
316 | 316 | } |
317 | 317 | } |
@@ -336,7 +336,7 @@ discard block |
||
336 | 336 | public function setCollectionFQCNs($collection_FQCNs) |
337 | 337 | { |
338 | 338 | foreach ((array) $collection_FQCNs as $collection_FQCN) { |
339 | - if (! empty($collection_FQCN)) { |
|
339 | + if ( ! empty($collection_FQCN)) { |
|
340 | 340 | if (class_exists($collection_FQCN)) { |
341 | 341 | $this->collection_FQCNs[] = $collection_FQCN; |
342 | 342 | } else { |
@@ -358,7 +358,7 @@ discard block |
||
358 | 358 | */ |
359 | 359 | protected function getFQCNsFromPartialNamespace($partial_FQCN) |
360 | 360 | { |
361 | - if (! $this->file_locator instanceof FqcnLocator) { |
|
361 | + if ( ! $this->file_locator instanceof FqcnLocator) { |
|
362 | 362 | $this->file_locator = new FqcnLocator(); |
363 | 363 | } |
364 | 364 | $this->file_locator->locate($partial_FQCN); |
@@ -384,8 +384,8 @@ discard block |
||
384 | 384 | public function setCollectionPaths($collection_paths) |
385 | 385 | { |
386 | 386 | foreach ((array) $collection_paths as $collection_path) { |
387 | - if (! empty($collection_path)) { |
|
388 | - if (! is_readable($collection_path)) { |
|
387 | + if ( ! empty($collection_path)) { |
|
388 | + if ( ! is_readable($collection_path)) { |
|
389 | 389 | throw new InvalidFilePathException($collection_path); |
390 | 390 | } |
391 | 391 | $this->collection_paths[] = $collection_path; |
@@ -42,353 +42,353 @@ |
||
42 | 42 | */ |
43 | 43 | class CollectionDetails implements CollectionDetailsInterface |
44 | 44 | { |
45 | - /** |
|
46 | - * if $identifier_type is set to this, |
|
47 | - * then the collection will use each object's spl_object_hash() as it's identifier |
|
48 | - */ |
|
49 | - const ID_OBJECT_HASH = 'identifier-uses-spl-object-hash'; |
|
50 | - |
|
51 | - /** |
|
52 | - * if $identifier_type is set to this, |
|
53 | - * then the collection will use each object's class name as it's identifier |
|
54 | - */ |
|
55 | - const ID_CLASS_NAME = 'identifier-uses-object-class-name'; |
|
56 | - |
|
57 | - /** |
|
58 | - * if $identifier_type is set to this, |
|
59 | - * then the collection will use the return value from a specified callback method on each object |
|
60 | - */ |
|
61 | - const ID_CALLBACK_METHOD = 'identifier-uses-callback-method'; |
|
62 | - |
|
63 | - /** |
|
64 | - * The interface used for controlling what gets added to the collection |
|
65 | - * |
|
66 | - * @var string $collection_interface |
|
67 | - */ |
|
68 | - protected $collection_interface = ''; |
|
69 | - |
|
70 | - /** |
|
71 | - * a unique name used to identify the collection in filter names |
|
72 | - * supplied value is run through sanitize_title_with_dashes(), |
|
73 | - * but then also converts dashes to underscores |
|
74 | - * |
|
75 | - * @var string $collection_name |
|
76 | - */ |
|
77 | - protected $collection_name = ''; |
|
78 | - |
|
79 | - /** |
|
80 | - * what the collection uses for the object identifier. |
|
81 | - * corresponds to one of the class constants above. |
|
82 | - * CollectionDetails::ID_OBJECT_HASH will use spl_object_hash( object ) for the identifier |
|
83 | - * CollectionDetails::ID_CLASS_NAME will use get_class( object ) for the identifier |
|
84 | - * CollectionDetails::ID_CALLBACK_METHOD will use a callback for the identifier |
|
85 | - * defaults to using spl_object_hash() so that multiple objects of the same class can be added |
|
86 | - * |
|
87 | - * @var string $identifier_type |
|
88 | - */ |
|
89 | - protected $identifier_type = CollectionDetails::ID_OBJECT_HASH; |
|
90 | - |
|
91 | - /** |
|
92 | - * the pattern applied to paths when searching for class files to add to the collection |
|
93 | - * ie: "My_Awesome_*.class.php" |
|
94 | - * defaults to "*.php" |
|
95 | - * |
|
96 | - * @var string $file_mask |
|
97 | - */ |
|
98 | - protected $file_mask = ''; |
|
99 | - |
|
100 | - /** |
|
101 | - * if the $identifier_type above is set to CollectionDetails::ID_CALLBACK_METHOD, |
|
102 | - * then this specifies the method to use on each entity. |
|
103 | - * If the callback method does not exist, then an exception will be thrown |
|
104 | - * |
|
105 | - * @var string $identifier_callback |
|
106 | - */ |
|
107 | - protected $identifier_callback = ''; |
|
108 | - |
|
109 | - /** |
|
110 | - * an array of Fully Qualified Class Names |
|
111 | - * for example: |
|
112 | - * $FQCNs = array( |
|
113 | - * '/Fully/Qualified/ClassNameA' |
|
114 | - * '/Fully/Qualified/Other/ClassNameB' |
|
115 | - * ); |
|
116 | - * |
|
117 | - * @var array $collection_FQCNs |
|
118 | - */ |
|
119 | - protected $collection_FQCNs = array(); |
|
120 | - |
|
121 | - /** |
|
122 | - * an array of full server paths to folders containing files to be loaded into collection |
|
123 | - * for example: |
|
124 | - * $paths = array( |
|
125 | - * '/full/server/path/to/ClassNameA.ext.php' // for class ClassNameA |
|
126 | - * '/full/server/path/to/other/ClassNameB.php' // for class ClassNameB |
|
127 | - * ); |
|
128 | - * |
|
129 | - * @var array $collection_paths |
|
130 | - */ |
|
131 | - protected $collection_paths = array(); |
|
132 | - |
|
133 | - /** |
|
134 | - * @var LocatorInterface $file_locator |
|
135 | - */ |
|
136 | - protected $file_locator; |
|
137 | - |
|
138 | - |
|
139 | - /** |
|
140 | - * CollectionDetails constructor. |
|
141 | - * |
|
142 | - * @access public |
|
143 | - * @param string $collection_name |
|
144 | - * @param string $collection_interface |
|
145 | - * @param array $collection_FQCNs |
|
146 | - * @param array $collection_paths |
|
147 | - * @param string $file_mask |
|
148 | - * @param string $identifier_type |
|
149 | - * @param string $identifier_callback |
|
150 | - * @param LocatorInterface $file_locator |
|
151 | - * @throws CollectionDetailsException |
|
152 | - */ |
|
153 | - public function __construct( |
|
154 | - $collection_name, |
|
155 | - $collection_interface, |
|
156 | - array $collection_FQCNs = array(), |
|
157 | - array $collection_paths = array(), |
|
158 | - $file_mask = '', |
|
159 | - $identifier_type = CollectionDetails::ID_OBJECT_HASH, |
|
160 | - $identifier_callback = '', |
|
161 | - LocatorInterface $file_locator = null |
|
162 | - ) { |
|
163 | - try { |
|
164 | - $this->setCollectionName($collection_name); |
|
165 | - $this->setCollectionInterface($collection_interface); |
|
166 | - $this->setCollectionFQCNs($collection_FQCNs); |
|
167 | - $this->setCollectionPaths($collection_paths); |
|
168 | - $this->setFileMasks($file_mask); |
|
169 | - $this->setIdentifierType($identifier_type); |
|
170 | - $this->setIdentifierCallback($identifier_callback); |
|
171 | - $this->file_locator = $file_locator; |
|
172 | - } catch (Exception $exception) { |
|
173 | - throw new CollectionDetailsException($exception); |
|
174 | - } |
|
175 | - } |
|
176 | - |
|
177 | - |
|
178 | - /** |
|
179 | - * @access public |
|
180 | - * @return mixed |
|
181 | - */ |
|
182 | - public function getCollectionInterface() |
|
183 | - { |
|
184 | - return $this->collection_interface; |
|
185 | - } |
|
186 | - |
|
187 | - |
|
188 | - /** |
|
189 | - * @access protected |
|
190 | - * @param string $collection_interface |
|
191 | - * @throws \EventEspresso\core\exceptions\InvalidInterfaceException |
|
192 | - */ |
|
193 | - protected function setCollectionInterface($collection_interface) |
|
194 | - { |
|
195 | - if (! (interface_exists($collection_interface) || class_exists($collection_interface))) { |
|
196 | - throw new InvalidInterfaceException($collection_interface); |
|
197 | - } |
|
198 | - $this->collection_interface = $collection_interface; |
|
199 | - } |
|
200 | - |
|
201 | - |
|
202 | - /** |
|
203 | - * the collection name will be used for creating dynamic filters |
|
204 | - * |
|
205 | - * @access public |
|
206 | - * @return string |
|
207 | - */ |
|
208 | - public function collectionName() |
|
209 | - { |
|
210 | - return $this->collection_name; |
|
211 | - } |
|
212 | - |
|
213 | - |
|
214 | - /** |
|
215 | - * sanitizes collection name and converts spaces and dashes to underscores |
|
216 | - * |
|
217 | - * @access protected |
|
218 | - * @param string $collection_name |
|
219 | - * @throws \EventEspresso\core\exceptions\InvalidDataTypeException |
|
220 | - */ |
|
221 | - protected function setCollectionName($collection_name) |
|
222 | - { |
|
223 | - if (! is_string($collection_name)) { |
|
224 | - throw new InvalidDataTypeException('$collection_name', $collection_name, 'string'); |
|
225 | - } |
|
226 | - $this->collection_name = str_replace( |
|
227 | - '-', |
|
228 | - '_', |
|
229 | - sanitize_title_with_dashes($collection_name, '', 'save') |
|
230 | - ); |
|
231 | - } |
|
232 | - |
|
233 | - |
|
234 | - /** |
|
235 | - * @access public |
|
236 | - * @return string |
|
237 | - */ |
|
238 | - public function identifierType() |
|
239 | - { |
|
240 | - return $this->identifier_type; |
|
241 | - } |
|
242 | - |
|
243 | - |
|
244 | - /** |
|
245 | - * @access protected |
|
246 | - * @param string $identifier_type |
|
247 | - * @throws InvalidIdentifierException |
|
248 | - */ |
|
249 | - protected function setIdentifierType($identifier_type) |
|
250 | - { |
|
251 | - if ( |
|
252 | - ! ($identifier_type === CollectionDetails::ID_CLASS_NAME |
|
253 | - || $identifier_type === CollectionDetails::ID_OBJECT_HASH |
|
254 | - || $identifier_type === CollectionDetails::ID_CALLBACK_METHOD |
|
255 | - ) |
|
256 | - ) { |
|
257 | - throw new InvalidIdentifierException( |
|
258 | - $identifier_type, |
|
259 | - 'CollectionDetails::ID_CLASS_NAME or CollectionDetails::ID_OBJECT_HASH or CollectionDetails::ID_CALLBACK_METHOD' |
|
260 | - ); |
|
261 | - } |
|
262 | - $this->identifier_type = $identifier_type; |
|
263 | - } |
|
264 | - |
|
265 | - |
|
266 | - /** |
|
267 | - * @access public |
|
268 | - * @return string |
|
269 | - */ |
|
270 | - public function identifierCallback() |
|
271 | - { |
|
272 | - return $this->identifier_callback; |
|
273 | - } |
|
274 | - |
|
275 | - |
|
276 | - /** |
|
277 | - * @access protected |
|
278 | - * @param string $identifier_callback |
|
279 | - * @throws \EventEspresso\core\exceptions\InvalidDataTypeException |
|
280 | - */ |
|
281 | - protected function setIdentifierCallback($identifier_callback = 'identifier') |
|
282 | - { |
|
283 | - if (! is_string($identifier_callback)) { |
|
284 | - throw new InvalidDataTypeException('$identifier_callback', $identifier_callback, 'string'); |
|
285 | - } |
|
286 | - $this->identifier_callback = $identifier_callback; |
|
287 | - } |
|
288 | - |
|
289 | - |
|
290 | - /** |
|
291 | - * @access public |
|
292 | - * @return string |
|
293 | - */ |
|
294 | - public function getFileMask() |
|
295 | - { |
|
296 | - return $this->file_mask; |
|
297 | - } |
|
298 | - |
|
299 | - |
|
300 | - /** |
|
301 | - * sets the file mask which is then used to filter what files get loaded |
|
302 | - * when searching for classes to add to the collection. Defaults to '*.php' |
|
303 | - * |
|
304 | - * @access protected |
|
305 | - * @param string $file_mask |
|
306 | - * @throws \EventEspresso\core\exceptions\InvalidDataTypeException |
|
307 | - */ |
|
308 | - protected function setFileMasks($file_mask) |
|
309 | - { |
|
310 | - $this->file_mask = ! empty($file_mask) ? $file_mask : '*.php'; |
|
311 | - // we know our default is a string, so if it's not a string now, |
|
312 | - // then that means the incoming parameter was something else |
|
313 | - if (! is_string($this->file_mask)) { |
|
314 | - throw new InvalidDataTypeException('$file_mask', $this->file_mask, 'string'); |
|
315 | - } |
|
316 | - } |
|
317 | - |
|
318 | - |
|
319 | - /** |
|
320 | - * @access public |
|
321 | - * @return array |
|
322 | - */ |
|
323 | - public function getCollectionFQCNs() |
|
324 | - { |
|
325 | - return $this->collection_FQCNs; |
|
326 | - } |
|
327 | - |
|
328 | - |
|
329 | - /** |
|
330 | - * @access public |
|
331 | - * @param string|array $collection_FQCNs |
|
332 | - * @throws \EventEspresso\core\exceptions\InvalidClassException |
|
333 | - * @throws \EventEspresso\core\exceptions\InvalidDataTypeException |
|
334 | - */ |
|
335 | - public function setCollectionFQCNs($collection_FQCNs) |
|
336 | - { |
|
337 | - foreach ((array) $collection_FQCNs as $collection_FQCN) { |
|
338 | - if (! empty($collection_FQCN)) { |
|
339 | - if (class_exists($collection_FQCN)) { |
|
340 | - $this->collection_FQCNs[] = $collection_FQCN; |
|
341 | - } else { |
|
342 | - foreach ($this->getFQCNsFromPartialNamespace($collection_FQCN) as $FQCN) { |
|
343 | - $this->collection_FQCNs[] = $FQCN; |
|
344 | - } |
|
345 | - } |
|
346 | - } |
|
347 | - } |
|
348 | - } |
|
349 | - |
|
350 | - |
|
351 | - /** |
|
352 | - * @access protected |
|
353 | - * @param string $partial_FQCN |
|
354 | - * @return array |
|
355 | - * @throws \EventEspresso\core\exceptions\InvalidDataTypeException |
|
356 | - * @throws \EventEspresso\core\exceptions\InvalidClassException |
|
357 | - */ |
|
358 | - protected function getFQCNsFromPartialNamespace($partial_FQCN) |
|
359 | - { |
|
360 | - if (! $this->file_locator instanceof FqcnLocator) { |
|
361 | - $this->file_locator = new FqcnLocator(); |
|
362 | - } |
|
363 | - $this->file_locator->locate($partial_FQCN); |
|
364 | - return $this->file_locator->getFQCNs(); |
|
365 | - } |
|
366 | - |
|
367 | - |
|
368 | - /** |
|
369 | - * @access public |
|
370 | - * @return array |
|
371 | - */ |
|
372 | - public function getCollectionPaths() |
|
373 | - { |
|
374 | - return $this->collection_paths; |
|
375 | - } |
|
376 | - |
|
377 | - |
|
378 | - /** |
|
379 | - * @access public |
|
380 | - * @param string|array $collection_paths |
|
381 | - * @throws \EventEspresso\core\exceptions\InvalidFilePathException |
|
382 | - */ |
|
383 | - public function setCollectionPaths($collection_paths) |
|
384 | - { |
|
385 | - foreach ((array) $collection_paths as $collection_path) { |
|
386 | - if (! empty($collection_path)) { |
|
387 | - if (! is_readable($collection_path)) { |
|
388 | - throw new InvalidFilePathException($collection_path); |
|
389 | - } |
|
390 | - $this->collection_paths[] = $collection_path; |
|
391 | - } |
|
392 | - } |
|
393 | - } |
|
45 | + /** |
|
46 | + * if $identifier_type is set to this, |
|
47 | + * then the collection will use each object's spl_object_hash() as it's identifier |
|
48 | + */ |
|
49 | + const ID_OBJECT_HASH = 'identifier-uses-spl-object-hash'; |
|
50 | + |
|
51 | + /** |
|
52 | + * if $identifier_type is set to this, |
|
53 | + * then the collection will use each object's class name as it's identifier |
|
54 | + */ |
|
55 | + const ID_CLASS_NAME = 'identifier-uses-object-class-name'; |
|
56 | + |
|
57 | + /** |
|
58 | + * if $identifier_type is set to this, |
|
59 | + * then the collection will use the return value from a specified callback method on each object |
|
60 | + */ |
|
61 | + const ID_CALLBACK_METHOD = 'identifier-uses-callback-method'; |
|
62 | + |
|
63 | + /** |
|
64 | + * The interface used for controlling what gets added to the collection |
|
65 | + * |
|
66 | + * @var string $collection_interface |
|
67 | + */ |
|
68 | + protected $collection_interface = ''; |
|
69 | + |
|
70 | + /** |
|
71 | + * a unique name used to identify the collection in filter names |
|
72 | + * supplied value is run through sanitize_title_with_dashes(), |
|
73 | + * but then also converts dashes to underscores |
|
74 | + * |
|
75 | + * @var string $collection_name |
|
76 | + */ |
|
77 | + protected $collection_name = ''; |
|
78 | + |
|
79 | + /** |
|
80 | + * what the collection uses for the object identifier. |
|
81 | + * corresponds to one of the class constants above. |
|
82 | + * CollectionDetails::ID_OBJECT_HASH will use spl_object_hash( object ) for the identifier |
|
83 | + * CollectionDetails::ID_CLASS_NAME will use get_class( object ) for the identifier |
|
84 | + * CollectionDetails::ID_CALLBACK_METHOD will use a callback for the identifier |
|
85 | + * defaults to using spl_object_hash() so that multiple objects of the same class can be added |
|
86 | + * |
|
87 | + * @var string $identifier_type |
|
88 | + */ |
|
89 | + protected $identifier_type = CollectionDetails::ID_OBJECT_HASH; |
|
90 | + |
|
91 | + /** |
|
92 | + * the pattern applied to paths when searching for class files to add to the collection |
|
93 | + * ie: "My_Awesome_*.class.php" |
|
94 | + * defaults to "*.php" |
|
95 | + * |
|
96 | + * @var string $file_mask |
|
97 | + */ |
|
98 | + protected $file_mask = ''; |
|
99 | + |
|
100 | + /** |
|
101 | + * if the $identifier_type above is set to CollectionDetails::ID_CALLBACK_METHOD, |
|
102 | + * then this specifies the method to use on each entity. |
|
103 | + * If the callback method does not exist, then an exception will be thrown |
|
104 | + * |
|
105 | + * @var string $identifier_callback |
|
106 | + */ |
|
107 | + protected $identifier_callback = ''; |
|
108 | + |
|
109 | + /** |
|
110 | + * an array of Fully Qualified Class Names |
|
111 | + * for example: |
|
112 | + * $FQCNs = array( |
|
113 | + * '/Fully/Qualified/ClassNameA' |
|
114 | + * '/Fully/Qualified/Other/ClassNameB' |
|
115 | + * ); |
|
116 | + * |
|
117 | + * @var array $collection_FQCNs |
|
118 | + */ |
|
119 | + protected $collection_FQCNs = array(); |
|
120 | + |
|
121 | + /** |
|
122 | + * an array of full server paths to folders containing files to be loaded into collection |
|
123 | + * for example: |
|
124 | + * $paths = array( |
|
125 | + * '/full/server/path/to/ClassNameA.ext.php' // for class ClassNameA |
|
126 | + * '/full/server/path/to/other/ClassNameB.php' // for class ClassNameB |
|
127 | + * ); |
|
128 | + * |
|
129 | + * @var array $collection_paths |
|
130 | + */ |
|
131 | + protected $collection_paths = array(); |
|
132 | + |
|
133 | + /** |
|
134 | + * @var LocatorInterface $file_locator |
|
135 | + */ |
|
136 | + protected $file_locator; |
|
137 | + |
|
138 | + |
|
139 | + /** |
|
140 | + * CollectionDetails constructor. |
|
141 | + * |
|
142 | + * @access public |
|
143 | + * @param string $collection_name |
|
144 | + * @param string $collection_interface |
|
145 | + * @param array $collection_FQCNs |
|
146 | + * @param array $collection_paths |
|
147 | + * @param string $file_mask |
|
148 | + * @param string $identifier_type |
|
149 | + * @param string $identifier_callback |
|
150 | + * @param LocatorInterface $file_locator |
|
151 | + * @throws CollectionDetailsException |
|
152 | + */ |
|
153 | + public function __construct( |
|
154 | + $collection_name, |
|
155 | + $collection_interface, |
|
156 | + array $collection_FQCNs = array(), |
|
157 | + array $collection_paths = array(), |
|
158 | + $file_mask = '', |
|
159 | + $identifier_type = CollectionDetails::ID_OBJECT_HASH, |
|
160 | + $identifier_callback = '', |
|
161 | + LocatorInterface $file_locator = null |
|
162 | + ) { |
|
163 | + try { |
|
164 | + $this->setCollectionName($collection_name); |
|
165 | + $this->setCollectionInterface($collection_interface); |
|
166 | + $this->setCollectionFQCNs($collection_FQCNs); |
|
167 | + $this->setCollectionPaths($collection_paths); |
|
168 | + $this->setFileMasks($file_mask); |
|
169 | + $this->setIdentifierType($identifier_type); |
|
170 | + $this->setIdentifierCallback($identifier_callback); |
|
171 | + $this->file_locator = $file_locator; |
|
172 | + } catch (Exception $exception) { |
|
173 | + throw new CollectionDetailsException($exception); |
|
174 | + } |
|
175 | + } |
|
176 | + |
|
177 | + |
|
178 | + /** |
|
179 | + * @access public |
|
180 | + * @return mixed |
|
181 | + */ |
|
182 | + public function getCollectionInterface() |
|
183 | + { |
|
184 | + return $this->collection_interface; |
|
185 | + } |
|
186 | + |
|
187 | + |
|
188 | + /** |
|
189 | + * @access protected |
|
190 | + * @param string $collection_interface |
|
191 | + * @throws \EventEspresso\core\exceptions\InvalidInterfaceException |
|
192 | + */ |
|
193 | + protected function setCollectionInterface($collection_interface) |
|
194 | + { |
|
195 | + if (! (interface_exists($collection_interface) || class_exists($collection_interface))) { |
|
196 | + throw new InvalidInterfaceException($collection_interface); |
|
197 | + } |
|
198 | + $this->collection_interface = $collection_interface; |
|
199 | + } |
|
200 | + |
|
201 | + |
|
202 | + /** |
|
203 | + * the collection name will be used for creating dynamic filters |
|
204 | + * |
|
205 | + * @access public |
|
206 | + * @return string |
|
207 | + */ |
|
208 | + public function collectionName() |
|
209 | + { |
|
210 | + return $this->collection_name; |
|
211 | + } |
|
212 | + |
|
213 | + |
|
214 | + /** |
|
215 | + * sanitizes collection name and converts spaces and dashes to underscores |
|
216 | + * |
|
217 | + * @access protected |
|
218 | + * @param string $collection_name |
|
219 | + * @throws \EventEspresso\core\exceptions\InvalidDataTypeException |
|
220 | + */ |
|
221 | + protected function setCollectionName($collection_name) |
|
222 | + { |
|
223 | + if (! is_string($collection_name)) { |
|
224 | + throw new InvalidDataTypeException('$collection_name', $collection_name, 'string'); |
|
225 | + } |
|
226 | + $this->collection_name = str_replace( |
|
227 | + '-', |
|
228 | + '_', |
|
229 | + sanitize_title_with_dashes($collection_name, '', 'save') |
|
230 | + ); |
|
231 | + } |
|
232 | + |
|
233 | + |
|
234 | + /** |
|
235 | + * @access public |
|
236 | + * @return string |
|
237 | + */ |
|
238 | + public function identifierType() |
|
239 | + { |
|
240 | + return $this->identifier_type; |
|
241 | + } |
|
242 | + |
|
243 | + |
|
244 | + /** |
|
245 | + * @access protected |
|
246 | + * @param string $identifier_type |
|
247 | + * @throws InvalidIdentifierException |
|
248 | + */ |
|
249 | + protected function setIdentifierType($identifier_type) |
|
250 | + { |
|
251 | + if ( |
|
252 | + ! ($identifier_type === CollectionDetails::ID_CLASS_NAME |
|
253 | + || $identifier_type === CollectionDetails::ID_OBJECT_HASH |
|
254 | + || $identifier_type === CollectionDetails::ID_CALLBACK_METHOD |
|
255 | + ) |
|
256 | + ) { |
|
257 | + throw new InvalidIdentifierException( |
|
258 | + $identifier_type, |
|
259 | + 'CollectionDetails::ID_CLASS_NAME or CollectionDetails::ID_OBJECT_HASH or CollectionDetails::ID_CALLBACK_METHOD' |
|
260 | + ); |
|
261 | + } |
|
262 | + $this->identifier_type = $identifier_type; |
|
263 | + } |
|
264 | + |
|
265 | + |
|
266 | + /** |
|
267 | + * @access public |
|
268 | + * @return string |
|
269 | + */ |
|
270 | + public function identifierCallback() |
|
271 | + { |
|
272 | + return $this->identifier_callback; |
|
273 | + } |
|
274 | + |
|
275 | + |
|
276 | + /** |
|
277 | + * @access protected |
|
278 | + * @param string $identifier_callback |
|
279 | + * @throws \EventEspresso\core\exceptions\InvalidDataTypeException |
|
280 | + */ |
|
281 | + protected function setIdentifierCallback($identifier_callback = 'identifier') |
|
282 | + { |
|
283 | + if (! is_string($identifier_callback)) { |
|
284 | + throw new InvalidDataTypeException('$identifier_callback', $identifier_callback, 'string'); |
|
285 | + } |
|
286 | + $this->identifier_callback = $identifier_callback; |
|
287 | + } |
|
288 | + |
|
289 | + |
|
290 | + /** |
|
291 | + * @access public |
|
292 | + * @return string |
|
293 | + */ |
|
294 | + public function getFileMask() |
|
295 | + { |
|
296 | + return $this->file_mask; |
|
297 | + } |
|
298 | + |
|
299 | + |
|
300 | + /** |
|
301 | + * sets the file mask which is then used to filter what files get loaded |
|
302 | + * when searching for classes to add to the collection. Defaults to '*.php' |
|
303 | + * |
|
304 | + * @access protected |
|
305 | + * @param string $file_mask |
|
306 | + * @throws \EventEspresso\core\exceptions\InvalidDataTypeException |
|
307 | + */ |
|
308 | + protected function setFileMasks($file_mask) |
|
309 | + { |
|
310 | + $this->file_mask = ! empty($file_mask) ? $file_mask : '*.php'; |
|
311 | + // we know our default is a string, so if it's not a string now, |
|
312 | + // then that means the incoming parameter was something else |
|
313 | + if (! is_string($this->file_mask)) { |
|
314 | + throw new InvalidDataTypeException('$file_mask', $this->file_mask, 'string'); |
|
315 | + } |
|
316 | + } |
|
317 | + |
|
318 | + |
|
319 | + /** |
|
320 | + * @access public |
|
321 | + * @return array |
|
322 | + */ |
|
323 | + public function getCollectionFQCNs() |
|
324 | + { |
|
325 | + return $this->collection_FQCNs; |
|
326 | + } |
|
327 | + |
|
328 | + |
|
329 | + /** |
|
330 | + * @access public |
|
331 | + * @param string|array $collection_FQCNs |
|
332 | + * @throws \EventEspresso\core\exceptions\InvalidClassException |
|
333 | + * @throws \EventEspresso\core\exceptions\InvalidDataTypeException |
|
334 | + */ |
|
335 | + public function setCollectionFQCNs($collection_FQCNs) |
|
336 | + { |
|
337 | + foreach ((array) $collection_FQCNs as $collection_FQCN) { |
|
338 | + if (! empty($collection_FQCN)) { |
|
339 | + if (class_exists($collection_FQCN)) { |
|
340 | + $this->collection_FQCNs[] = $collection_FQCN; |
|
341 | + } else { |
|
342 | + foreach ($this->getFQCNsFromPartialNamespace($collection_FQCN) as $FQCN) { |
|
343 | + $this->collection_FQCNs[] = $FQCN; |
|
344 | + } |
|
345 | + } |
|
346 | + } |
|
347 | + } |
|
348 | + } |
|
349 | + |
|
350 | + |
|
351 | + /** |
|
352 | + * @access protected |
|
353 | + * @param string $partial_FQCN |
|
354 | + * @return array |
|
355 | + * @throws \EventEspresso\core\exceptions\InvalidDataTypeException |
|
356 | + * @throws \EventEspresso\core\exceptions\InvalidClassException |
|
357 | + */ |
|
358 | + protected function getFQCNsFromPartialNamespace($partial_FQCN) |
|
359 | + { |
|
360 | + if (! $this->file_locator instanceof FqcnLocator) { |
|
361 | + $this->file_locator = new FqcnLocator(); |
|
362 | + } |
|
363 | + $this->file_locator->locate($partial_FQCN); |
|
364 | + return $this->file_locator->getFQCNs(); |
|
365 | + } |
|
366 | + |
|
367 | + |
|
368 | + /** |
|
369 | + * @access public |
|
370 | + * @return array |
|
371 | + */ |
|
372 | + public function getCollectionPaths() |
|
373 | + { |
|
374 | + return $this->collection_paths; |
|
375 | + } |
|
376 | + |
|
377 | + |
|
378 | + /** |
|
379 | + * @access public |
|
380 | + * @param string|array $collection_paths |
|
381 | + * @throws \EventEspresso\core\exceptions\InvalidFilePathException |
|
382 | + */ |
|
383 | + public function setCollectionPaths($collection_paths) |
|
384 | + { |
|
385 | + foreach ((array) $collection_paths as $collection_path) { |
|
386 | + if (! empty($collection_path)) { |
|
387 | + if (! is_readable($collection_path)) { |
|
388 | + throw new InvalidFilePathException($collection_path); |
|
389 | + } |
|
390 | + $this->collection_paths[] = $collection_path; |
|
391 | + } |
|
392 | + } |
|
393 | + } |
|
394 | 394 | } |
@@ -85,7 +85,7 @@ discard block |
||
85 | 85 | */ |
86 | 86 | public function setReturnUrl($return_url) |
87 | 87 | { |
88 | - if (! is_string($return_url)) { |
|
88 | + if ( ! is_string($return_url)) { |
|
89 | 89 | throw new InvalidDataTypeException('$return_url', $return_url, 'string'); |
90 | 90 | } |
91 | 91 | $this->return_url = $return_url; |
@@ -102,7 +102,7 @@ discard block |
||
102 | 102 | */ |
103 | 103 | protected function getPersistentAdminNoticeCollection() |
104 | 104 | { |
105 | - if (! $this->notice_collection instanceof Collection) { |
|
105 | + if ( ! $this->notice_collection instanceof Collection) { |
|
106 | 106 | $this->notice_collection = new Collection( |
107 | 107 | 'EventEspresso\core\domain\entities\notifications\PersistentAdminNotice' |
108 | 108 | ); |
@@ -125,7 +125,7 @@ discard block |
||
125 | 125 | protected function retrieveStoredNotices() |
126 | 126 | { |
127 | 127 | $persistent_admin_notices = get_option(PersistentAdminNoticeManager::WP_OPTION_KEY, array()); |
128 | - if (! empty($persistent_admin_notices)) { |
|
128 | + if ( ! empty($persistent_admin_notices)) { |
|
129 | 129 | foreach ($persistent_admin_notices as $name => $details) { |
130 | 130 | if (is_array($details)) { |
131 | 131 | if ( |
@@ -247,14 +247,14 @@ discard block |
||
247 | 247 | { |
248 | 248 | wp_register_script( |
249 | 249 | 'espresso_core', |
250 | - EE_GLOBAL_ASSETS_URL . 'scripts/espresso_core.js', |
|
250 | + EE_GLOBAL_ASSETS_URL.'scripts/espresso_core.js', |
|
251 | 251 | array('jquery'), |
252 | 252 | EVENT_ESPRESSO_VERSION, |
253 | 253 | true |
254 | 254 | ); |
255 | 255 | wp_register_script( |
256 | 256 | 'ee_error_js', |
257 | - EE_GLOBAL_ASSETS_URL . 'scripts/EE_Error.js', |
|
257 | + EE_GLOBAL_ASSETS_URL.'scripts/EE_Error.js', |
|
258 | 258 | array('espresso_core'), |
259 | 259 | EVENT_ESPRESSO_VERSION, |
260 | 260 | true |
@@ -285,7 +285,7 @@ discard block |
||
285 | 285 | // used in template |
286 | 286 | $persistent_admin_notice_name = $persistent_admin_notice->getName(); |
287 | 287 | $persistent_admin_notice_message = $persistent_admin_notice->getMessage(); |
288 | - require EE_TEMPLATES . '/notifications/persistent_admin_notice.template.php'; |
|
288 | + require EE_TEMPLATES.'/notifications/persistent_admin_notice.template.php'; |
|
289 | 289 | } |
290 | 290 | |
291 | 291 | |
@@ -310,7 +310,7 @@ discard block |
||
310 | 310 | { |
311 | 311 | $pan_name = $this->request->getRequestParam('ee_nag_notice', $pan_name); |
312 | 312 | $this->notice_collection = $this->getPersistentAdminNoticeCollection(); |
313 | - if (! empty($pan_name) && $this->notice_collection->has($pan_name)) { |
|
313 | + if ( ! empty($pan_name) && $this->notice_collection->has($pan_name)) { |
|
314 | 314 | /** @var PersistentAdminNotice $persistent_admin_notice */ |
315 | 315 | $persistent_admin_notice = $this->notice_collection->get($pan_name); |
316 | 316 | $persistent_admin_notice->setDismissed(true); |
@@ -360,10 +360,10 @@ discard block |
||
360 | 360 | foreach ($this->notice_collection as $persistent_admin_notice) { |
361 | 361 | // are we deleting this notice ? |
362 | 362 | if ($persistent_admin_notice->getPurge()) { |
363 | - unset($persistent_admin_notices[ $persistent_admin_notice->getName() ]); |
|
363 | + unset($persistent_admin_notices[$persistent_admin_notice->getName()]); |
|
364 | 364 | } else { |
365 | 365 | /** @var PersistentAdminNotice $persistent_admin_notice */ |
366 | - $persistent_admin_notices[ $persistent_admin_notice->getName() ] = array( |
|
366 | + $persistent_admin_notices[$persistent_admin_notice->getName()] = array( |
|
367 | 367 | 'message' => $persistent_admin_notice->getMessage(), |
368 | 368 | 'capability' => $persistent_admin_notice->getCapability(), |
369 | 369 | 'cap_context' => $persistent_admin_notice->getCapContext(), |
@@ -30,392 +30,392 @@ |
||
30 | 30 | */ |
31 | 31 | class PersistentAdminNoticeManager |
32 | 32 | { |
33 | - const WP_OPTION_KEY = 'ee_pers_admin_notices'; |
|
34 | - |
|
35 | - /** |
|
36 | - * @var Collection|PersistentAdminNotice[] $notice_collection |
|
37 | - */ |
|
38 | - private $notice_collection; |
|
39 | - |
|
40 | - /** |
|
41 | - * if AJAX is not enabled, then the return URL will be used for redirecting back to the admin page where the |
|
42 | - * persistent admin notice was displayed, and ultimately dismissed from. |
|
43 | - * |
|
44 | - * @var string $return_url |
|
45 | - */ |
|
46 | - private $return_url; |
|
47 | - |
|
48 | - /** |
|
49 | - * @var CapabilitiesChecker $capabilities_checker |
|
50 | - */ |
|
51 | - private $capabilities_checker; |
|
52 | - |
|
53 | - /** |
|
54 | - * @var RequestInterface $request |
|
55 | - */ |
|
56 | - private $request; |
|
57 | - |
|
58 | - |
|
59 | - /** |
|
60 | - * PersistentAdminNoticeManager constructor |
|
61 | - * |
|
62 | - * @param CapabilitiesChecker $capabilities_checker |
|
63 | - * @param RequestInterface $request |
|
64 | - * @param string $return_url where to redirect to after dismissing notices |
|
65 | - * @throws InvalidDataTypeException |
|
66 | - */ |
|
67 | - public function __construct( |
|
68 | - CapabilitiesChecker $capabilities_checker, |
|
69 | - RequestInterface $request, |
|
70 | - string $return_url = '' |
|
71 | - ) { |
|
72 | - $this->setReturnUrl($return_url); |
|
73 | - $this->capabilities_checker = $capabilities_checker; |
|
74 | - $this->request = $request; |
|
75 | - // setup up notices at priority 9 because `EE_Admin::display_admin_notices()` runs at priority 10, |
|
76 | - // and we want to retrieve and generate any nag notices at the last possible moment |
|
77 | - add_action('admin_notices', array($this, 'displayNotices'), 9); |
|
78 | - add_action('network_admin_notices', array($this, 'displayNotices'), 9); |
|
79 | - add_action('wp_ajax_dismiss_ee_nag_notice', array($this, 'dismissNotice')); |
|
80 | - add_action('shutdown', array($this, 'registerAndSaveNotices'), 998); |
|
81 | - } |
|
82 | - |
|
83 | - |
|
84 | - /** |
|
85 | - * @param string $return_url |
|
86 | - * @throws InvalidDataTypeException |
|
87 | - */ |
|
88 | - public function setReturnUrl($return_url) |
|
89 | - { |
|
90 | - if (! is_string($return_url)) { |
|
91 | - throw new InvalidDataTypeException('$return_url', $return_url, 'string'); |
|
92 | - } |
|
93 | - $this->return_url = $return_url; |
|
94 | - } |
|
95 | - |
|
96 | - |
|
97 | - /** |
|
98 | - * @return Collection |
|
99 | - * @throws InvalidEntityException |
|
100 | - * @throws InvalidInterfaceException |
|
101 | - * @throws InvalidDataTypeException |
|
102 | - * @throws DomainException |
|
103 | - * @throws DuplicateCollectionIdentifierException |
|
104 | - */ |
|
105 | - protected function getPersistentAdminNoticeCollection() |
|
106 | - { |
|
107 | - if (! $this->notice_collection instanceof Collection) { |
|
108 | - $this->notice_collection = new Collection( |
|
109 | - 'EventEspresso\core\domain\entities\notifications\PersistentAdminNotice' |
|
110 | - ); |
|
111 | - $this->retrieveStoredNotices(); |
|
112 | - $this->registerNotices(); |
|
113 | - } |
|
114 | - return $this->notice_collection; |
|
115 | - } |
|
116 | - |
|
117 | - |
|
118 | - /** |
|
119 | - * generates PersistentAdminNotice objects for all non-dismissed notices saved to the db |
|
120 | - * |
|
121 | - * @return void |
|
122 | - * @throws InvalidEntityException |
|
123 | - * @throws DomainException |
|
124 | - * @throws InvalidDataTypeException |
|
125 | - * @throws DuplicateCollectionIdentifierException |
|
126 | - */ |
|
127 | - protected function retrieveStoredNotices() |
|
128 | - { |
|
129 | - $persistent_admin_notices = get_option(PersistentAdminNoticeManager::WP_OPTION_KEY, array()); |
|
130 | - if (! empty($persistent_admin_notices)) { |
|
131 | - foreach ($persistent_admin_notices as $name => $details) { |
|
132 | - if (is_array($details)) { |
|
133 | - if ( |
|
134 | - ! isset( |
|
135 | - $details['message'], |
|
136 | - $details['capability'], |
|
137 | - $details['cap_context'], |
|
138 | - $details['dismissed'] |
|
139 | - ) |
|
140 | - ) { |
|
141 | - throw new DomainException( |
|
142 | - sprintf( |
|
143 | - esc_html__( |
|
144 | - 'The "%1$s" PersistentAdminNotice could not be retrieved from the database.', |
|
145 | - 'event_espresso' |
|
146 | - ), |
|
147 | - $name |
|
148 | - ) |
|
149 | - ); |
|
150 | - } |
|
151 | - // new format for nag notices |
|
152 | - $this->notice_collection->add( |
|
153 | - new PersistentAdminNotice( |
|
154 | - $name, |
|
155 | - $details['message'], |
|
156 | - false, |
|
157 | - $details['capability'], |
|
158 | - $details['cap_context'], |
|
159 | - $details['dismissed'] |
|
160 | - ), |
|
161 | - sanitize_key($name) |
|
162 | - ); |
|
163 | - } else { |
|
164 | - try { |
|
165 | - // old nag notices, that we want to convert to the new format |
|
166 | - $this->notice_collection->add( |
|
167 | - new PersistentAdminNotice( |
|
168 | - $name, |
|
169 | - (string) $details, |
|
170 | - false, |
|
171 | - '', |
|
172 | - '', |
|
173 | - empty($details) |
|
174 | - ), |
|
175 | - sanitize_key($name) |
|
176 | - ); |
|
177 | - } catch (Exception $e) { |
|
178 | - EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__); |
|
179 | - } |
|
180 | - } |
|
181 | - // each notice will self register when the action hook in registerNotices is triggered |
|
182 | - } |
|
183 | - } |
|
184 | - } |
|
185 | - |
|
186 | - |
|
187 | - /** |
|
188 | - * exposes the Persistent Admin Notice Collection via an action |
|
189 | - * so that PersistentAdminNotice objects can be added and/or removed |
|
190 | - * without compromising the actual collection like a filter would |
|
191 | - */ |
|
192 | - protected function registerNotices() |
|
193 | - { |
|
194 | - do_action( |
|
195 | - 'AHEE__EventEspresso_core_services_notifications_PersistentAdminNoticeManager__registerNotices', |
|
196 | - $this->notice_collection |
|
197 | - ); |
|
198 | - } |
|
199 | - |
|
200 | - |
|
201 | - /** |
|
202 | - * @throws DomainException |
|
203 | - * @throws InvalidClassException |
|
204 | - * @throws InvalidDataTypeException |
|
205 | - * @throws InvalidInterfaceException |
|
206 | - * @throws InvalidEntityException |
|
207 | - * @throws DuplicateCollectionIdentifierException |
|
208 | - */ |
|
209 | - public function displayNotices() |
|
210 | - { |
|
211 | - $this->notice_collection = $this->getPersistentAdminNoticeCollection(); |
|
212 | - if ($this->notice_collection->hasObjects()) { |
|
213 | - $enqueue_assets = false; |
|
214 | - // and display notices |
|
215 | - foreach ($this->notice_collection as $persistent_admin_notice) { |
|
216 | - /** @var PersistentAdminNotice $persistent_admin_notice */ |
|
217 | - // don't display notices that have already been dismissed |
|
218 | - if ($persistent_admin_notice->getDismissed()) { |
|
219 | - continue; |
|
220 | - } |
|
221 | - try { |
|
222 | - $this->capabilities_checker->processCapCheck( |
|
223 | - $persistent_admin_notice->getCapCheck() |
|
224 | - ); |
|
225 | - } catch (InsufficientPermissionsException $e) { |
|
226 | - // user does not have required cap, so skip to next notice |
|
227 | - // and just eat the exception - nom nom nom nom |
|
228 | - continue; |
|
229 | - } |
|
230 | - if ($persistent_admin_notice->getMessage() === '') { |
|
231 | - continue; |
|
232 | - } |
|
233 | - $this->displayPersistentAdminNotice($persistent_admin_notice); |
|
234 | - $enqueue_assets = true; |
|
235 | - } |
|
236 | - if ($enqueue_assets) { |
|
237 | - $this->enqueueAssets(); |
|
238 | - } |
|
239 | - } |
|
240 | - } |
|
241 | - |
|
242 | - |
|
243 | - /** |
|
244 | - * does what it's named |
|
245 | - * |
|
246 | - * @return void |
|
247 | - */ |
|
248 | - public function enqueueAssets() |
|
249 | - { |
|
250 | - wp_register_script( |
|
251 | - 'espresso_core', |
|
252 | - EE_GLOBAL_ASSETS_URL . 'scripts/espresso_core.js', |
|
253 | - array('jquery'), |
|
254 | - EVENT_ESPRESSO_VERSION, |
|
255 | - true |
|
256 | - ); |
|
257 | - wp_register_script( |
|
258 | - 'ee_error_js', |
|
259 | - EE_GLOBAL_ASSETS_URL . 'scripts/EE_Error.js', |
|
260 | - array('espresso_core'), |
|
261 | - EVENT_ESPRESSO_VERSION, |
|
262 | - true |
|
263 | - ); |
|
264 | - wp_localize_script( |
|
265 | - 'ee_error_js', |
|
266 | - 'ee_dismiss', |
|
267 | - array( |
|
268 | - 'return_url' => urlencode($this->return_url), |
|
269 | - 'ajax_url' => WP_AJAX_URL, |
|
270 | - 'unknown_error' => wp_strip_all_tags( |
|
271 | - __( |
|
272 | - 'An unknown error has occurred on the server while attempting to dismiss this notice.', |
|
273 | - 'event_espresso' |
|
274 | - ) |
|
275 | - ), |
|
276 | - ) |
|
277 | - ); |
|
278 | - wp_enqueue_script('ee_error_js'); |
|
279 | - } |
|
280 | - |
|
281 | - |
|
282 | - /** |
|
283 | - * displayPersistentAdminNoticeHtml |
|
284 | - * |
|
285 | - * @param PersistentAdminNotice $persistent_admin_notice |
|
286 | - */ |
|
287 | - protected function displayPersistentAdminNotice(PersistentAdminNotice $persistent_admin_notice) |
|
288 | - { |
|
289 | - // used in template |
|
290 | - $persistent_admin_notice_name = $persistent_admin_notice->getName(); |
|
291 | - $persistent_admin_notice_message = $persistent_admin_notice->getMessage(); |
|
292 | - require EE_TEMPLATES . '/notifications/persistent_admin_notice.template.php'; |
|
293 | - } |
|
294 | - |
|
295 | - |
|
296 | - /** |
|
297 | - * dismissNotice |
|
298 | - * |
|
299 | - * @param string $pan_name the name, or key of the Persistent Admin Notice to be dismissed |
|
300 | - * @param bool $purge if true, then delete it from the db |
|
301 | - * @param bool $return forget all of this AJAX or redirect nonsense, and just return |
|
302 | - * @return void |
|
303 | - * @throws InvalidEntityException |
|
304 | - * @throws InvalidInterfaceException |
|
305 | - * @throws InvalidDataTypeException |
|
306 | - * @throws DomainException |
|
307 | - * @throws InvalidArgumentException |
|
308 | - * @throws InvalidArgumentException |
|
309 | - * @throws InvalidArgumentException |
|
310 | - * @throws InvalidArgumentException |
|
311 | - * @throws DuplicateCollectionIdentifierException |
|
312 | - */ |
|
313 | - public function dismissNotice($pan_name = '', $purge = false, $return = false) |
|
314 | - { |
|
315 | - $pan_name = $this->request->getRequestParam('ee_nag_notice', $pan_name); |
|
316 | - $this->notice_collection = $this->getPersistentAdminNoticeCollection(); |
|
317 | - if (! empty($pan_name) && $this->notice_collection->has($pan_name)) { |
|
318 | - /** @var PersistentAdminNotice $persistent_admin_notice */ |
|
319 | - $persistent_admin_notice = $this->notice_collection->get($pan_name); |
|
320 | - $persistent_admin_notice->setDismissed(true); |
|
321 | - $persistent_admin_notice->setPurge($purge); |
|
322 | - $this->saveNotices(); |
|
323 | - } |
|
324 | - if ($return) { |
|
325 | - return; |
|
326 | - } |
|
327 | - if ($this->request->isAjax()) { |
|
328 | - // grab any notices and concatenate into string |
|
329 | - echo wp_json_encode( |
|
330 | - array( |
|
331 | - 'errors' => implode('<br />', EE_Error::get_notices(false)), |
|
332 | - ) |
|
333 | - ); |
|
334 | - exit(); |
|
335 | - } |
|
336 | - // save errors to a transient to be displayed on next request (after redirect) |
|
337 | - EE_Error::get_notices(false, true); |
|
338 | - wp_safe_redirect( |
|
339 | - urldecode( |
|
340 | - $this->request->getRequestParam('return_url', '') |
|
341 | - ) |
|
342 | - ); |
|
343 | - } |
|
344 | - |
|
345 | - |
|
346 | - /** |
|
347 | - * saveNotices |
|
348 | - * |
|
349 | - * @throws DomainException |
|
350 | - * @throws InvalidDataTypeException |
|
351 | - * @throws InvalidInterfaceException |
|
352 | - * @throws InvalidEntityException |
|
353 | - * @throws DuplicateCollectionIdentifierException |
|
354 | - */ |
|
355 | - public function saveNotices() |
|
356 | - { |
|
357 | - $this->notice_collection = $this->getPersistentAdminNoticeCollection(); |
|
358 | - if ($this->notice_collection->hasObjects()) { |
|
359 | - $persistent_admin_notices = get_option(PersistentAdminNoticeManager::WP_OPTION_KEY, array()); |
|
360 | - // maybe initialize persistent_admin_notices |
|
361 | - if (empty($persistent_admin_notices)) { |
|
362 | - add_option(PersistentAdminNoticeManager::WP_OPTION_KEY, array(), '', 'no'); |
|
363 | - } |
|
364 | - foreach ($this->notice_collection as $persistent_admin_notice) { |
|
365 | - // are we deleting this notice ? |
|
366 | - if ($persistent_admin_notice->getPurge()) { |
|
367 | - unset($persistent_admin_notices[ $persistent_admin_notice->getName() ]); |
|
368 | - } else { |
|
369 | - /** @var PersistentAdminNotice $persistent_admin_notice */ |
|
370 | - $persistent_admin_notices[ $persistent_admin_notice->getName() ] = array( |
|
371 | - 'message' => $persistent_admin_notice->getMessage(), |
|
372 | - 'capability' => $persistent_admin_notice->getCapability(), |
|
373 | - 'cap_context' => $persistent_admin_notice->getCapContext(), |
|
374 | - 'dismissed' => $persistent_admin_notice->getDismissed(), |
|
375 | - ); |
|
376 | - } |
|
377 | - } |
|
378 | - update_option(PersistentAdminNoticeManager::WP_OPTION_KEY, $persistent_admin_notices); |
|
379 | - } |
|
380 | - } |
|
381 | - |
|
382 | - |
|
383 | - /** |
|
384 | - * @throws DomainException |
|
385 | - * @throws InvalidDataTypeException |
|
386 | - * @throws InvalidEntityException |
|
387 | - * @throws InvalidInterfaceException |
|
388 | - * @throws DuplicateCollectionIdentifierException |
|
389 | - */ |
|
390 | - public function registerAndSaveNotices() |
|
391 | - { |
|
392 | - $this->getPersistentAdminNoticeCollection(); |
|
393 | - $this->registerNotices(); |
|
394 | - $this->saveNotices(); |
|
395 | - add_filter( |
|
396 | - 'PersistentAdminNoticeManager__registerAndSaveNotices__complete', |
|
397 | - '__return_true' |
|
398 | - ); |
|
399 | - } |
|
400 | - |
|
401 | - |
|
402 | - /** |
|
403 | - * @throws DomainException |
|
404 | - * @throws InvalidDataTypeException |
|
405 | - * @throws InvalidEntityException |
|
406 | - * @throws InvalidInterfaceException |
|
407 | - * @throws InvalidArgumentException |
|
408 | - * @throws DuplicateCollectionIdentifierException |
|
409 | - */ |
|
410 | - public static function loadRegisterAndSaveNotices() |
|
411 | - { |
|
412 | - /** @var PersistentAdminNoticeManager $persistent_admin_notice_manager */ |
|
413 | - $persistent_admin_notice_manager = LoaderFactory::getLoader()->getShared( |
|
414 | - 'EventEspresso\core\services\notifications\PersistentAdminNoticeManager' |
|
415 | - ); |
|
416 | - // if shutdown has already run, then call registerAndSaveNotices() manually |
|
417 | - if (did_action('shutdown')) { |
|
418 | - $persistent_admin_notice_manager->registerAndSaveNotices(); |
|
419 | - } |
|
420 | - } |
|
33 | + const WP_OPTION_KEY = 'ee_pers_admin_notices'; |
|
34 | + |
|
35 | + /** |
|
36 | + * @var Collection|PersistentAdminNotice[] $notice_collection |
|
37 | + */ |
|
38 | + private $notice_collection; |
|
39 | + |
|
40 | + /** |
|
41 | + * if AJAX is not enabled, then the return URL will be used for redirecting back to the admin page where the |
|
42 | + * persistent admin notice was displayed, and ultimately dismissed from. |
|
43 | + * |
|
44 | + * @var string $return_url |
|
45 | + */ |
|
46 | + private $return_url; |
|
47 | + |
|
48 | + /** |
|
49 | + * @var CapabilitiesChecker $capabilities_checker |
|
50 | + */ |
|
51 | + private $capabilities_checker; |
|
52 | + |
|
53 | + /** |
|
54 | + * @var RequestInterface $request |
|
55 | + */ |
|
56 | + private $request; |
|
57 | + |
|
58 | + |
|
59 | + /** |
|
60 | + * PersistentAdminNoticeManager constructor |
|
61 | + * |
|
62 | + * @param CapabilitiesChecker $capabilities_checker |
|
63 | + * @param RequestInterface $request |
|
64 | + * @param string $return_url where to redirect to after dismissing notices |
|
65 | + * @throws InvalidDataTypeException |
|
66 | + */ |
|
67 | + public function __construct( |
|
68 | + CapabilitiesChecker $capabilities_checker, |
|
69 | + RequestInterface $request, |
|
70 | + string $return_url = '' |
|
71 | + ) { |
|
72 | + $this->setReturnUrl($return_url); |
|
73 | + $this->capabilities_checker = $capabilities_checker; |
|
74 | + $this->request = $request; |
|
75 | + // setup up notices at priority 9 because `EE_Admin::display_admin_notices()` runs at priority 10, |
|
76 | + // and we want to retrieve and generate any nag notices at the last possible moment |
|
77 | + add_action('admin_notices', array($this, 'displayNotices'), 9); |
|
78 | + add_action('network_admin_notices', array($this, 'displayNotices'), 9); |
|
79 | + add_action('wp_ajax_dismiss_ee_nag_notice', array($this, 'dismissNotice')); |
|
80 | + add_action('shutdown', array($this, 'registerAndSaveNotices'), 998); |
|
81 | + } |
|
82 | + |
|
83 | + |
|
84 | + /** |
|
85 | + * @param string $return_url |
|
86 | + * @throws InvalidDataTypeException |
|
87 | + */ |
|
88 | + public function setReturnUrl($return_url) |
|
89 | + { |
|
90 | + if (! is_string($return_url)) { |
|
91 | + throw new InvalidDataTypeException('$return_url', $return_url, 'string'); |
|
92 | + } |
|
93 | + $this->return_url = $return_url; |
|
94 | + } |
|
95 | + |
|
96 | + |
|
97 | + /** |
|
98 | + * @return Collection |
|
99 | + * @throws InvalidEntityException |
|
100 | + * @throws InvalidInterfaceException |
|
101 | + * @throws InvalidDataTypeException |
|
102 | + * @throws DomainException |
|
103 | + * @throws DuplicateCollectionIdentifierException |
|
104 | + */ |
|
105 | + protected function getPersistentAdminNoticeCollection() |
|
106 | + { |
|
107 | + if (! $this->notice_collection instanceof Collection) { |
|
108 | + $this->notice_collection = new Collection( |
|
109 | + 'EventEspresso\core\domain\entities\notifications\PersistentAdminNotice' |
|
110 | + ); |
|
111 | + $this->retrieveStoredNotices(); |
|
112 | + $this->registerNotices(); |
|
113 | + } |
|
114 | + return $this->notice_collection; |
|
115 | + } |
|
116 | + |
|
117 | + |
|
118 | + /** |
|
119 | + * generates PersistentAdminNotice objects for all non-dismissed notices saved to the db |
|
120 | + * |
|
121 | + * @return void |
|
122 | + * @throws InvalidEntityException |
|
123 | + * @throws DomainException |
|
124 | + * @throws InvalidDataTypeException |
|
125 | + * @throws DuplicateCollectionIdentifierException |
|
126 | + */ |
|
127 | + protected function retrieveStoredNotices() |
|
128 | + { |
|
129 | + $persistent_admin_notices = get_option(PersistentAdminNoticeManager::WP_OPTION_KEY, array()); |
|
130 | + if (! empty($persistent_admin_notices)) { |
|
131 | + foreach ($persistent_admin_notices as $name => $details) { |
|
132 | + if (is_array($details)) { |
|
133 | + if ( |
|
134 | + ! isset( |
|
135 | + $details['message'], |
|
136 | + $details['capability'], |
|
137 | + $details['cap_context'], |
|
138 | + $details['dismissed'] |
|
139 | + ) |
|
140 | + ) { |
|
141 | + throw new DomainException( |
|
142 | + sprintf( |
|
143 | + esc_html__( |
|
144 | + 'The "%1$s" PersistentAdminNotice could not be retrieved from the database.', |
|
145 | + 'event_espresso' |
|
146 | + ), |
|
147 | + $name |
|
148 | + ) |
|
149 | + ); |
|
150 | + } |
|
151 | + // new format for nag notices |
|
152 | + $this->notice_collection->add( |
|
153 | + new PersistentAdminNotice( |
|
154 | + $name, |
|
155 | + $details['message'], |
|
156 | + false, |
|
157 | + $details['capability'], |
|
158 | + $details['cap_context'], |
|
159 | + $details['dismissed'] |
|
160 | + ), |
|
161 | + sanitize_key($name) |
|
162 | + ); |
|
163 | + } else { |
|
164 | + try { |
|
165 | + // old nag notices, that we want to convert to the new format |
|
166 | + $this->notice_collection->add( |
|
167 | + new PersistentAdminNotice( |
|
168 | + $name, |
|
169 | + (string) $details, |
|
170 | + false, |
|
171 | + '', |
|
172 | + '', |
|
173 | + empty($details) |
|
174 | + ), |
|
175 | + sanitize_key($name) |
|
176 | + ); |
|
177 | + } catch (Exception $e) { |
|
178 | + EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__); |
|
179 | + } |
|
180 | + } |
|
181 | + // each notice will self register when the action hook in registerNotices is triggered |
|
182 | + } |
|
183 | + } |
|
184 | + } |
|
185 | + |
|
186 | + |
|
187 | + /** |
|
188 | + * exposes the Persistent Admin Notice Collection via an action |
|
189 | + * so that PersistentAdminNotice objects can be added and/or removed |
|
190 | + * without compromising the actual collection like a filter would |
|
191 | + */ |
|
192 | + protected function registerNotices() |
|
193 | + { |
|
194 | + do_action( |
|
195 | + 'AHEE__EventEspresso_core_services_notifications_PersistentAdminNoticeManager__registerNotices', |
|
196 | + $this->notice_collection |
|
197 | + ); |
|
198 | + } |
|
199 | + |
|
200 | + |
|
201 | + /** |
|
202 | + * @throws DomainException |
|
203 | + * @throws InvalidClassException |
|
204 | + * @throws InvalidDataTypeException |
|
205 | + * @throws InvalidInterfaceException |
|
206 | + * @throws InvalidEntityException |
|
207 | + * @throws DuplicateCollectionIdentifierException |
|
208 | + */ |
|
209 | + public function displayNotices() |
|
210 | + { |
|
211 | + $this->notice_collection = $this->getPersistentAdminNoticeCollection(); |
|
212 | + if ($this->notice_collection->hasObjects()) { |
|
213 | + $enqueue_assets = false; |
|
214 | + // and display notices |
|
215 | + foreach ($this->notice_collection as $persistent_admin_notice) { |
|
216 | + /** @var PersistentAdminNotice $persistent_admin_notice */ |
|
217 | + // don't display notices that have already been dismissed |
|
218 | + if ($persistent_admin_notice->getDismissed()) { |
|
219 | + continue; |
|
220 | + } |
|
221 | + try { |
|
222 | + $this->capabilities_checker->processCapCheck( |
|
223 | + $persistent_admin_notice->getCapCheck() |
|
224 | + ); |
|
225 | + } catch (InsufficientPermissionsException $e) { |
|
226 | + // user does not have required cap, so skip to next notice |
|
227 | + // and just eat the exception - nom nom nom nom |
|
228 | + continue; |
|
229 | + } |
|
230 | + if ($persistent_admin_notice->getMessage() === '') { |
|
231 | + continue; |
|
232 | + } |
|
233 | + $this->displayPersistentAdminNotice($persistent_admin_notice); |
|
234 | + $enqueue_assets = true; |
|
235 | + } |
|
236 | + if ($enqueue_assets) { |
|
237 | + $this->enqueueAssets(); |
|
238 | + } |
|
239 | + } |
|
240 | + } |
|
241 | + |
|
242 | + |
|
243 | + /** |
|
244 | + * does what it's named |
|
245 | + * |
|
246 | + * @return void |
|
247 | + */ |
|
248 | + public function enqueueAssets() |
|
249 | + { |
|
250 | + wp_register_script( |
|
251 | + 'espresso_core', |
|
252 | + EE_GLOBAL_ASSETS_URL . 'scripts/espresso_core.js', |
|
253 | + array('jquery'), |
|
254 | + EVENT_ESPRESSO_VERSION, |
|
255 | + true |
|
256 | + ); |
|
257 | + wp_register_script( |
|
258 | + 'ee_error_js', |
|
259 | + EE_GLOBAL_ASSETS_URL . 'scripts/EE_Error.js', |
|
260 | + array('espresso_core'), |
|
261 | + EVENT_ESPRESSO_VERSION, |
|
262 | + true |
|
263 | + ); |
|
264 | + wp_localize_script( |
|
265 | + 'ee_error_js', |
|
266 | + 'ee_dismiss', |
|
267 | + array( |
|
268 | + 'return_url' => urlencode($this->return_url), |
|
269 | + 'ajax_url' => WP_AJAX_URL, |
|
270 | + 'unknown_error' => wp_strip_all_tags( |
|
271 | + __( |
|
272 | + 'An unknown error has occurred on the server while attempting to dismiss this notice.', |
|
273 | + 'event_espresso' |
|
274 | + ) |
|
275 | + ), |
|
276 | + ) |
|
277 | + ); |
|
278 | + wp_enqueue_script('ee_error_js'); |
|
279 | + } |
|
280 | + |
|
281 | + |
|
282 | + /** |
|
283 | + * displayPersistentAdminNoticeHtml |
|
284 | + * |
|
285 | + * @param PersistentAdminNotice $persistent_admin_notice |
|
286 | + */ |
|
287 | + protected function displayPersistentAdminNotice(PersistentAdminNotice $persistent_admin_notice) |
|
288 | + { |
|
289 | + // used in template |
|
290 | + $persistent_admin_notice_name = $persistent_admin_notice->getName(); |
|
291 | + $persistent_admin_notice_message = $persistent_admin_notice->getMessage(); |
|
292 | + require EE_TEMPLATES . '/notifications/persistent_admin_notice.template.php'; |
|
293 | + } |
|
294 | + |
|
295 | + |
|
296 | + /** |
|
297 | + * dismissNotice |
|
298 | + * |
|
299 | + * @param string $pan_name the name, or key of the Persistent Admin Notice to be dismissed |
|
300 | + * @param bool $purge if true, then delete it from the db |
|
301 | + * @param bool $return forget all of this AJAX or redirect nonsense, and just return |
|
302 | + * @return void |
|
303 | + * @throws InvalidEntityException |
|
304 | + * @throws InvalidInterfaceException |
|
305 | + * @throws InvalidDataTypeException |
|
306 | + * @throws DomainException |
|
307 | + * @throws InvalidArgumentException |
|
308 | + * @throws InvalidArgumentException |
|
309 | + * @throws InvalidArgumentException |
|
310 | + * @throws InvalidArgumentException |
|
311 | + * @throws DuplicateCollectionIdentifierException |
|
312 | + */ |
|
313 | + public function dismissNotice($pan_name = '', $purge = false, $return = false) |
|
314 | + { |
|
315 | + $pan_name = $this->request->getRequestParam('ee_nag_notice', $pan_name); |
|
316 | + $this->notice_collection = $this->getPersistentAdminNoticeCollection(); |
|
317 | + if (! empty($pan_name) && $this->notice_collection->has($pan_name)) { |
|
318 | + /** @var PersistentAdminNotice $persistent_admin_notice */ |
|
319 | + $persistent_admin_notice = $this->notice_collection->get($pan_name); |
|
320 | + $persistent_admin_notice->setDismissed(true); |
|
321 | + $persistent_admin_notice->setPurge($purge); |
|
322 | + $this->saveNotices(); |
|
323 | + } |
|
324 | + if ($return) { |
|
325 | + return; |
|
326 | + } |
|
327 | + if ($this->request->isAjax()) { |
|
328 | + // grab any notices and concatenate into string |
|
329 | + echo wp_json_encode( |
|
330 | + array( |
|
331 | + 'errors' => implode('<br />', EE_Error::get_notices(false)), |
|
332 | + ) |
|
333 | + ); |
|
334 | + exit(); |
|
335 | + } |
|
336 | + // save errors to a transient to be displayed on next request (after redirect) |
|
337 | + EE_Error::get_notices(false, true); |
|
338 | + wp_safe_redirect( |
|
339 | + urldecode( |
|
340 | + $this->request->getRequestParam('return_url', '') |
|
341 | + ) |
|
342 | + ); |
|
343 | + } |
|
344 | + |
|
345 | + |
|
346 | + /** |
|
347 | + * saveNotices |
|
348 | + * |
|
349 | + * @throws DomainException |
|
350 | + * @throws InvalidDataTypeException |
|
351 | + * @throws InvalidInterfaceException |
|
352 | + * @throws InvalidEntityException |
|
353 | + * @throws DuplicateCollectionIdentifierException |
|
354 | + */ |
|
355 | + public function saveNotices() |
|
356 | + { |
|
357 | + $this->notice_collection = $this->getPersistentAdminNoticeCollection(); |
|
358 | + if ($this->notice_collection->hasObjects()) { |
|
359 | + $persistent_admin_notices = get_option(PersistentAdminNoticeManager::WP_OPTION_KEY, array()); |
|
360 | + // maybe initialize persistent_admin_notices |
|
361 | + if (empty($persistent_admin_notices)) { |
|
362 | + add_option(PersistentAdminNoticeManager::WP_OPTION_KEY, array(), '', 'no'); |
|
363 | + } |
|
364 | + foreach ($this->notice_collection as $persistent_admin_notice) { |
|
365 | + // are we deleting this notice ? |
|
366 | + if ($persistent_admin_notice->getPurge()) { |
|
367 | + unset($persistent_admin_notices[ $persistent_admin_notice->getName() ]); |
|
368 | + } else { |
|
369 | + /** @var PersistentAdminNotice $persistent_admin_notice */ |
|
370 | + $persistent_admin_notices[ $persistent_admin_notice->getName() ] = array( |
|
371 | + 'message' => $persistent_admin_notice->getMessage(), |
|
372 | + 'capability' => $persistent_admin_notice->getCapability(), |
|
373 | + 'cap_context' => $persistent_admin_notice->getCapContext(), |
|
374 | + 'dismissed' => $persistent_admin_notice->getDismissed(), |
|
375 | + ); |
|
376 | + } |
|
377 | + } |
|
378 | + update_option(PersistentAdminNoticeManager::WP_OPTION_KEY, $persistent_admin_notices); |
|
379 | + } |
|
380 | + } |
|
381 | + |
|
382 | + |
|
383 | + /** |
|
384 | + * @throws DomainException |
|
385 | + * @throws InvalidDataTypeException |
|
386 | + * @throws InvalidEntityException |
|
387 | + * @throws InvalidInterfaceException |
|
388 | + * @throws DuplicateCollectionIdentifierException |
|
389 | + */ |
|
390 | + public function registerAndSaveNotices() |
|
391 | + { |
|
392 | + $this->getPersistentAdminNoticeCollection(); |
|
393 | + $this->registerNotices(); |
|
394 | + $this->saveNotices(); |
|
395 | + add_filter( |
|
396 | + 'PersistentAdminNoticeManager__registerAndSaveNotices__complete', |
|
397 | + '__return_true' |
|
398 | + ); |
|
399 | + } |
|
400 | + |
|
401 | + |
|
402 | + /** |
|
403 | + * @throws DomainException |
|
404 | + * @throws InvalidDataTypeException |
|
405 | + * @throws InvalidEntityException |
|
406 | + * @throws InvalidInterfaceException |
|
407 | + * @throws InvalidArgumentException |
|
408 | + * @throws DuplicateCollectionIdentifierException |
|
409 | + */ |
|
410 | + public static function loadRegisterAndSaveNotices() |
|
411 | + { |
|
412 | + /** @var PersistentAdminNoticeManager $persistent_admin_notice_manager */ |
|
413 | + $persistent_admin_notice_manager = LoaderFactory::getLoader()->getShared( |
|
414 | + 'EventEspresso\core\services\notifications\PersistentAdminNoticeManager' |
|
415 | + ); |
|
416 | + // if shutdown has already run, then call registerAndSaveNotices() manually |
|
417 | + if (did_action('shutdown')) { |
|
418 | + $persistent_admin_notice_manager->registerAndSaveNotices(); |
|
419 | + } |
|
420 | + } |
|
421 | 421 | } |
@@ -32,7 +32,7 @@ discard block |
||
32 | 32 | public function ensureTableNameHasPrefix($table_name) |
33 | 33 | { |
34 | 34 | global $wpdb; |
35 | - return strpos($table_name, $wpdb->base_prefix) === 0 ? $table_name : $wpdb->prefix . $table_name; |
|
35 | + return strpos($table_name, $wpdb->base_prefix) === 0 ? $table_name : $wpdb->prefix.$table_name; |
|
36 | 36 | } |
37 | 37 | |
38 | 38 | |
@@ -81,7 +81,7 @@ discard block |
||
81 | 81 | $wpdb->last_error = $old_error; |
82 | 82 | $EZSQL_ERROR = $ezsql_error_cache; |
83 | 83 | // if there was a table doesn't exist error |
84 | - if (! empty($new_error)) { |
|
84 | + if ( ! empty($new_error)) { |
|
85 | 85 | if ( |
86 | 86 | in_array( |
87 | 87 | \EEH_Activation::last_wpdb_error_code(), |
@@ -13,132 +13,132 @@ |
||
13 | 13 | */ |
14 | 14 | class TableAnalysis extends \EE_Base |
15 | 15 | { |
16 | - /** |
|
17 | - * The maximum number of characters that can be indexed on a column using utf8mb4 collation, |
|
18 | - * see https://events.codebasehq.com/redirect?https://make.wordpress.org/core/2015/04/02/the-utf8mb4-upgrade/ |
|
19 | - */ |
|
20 | - const INDEX_COLUMN_SIZE = 191; |
|
16 | + /** |
|
17 | + * The maximum number of characters that can be indexed on a column using utf8mb4 collation, |
|
18 | + * see https://events.codebasehq.com/redirect?https://make.wordpress.org/core/2015/04/02/the-utf8mb4-upgrade/ |
|
19 | + */ |
|
20 | + const INDEX_COLUMN_SIZE = 191; |
|
21 | 21 | |
22 | - /** |
|
23 | - * Returns the table name which will definitely have the wpdb prefix on the front, |
|
24 | - * except if it currently has the wpdb->base_prefix on the front, in which case |
|
25 | - * it will have the wpdb->base_prefix on it |
|
26 | - * |
|
27 | - * @global \wpdb $wpdb |
|
28 | - * @param string $table_name |
|
29 | - * @return string $tableName, having ensured it has the wpdb prefix on the front |
|
30 | - */ |
|
31 | - public function ensureTableNameHasPrefix($table_name) |
|
32 | - { |
|
33 | - global $wpdb; |
|
34 | - return strpos($table_name, $wpdb->base_prefix) === 0 ? $table_name : $wpdb->prefix . $table_name; |
|
35 | - } |
|
22 | + /** |
|
23 | + * Returns the table name which will definitely have the wpdb prefix on the front, |
|
24 | + * except if it currently has the wpdb->base_prefix on the front, in which case |
|
25 | + * it will have the wpdb->base_prefix on it |
|
26 | + * |
|
27 | + * @global \wpdb $wpdb |
|
28 | + * @param string $table_name |
|
29 | + * @return string $tableName, having ensured it has the wpdb prefix on the front |
|
30 | + */ |
|
31 | + public function ensureTableNameHasPrefix($table_name) |
|
32 | + { |
|
33 | + global $wpdb; |
|
34 | + return strpos($table_name, $wpdb->base_prefix) === 0 ? $table_name : $wpdb->prefix . $table_name; |
|
35 | + } |
|
36 | 36 | |
37 | 37 | |
38 | - /** |
|
39 | - * Indicates whether or not the table has any entries. $table_name can |
|
40 | - * optionally start with $wpdb->prefix or not |
|
41 | - * |
|
42 | - * @global \wpdb $wpdb |
|
43 | - * @param string $table_name |
|
44 | - * @return bool |
|
45 | - */ |
|
46 | - public function tableIsEmpty($table_name) |
|
47 | - { |
|
48 | - global $wpdb; |
|
49 | - $table_name = $this->ensureTableNameHasPrefix($table_name); |
|
50 | - if ($this->tableExists($table_name)) { |
|
51 | - $count = $wpdb->get_var("SELECT COUNT(*) FROM $table_name"); |
|
52 | - return absint($count) === 0 ? true : false; |
|
53 | - } |
|
54 | - return false; |
|
55 | - } |
|
38 | + /** |
|
39 | + * Indicates whether or not the table has any entries. $table_name can |
|
40 | + * optionally start with $wpdb->prefix or not |
|
41 | + * |
|
42 | + * @global \wpdb $wpdb |
|
43 | + * @param string $table_name |
|
44 | + * @return bool |
|
45 | + */ |
|
46 | + public function tableIsEmpty($table_name) |
|
47 | + { |
|
48 | + global $wpdb; |
|
49 | + $table_name = $this->ensureTableNameHasPrefix($table_name); |
|
50 | + if ($this->tableExists($table_name)) { |
|
51 | + $count = $wpdb->get_var("SELECT COUNT(*) FROM $table_name"); |
|
52 | + return absint($count) === 0 ? true : false; |
|
53 | + } |
|
54 | + return false; |
|
55 | + } |
|
56 | 56 | |
57 | 57 | |
58 | - /** |
|
59 | - * Indicates whether or not the table exists. $table_name can optionally |
|
60 | - * have the $wpdb->prefix on the beginning, or not. |
|
61 | - * |
|
62 | - * @global \wpdb $wpdb |
|
63 | - * @global array EZSQL_Error |
|
64 | - * @param $table_name |
|
65 | - * @return bool |
|
66 | - */ |
|
67 | - public function tableExists($table_name) |
|
68 | - { |
|
69 | - global $wpdb, $EZSQL_ERROR; |
|
70 | - $table_name = $this->ensureTableNameHasPrefix($table_name); |
|
71 | - // ignore if this causes an sql error |
|
72 | - $old_error = $wpdb->last_error; |
|
73 | - $old_suppress_errors = $wpdb->suppress_errors(); |
|
74 | - $old_show_errors_value = $wpdb->show_errors(false); |
|
75 | - $ezsql_error_cache = $EZSQL_ERROR; |
|
76 | - $wpdb->get_results("SELECT * from $table_name LIMIT 1"); |
|
77 | - $wpdb->show_errors($old_show_errors_value); |
|
78 | - $wpdb->suppress_errors($old_suppress_errors); |
|
79 | - $new_error = $wpdb->last_error; |
|
80 | - $wpdb->last_error = $old_error; |
|
81 | - $EZSQL_ERROR = $ezsql_error_cache; |
|
82 | - // if there was a table doesn't exist error |
|
83 | - if (! empty($new_error)) { |
|
84 | - if ( |
|
85 | - in_array( |
|
86 | - \EEH_Activation::last_wpdb_error_code(), |
|
87 | - array( |
|
88 | - 1051, // bad table |
|
89 | - 1109, // unknown table |
|
90 | - 117, // no such table |
|
91 | - ) |
|
92 | - ) |
|
93 | - || |
|
94 | - preg_match( |
|
95 | - '~^Table .* doesn\'t exist~', |
|
96 | - $new_error |
|
97 | - ) // in case not using mysql and error codes aren't reliable, just check for this error string |
|
98 | - ) { |
|
99 | - return false; |
|
100 | - } else { |
|
101 | - // log this because that's weird. Just use the normal PHP error log |
|
102 | - error_log( |
|
103 | - sprintf( |
|
104 | - esc_html__( |
|
105 | - 'Event Espresso error detected when checking if table existed: %1$s (it wasn\'t just that the table didn\'t exist either)', |
|
106 | - 'event_espresso' |
|
107 | - ), |
|
108 | - $new_error |
|
109 | - ) |
|
110 | - ); |
|
111 | - } |
|
112 | - } |
|
113 | - return true; |
|
114 | - } |
|
58 | + /** |
|
59 | + * Indicates whether or not the table exists. $table_name can optionally |
|
60 | + * have the $wpdb->prefix on the beginning, or not. |
|
61 | + * |
|
62 | + * @global \wpdb $wpdb |
|
63 | + * @global array EZSQL_Error |
|
64 | + * @param $table_name |
|
65 | + * @return bool |
|
66 | + */ |
|
67 | + public function tableExists($table_name) |
|
68 | + { |
|
69 | + global $wpdb, $EZSQL_ERROR; |
|
70 | + $table_name = $this->ensureTableNameHasPrefix($table_name); |
|
71 | + // ignore if this causes an sql error |
|
72 | + $old_error = $wpdb->last_error; |
|
73 | + $old_suppress_errors = $wpdb->suppress_errors(); |
|
74 | + $old_show_errors_value = $wpdb->show_errors(false); |
|
75 | + $ezsql_error_cache = $EZSQL_ERROR; |
|
76 | + $wpdb->get_results("SELECT * from $table_name LIMIT 1"); |
|
77 | + $wpdb->show_errors($old_show_errors_value); |
|
78 | + $wpdb->suppress_errors($old_suppress_errors); |
|
79 | + $new_error = $wpdb->last_error; |
|
80 | + $wpdb->last_error = $old_error; |
|
81 | + $EZSQL_ERROR = $ezsql_error_cache; |
|
82 | + // if there was a table doesn't exist error |
|
83 | + if (! empty($new_error)) { |
|
84 | + if ( |
|
85 | + in_array( |
|
86 | + \EEH_Activation::last_wpdb_error_code(), |
|
87 | + array( |
|
88 | + 1051, // bad table |
|
89 | + 1109, // unknown table |
|
90 | + 117, // no such table |
|
91 | + ) |
|
92 | + ) |
|
93 | + || |
|
94 | + preg_match( |
|
95 | + '~^Table .* doesn\'t exist~', |
|
96 | + $new_error |
|
97 | + ) // in case not using mysql and error codes aren't reliable, just check for this error string |
|
98 | + ) { |
|
99 | + return false; |
|
100 | + } else { |
|
101 | + // log this because that's weird. Just use the normal PHP error log |
|
102 | + error_log( |
|
103 | + sprintf( |
|
104 | + esc_html__( |
|
105 | + 'Event Espresso error detected when checking if table existed: %1$s (it wasn\'t just that the table didn\'t exist either)', |
|
106 | + 'event_espresso' |
|
107 | + ), |
|
108 | + $new_error |
|
109 | + ) |
|
110 | + ); |
|
111 | + } |
|
112 | + } |
|
113 | + return true; |
|
114 | + } |
|
115 | 115 | |
116 | 116 | |
117 | - /** |
|
118 | - * @param $table_name |
|
119 | - * @param $index_name |
|
120 | - * @return array of columns used on that index, Each entry is an object with the following properties { |
|
121 | - * @type string Table |
|
122 | - * @type string Non_unique "0" or "1" |
|
123 | - * @type string Key_name |
|
124 | - * @type string Seq_in_index |
|
125 | - * @type string Column_name |
|
126 | - * @type string Collation |
|
127 | - * @type string Cardinality |
|
128 | - * @type string Sub_part on a column, usually this is just the number of characters from this column to use in |
|
129 | - * indexing |
|
130 | - * @type string|null Packed |
|
131 | - * @type string Null |
|
132 | - * @type string Index_type |
|
133 | - * @type string Comment |
|
134 | - * @type string Index_comment |
|
135 | - * } |
|
136 | - */ |
|
137 | - public function showIndexes($table_name, $index_name) |
|
138 | - { |
|
139 | - global $wpdb; |
|
140 | - $table_name = $this->ensureTableNameHasPrefix($table_name); |
|
141 | - $index_exists_query = "SHOW INDEX FROM {$table_name} WHERE Key_name = '{$index_name}'"; |
|
142 | - return $wpdb->get_results($index_exists_query); |
|
143 | - } |
|
117 | + /** |
|
118 | + * @param $table_name |
|
119 | + * @param $index_name |
|
120 | + * @return array of columns used on that index, Each entry is an object with the following properties { |
|
121 | + * @type string Table |
|
122 | + * @type string Non_unique "0" or "1" |
|
123 | + * @type string Key_name |
|
124 | + * @type string Seq_in_index |
|
125 | + * @type string Column_name |
|
126 | + * @type string Collation |
|
127 | + * @type string Cardinality |
|
128 | + * @type string Sub_part on a column, usually this is just the number of characters from this column to use in |
|
129 | + * indexing |
|
130 | + * @type string|null Packed |
|
131 | + * @type string Null |
|
132 | + * @type string Index_type |
|
133 | + * @type string Comment |
|
134 | + * @type string Index_comment |
|
135 | + * } |
|
136 | + */ |
|
137 | + public function showIndexes($table_name, $index_name) |
|
138 | + { |
|
139 | + global $wpdb; |
|
140 | + $table_name = $this->ensureTableNameHasPrefix($table_name); |
|
141 | + $index_exists_query = "SHOW INDEX FROM {$table_name} WHERE Key_name = '{$index_name}'"; |
|
142 | + return $wpdb->get_results($index_exists_query); |
|
143 | + } |
|
144 | 144 | } |
@@ -57,7 +57,7 @@ discard block |
||
57 | 57 | // round current time down to closest 5 minutes to simplify scheduling |
58 | 58 | $this->current_time = $this->roundTimestamp(time(), '5-minutes', false); |
59 | 59 | $this->transients = (array) get_option(TransientCacheStorage::TRANSIENT_SCHEDULE_OPTIONS_KEY, array()); |
60 | - if (! (defined('DOING_AJAX') && DOING_AJAX) && $this->transient_cleanup_frequency !== 'off') { |
|
60 | + if ( ! (defined('DOING_AJAX') && DOING_AJAX) && $this->transient_cleanup_frequency !== 'off') { |
|
61 | 61 | add_action('shutdown', array($this, 'checkTransientCleanupSchedule'), 999); |
62 | 62 | } |
63 | 63 | } |
@@ -190,7 +190,7 @@ discard block |
||
190 | 190 | */ |
191 | 191 | public function get($transient_key, $standard_cache = true) |
192 | 192 | { |
193 | - if (isset($this->transients[ $transient_key ])) { |
|
193 | + if (isset($this->transients[$transient_key])) { |
|
194 | 194 | // to avoid cache stampedes (AKA:dogpiles) for standard cache items, |
195 | 195 | // check if known cache expires within the next minute, |
196 | 196 | // and if so, remove it from our tracking and and return nothing. |
@@ -199,17 +199,17 @@ discard block |
||
199 | 199 | // until it gets replaced with the refreshed content |
200 | 200 | if ( |
201 | 201 | $standard_cache |
202 | - && $this->transients[ $transient_key ] - time() <= MINUTE_IN_SECONDS |
|
202 | + && $this->transients[$transient_key] - time() <= MINUTE_IN_SECONDS |
|
203 | 203 | ) { |
204 | - unset($this->transients[ $transient_key ]); |
|
204 | + unset($this->transients[$transient_key]); |
|
205 | 205 | $this->updateTransients(); |
206 | 206 | return null; |
207 | 207 | } |
208 | 208 | |
209 | 209 | // for non standard cache items, remove the key from our tracking, |
210 | 210 | // but proceed to retrieve the transient so that it also gets removed from the db |
211 | - if ($this->transients[ $transient_key ] <= time()) { |
|
212 | - unset($this->transients[ $transient_key ]); |
|
211 | + if ($this->transients[$transient_key] <= time()) { |
|
212 | + unset($this->transients[$transient_key]); |
|
213 | 213 | $this->updateTransients(); |
214 | 214 | } |
215 | 215 | } |
@@ -282,7 +282,7 @@ discard block |
||
282 | 282 | // and round to the closest 15 minutes |
283 | 283 | $expiration = $this->roundTimestamp($expiration); |
284 | 284 | // save transients to clear using their ID as the key to avoid duplicates |
285 | - $this->transients[ $transient_key ] = $expiration; |
|
285 | + $this->transients[$transient_key] = $expiration; |
|
286 | 286 | $this->updateTransients(); |
287 | 287 | } |
288 | 288 | |
@@ -334,8 +334,8 @@ discard block |
||
334 | 334 | if ($expiration > $this->current_time) { |
335 | 335 | continue; |
336 | 336 | } |
337 | - if (! $expiration || ! $transient_key) { |
|
338 | - unset($this->transients[ $transient_key ]); |
|
337 | + if ( ! $expiration || ! $transient_key) { |
|
338 | + unset($this->transients[$transient_key]); |
|
339 | 339 | $update = true; |
340 | 340 | continue; |
341 | 341 | } |
@@ -374,7 +374,7 @@ discard block |
||
374 | 374 | ? str_replace('_transient_', '', $transient_key) |
375 | 375 | : $transient_key; |
376 | 376 | delete_transient($transient_key); |
377 | - unset($this->transients[ $transient_key ]); |
|
377 | + unset($this->transients[$transient_key]); |
|
378 | 378 | $counter++; |
379 | 379 | } |
380 | 380 | return $counter > 0; |
@@ -15,367 +15,367 @@ |
||
15 | 15 | */ |
16 | 16 | class TransientCacheStorage implements CacheStorageInterface |
17 | 17 | { |
18 | - /** |
|
19 | - * wp-option option_name for tracking transients |
|
20 | - * |
|
21 | - * @type string |
|
22 | - */ |
|
23 | - const TRANSIENT_SCHEDULE_OPTIONS_KEY = 'ee_transient_schedule'; |
|
24 | - |
|
25 | - /** |
|
26 | - * @var int $current_time |
|
27 | - */ |
|
28 | - private $current_time; |
|
29 | - |
|
30 | - /** |
|
31 | - * how often to perform transient cleanup |
|
32 | - * |
|
33 | - * @var string $transient_cleanup_frequency |
|
34 | - */ |
|
35 | - private $transient_cleanup_frequency; |
|
36 | - |
|
37 | - /** |
|
38 | - * options for how often to perform transient cleanup |
|
39 | - * |
|
40 | - * @var array $transient_cleanup_frequency_options |
|
41 | - */ |
|
42 | - private $transient_cleanup_frequency_options = array(); |
|
43 | - |
|
44 | - /** |
|
45 | - * @var array $transients |
|
46 | - */ |
|
47 | - private $transients; |
|
48 | - |
|
49 | - |
|
50 | - /** |
|
51 | - * TransientCacheStorage constructor. |
|
52 | - */ |
|
53 | - public function __construct() |
|
54 | - { |
|
55 | - $this->transient_cleanup_frequency = $this->setTransientCleanupFrequency(); |
|
56 | - // round current time down to closest 5 minutes to simplify scheduling |
|
57 | - $this->current_time = $this->roundTimestamp(time(), '5-minutes', false); |
|
58 | - $this->transients = (array) get_option(TransientCacheStorage::TRANSIENT_SCHEDULE_OPTIONS_KEY, array()); |
|
59 | - if (! (defined('DOING_AJAX') && DOING_AJAX) && $this->transient_cleanup_frequency !== 'off') { |
|
60 | - add_action('shutdown', array($this, 'checkTransientCleanupSchedule'), 999); |
|
61 | - } |
|
62 | - } |
|
63 | - |
|
64 | - |
|
65 | - /** |
|
66 | - * Sets how often transient cleanup occurs |
|
67 | - * |
|
68 | - * @return string |
|
69 | - */ |
|
70 | - private function setTransientCleanupFrequency() |
|
71 | - { |
|
72 | - // sets how often transients are cleaned up |
|
73 | - $this->transient_cleanup_frequency_options = apply_filters( |
|
74 | - 'FHEE__TransientCacheStorage__transient_cleanup_schedule_options', |
|
75 | - array( |
|
76 | - 'off', |
|
77 | - '15-minutes', |
|
78 | - 'hour', |
|
79 | - '12-hours', |
|
80 | - 'day', |
|
81 | - ) |
|
82 | - ); |
|
83 | - $transient_cleanup_frequency = apply_filters( |
|
84 | - 'FHEE__TransientCacheStorage__transient_cleanup_schedule', |
|
85 | - 'hour' |
|
86 | - ); |
|
87 | - return in_array( |
|
88 | - $transient_cleanup_frequency, |
|
89 | - $this->transient_cleanup_frequency_options, |
|
90 | - true |
|
91 | - ) |
|
92 | - ? $transient_cleanup_frequency |
|
93 | - : 'hour'; |
|
94 | - } |
|
95 | - |
|
96 | - |
|
97 | - /** |
|
98 | - * we need to be able to round timestamps off to match the set transient cleanup frequency |
|
99 | - * so if a transient is set to expire at 1:17 pm for example, and our cleanup schedule is every hour, |
|
100 | - * then that timestamp needs to be rounded up to 2:00 pm so that it is removed |
|
101 | - * during the next scheduled cleanup after its expiration. |
|
102 | - * We also round off the current time timestamp to the closest 5 minutes |
|
103 | - * just to make the timestamps a little easier to round which helps with debugging. |
|
104 | - * |
|
105 | - * @param int $timestamp [required] |
|
106 | - * @param string $cleanup_frequency |
|
107 | - * @param bool $round_up |
|
108 | - * @return int |
|
109 | - */ |
|
110 | - private function roundTimestamp($timestamp, $cleanup_frequency = 'hour', $round_up = true) |
|
111 | - { |
|
112 | - $cleanup_frequency = $cleanup_frequency ? $cleanup_frequency : $this->transient_cleanup_frequency; |
|
113 | - // in order to round the time to the closest xx minutes (or hours), |
|
114 | - // we take the minutes (or hours) portion of the timestamp and divide it by xx, |
|
115 | - // round down to a whole number, then multiply by xx to bring us almost back up to where we were |
|
116 | - // why round down ? so the minutes (or hours) don't go over 60 (or 24) |
|
117 | - // and bump the hour, which could bump the day, which could bump the month, etc, |
|
118 | - // which would be bad because we don't always want to round up, |
|
119 | - // but when we do we can easily achieve that by simply adding the desired offset, |
|
120 | - $minutes = '00'; |
|
121 | - $hours = 'H'; |
|
122 | - switch ($cleanup_frequency) { |
|
123 | - case '5-minutes': |
|
124 | - $minutes = floor((int) date('i', $timestamp) / 5) * 5; |
|
125 | - $minutes = str_pad($minutes, 2, '0', STR_PAD_LEFT); |
|
126 | - $offset = MINUTE_IN_SECONDS * 5; |
|
127 | - break; |
|
128 | - case '15-minutes': |
|
129 | - $minutes = floor((int) date('i', $timestamp) / 15) * 15; |
|
130 | - $minutes = str_pad($minutes, 2, '0', STR_PAD_LEFT); |
|
131 | - $offset = MINUTE_IN_SECONDS * 15; |
|
132 | - break; |
|
133 | - case '12-hours': |
|
134 | - $hours = floor((int) date('H', $timestamp) / 12) * 12; |
|
135 | - $hours = str_pad($hours, 2, '0', STR_PAD_LEFT); |
|
136 | - $offset = HOUR_IN_SECONDS * 12; |
|
137 | - break; |
|
138 | - case 'day': |
|
139 | - $hours = '03'; // run cleanup at 3:00 am (or first site hit after that) |
|
140 | - $offset = DAY_IN_SECONDS; |
|
141 | - break; |
|
142 | - case 'hour': |
|
143 | - default: |
|
144 | - $offset = HOUR_IN_SECONDS; |
|
145 | - break; |
|
146 | - } |
|
147 | - $rounded_timestamp = (int) strtotime(date("Y-m-d {$hours}:{$minutes}:00", $timestamp)); |
|
148 | - $rounded_timestamp += $round_up ? $offset : 0; |
|
149 | - return apply_filters( |
|
150 | - 'FHEE__TransientCacheStorage__roundTimestamp__timestamp', |
|
151 | - $rounded_timestamp, |
|
152 | - $timestamp, |
|
153 | - $cleanup_frequency, |
|
154 | - $round_up |
|
155 | - ); |
|
156 | - } |
|
157 | - |
|
158 | - |
|
159 | - /** |
|
160 | - * Saves supplied data to a transient |
|
161 | - * if an expiration is set, then it automatically schedules the transient for cleanup |
|
162 | - * |
|
163 | - * @param string $transient_key [required] |
|
164 | - * @param string $data [required] |
|
165 | - * @param int $expiration number of seconds until the cache expires |
|
166 | - * @return bool |
|
167 | - */ |
|
168 | - public function add($transient_key, $data, $expiration = 0) |
|
169 | - { |
|
170 | - $expiration = (int) abs($expiration); |
|
171 | - $saved = set_transient($transient_key, $data, $expiration); |
|
172 | - if ($saved && $expiration) { |
|
173 | - $this->scheduleTransientCleanup($transient_key, $expiration); |
|
174 | - } |
|
175 | - return $saved; |
|
176 | - } |
|
177 | - |
|
178 | - |
|
179 | - /** |
|
180 | - * retrieves transient data |
|
181 | - * automatically triggers early cache refresh for standard cache items |
|
182 | - * in order to avoid cache stampedes on busy sites. |
|
183 | - * For non-standard cache items like PHP Session data where early refreshing is not wanted, |
|
184 | - * the $standard_cache parameter should be set to false when retrieving data |
|
185 | - * |
|
186 | - * @param string $transient_key [required] |
|
187 | - * @param bool $standard_cache |
|
188 | - * @return mixed|null |
|
189 | - */ |
|
190 | - public function get($transient_key, $standard_cache = true) |
|
191 | - { |
|
192 | - if (isset($this->transients[ $transient_key ])) { |
|
193 | - // to avoid cache stampedes (AKA:dogpiles) for standard cache items, |
|
194 | - // check if known cache expires within the next minute, |
|
195 | - // and if so, remove it from our tracking and and return nothing. |
|
196 | - // this should trigger the cache content to be regenerated during this request, |
|
197 | - // while allowing any following requests to still access the existing cache |
|
198 | - // until it gets replaced with the refreshed content |
|
199 | - if ( |
|
200 | - $standard_cache |
|
201 | - && $this->transients[ $transient_key ] - time() <= MINUTE_IN_SECONDS |
|
202 | - ) { |
|
203 | - unset($this->transients[ $transient_key ]); |
|
204 | - $this->updateTransients(); |
|
205 | - return null; |
|
206 | - } |
|
207 | - |
|
208 | - // for non standard cache items, remove the key from our tracking, |
|
209 | - // but proceed to retrieve the transient so that it also gets removed from the db |
|
210 | - if ($this->transients[ $transient_key ] <= time()) { |
|
211 | - unset($this->transients[ $transient_key ]); |
|
212 | - $this->updateTransients(); |
|
213 | - } |
|
214 | - } |
|
215 | - |
|
216 | - $content = get_transient($transient_key); |
|
217 | - return $content !== false ? $content : null; |
|
218 | - } |
|
219 | - |
|
220 | - |
|
221 | - /** |
|
222 | - * delete a single transient and remove tracking |
|
223 | - * |
|
224 | - * @param string $transient_key [required] full or partial transient key to be deleted |
|
225 | - */ |
|
226 | - public function delete($transient_key) |
|
227 | - { |
|
228 | - $this->deleteMany(array($transient_key)); |
|
229 | - } |
|
230 | - |
|
231 | - |
|
232 | - /** |
|
233 | - * delete multiple transients and remove tracking |
|
234 | - * |
|
235 | - * @param array $transient_keys [required] array of full or partial transient keys to be deleted |
|
236 | - * @param bool $force_delete [optional] if true, then will not check incoming keys against those being tracked |
|
237 | - * and proceed directly to deleting those entries from the cache storage |
|
238 | - */ |
|
239 | - public function deleteMany(array $transient_keys, $force_delete = false) |
|
240 | - { |
|
241 | - $full_transient_keys = $force_delete ? $transient_keys : array(); |
|
242 | - if (empty($full_transient_keys)) { |
|
243 | - foreach ($this->transients as $transient_key => $expiration) { |
|
244 | - foreach ($transient_keys as $transient_key_to_delete) { |
|
245 | - if (strpos($transient_key, $transient_key_to_delete) !== false) { |
|
246 | - $full_transient_keys[] = $transient_key; |
|
247 | - } |
|
248 | - } |
|
249 | - } |
|
250 | - } |
|
251 | - if ($this->deleteTransientKeys($full_transient_keys)) { |
|
252 | - $this->updateTransients(); |
|
253 | - } |
|
254 | - } |
|
255 | - |
|
256 | - |
|
257 | - /** |
|
258 | - * sorts transients numerically by timestamp |
|
259 | - * then saves the transient schedule to a WP option |
|
260 | - */ |
|
261 | - private function updateTransients() |
|
262 | - { |
|
263 | - asort($this->transients, SORT_NUMERIC); |
|
264 | - update_option( |
|
265 | - TransientCacheStorage::TRANSIENT_SCHEDULE_OPTIONS_KEY, |
|
266 | - $this->transients |
|
267 | - ); |
|
268 | - } |
|
269 | - |
|
270 | - |
|
271 | - /** |
|
272 | - * schedules a transient for cleanup by adding it to the transient tracking |
|
273 | - * |
|
274 | - * @param string $transient_key [required] |
|
275 | - * @param int $expiration [required] |
|
276 | - */ |
|
277 | - private function scheduleTransientCleanup($transient_key, $expiration) |
|
278 | - { |
|
279 | - // make sure a valid future timestamp is set |
|
280 | - $expiration += $expiration < time() ? time() : 0; |
|
281 | - // and round to the closest 15 minutes |
|
282 | - $expiration = $this->roundTimestamp($expiration); |
|
283 | - // save transients to clear using their ID as the key to avoid duplicates |
|
284 | - $this->transients[ $transient_key ] = $expiration; |
|
285 | - $this->updateTransients(); |
|
286 | - } |
|
287 | - |
|
288 | - |
|
289 | - /** |
|
290 | - * Since our tracked transients are sorted by their timestamps |
|
291 | - * we can grab the first transient and see when it is scheduled for cleanup. |
|
292 | - * If that timestamp is less than or equal to the current time, |
|
293 | - * then cleanup is triggered |
|
294 | - */ |
|
295 | - public function checkTransientCleanupSchedule() |
|
296 | - { |
|
297 | - if (empty($this->transients)) { |
|
298 | - return; |
|
299 | - } |
|
300 | - // when do we run the next cleanup job? |
|
301 | - reset($this->transients); |
|
302 | - $next_scheduled_cleanup = current($this->transients); |
|
303 | - // if the next cleanup job is scheduled for the current hour |
|
304 | - if ($next_scheduled_cleanup <= $this->current_time) { |
|
305 | - if ($this->cleanupExpiredTransients()) { |
|
306 | - $this->updateTransients(); |
|
307 | - } |
|
308 | - } |
|
309 | - } |
|
310 | - |
|
311 | - |
|
312 | - /** |
|
313 | - * loops through the array of tracked transients, |
|
314 | - * compiles a list of those that have expired, and sends that list off for deletion. |
|
315 | - * Also removes any bad records from the transients array |
|
316 | - * |
|
317 | - * @return bool |
|
318 | - */ |
|
319 | - private function cleanupExpiredTransients() |
|
320 | - { |
|
321 | - $update = false; |
|
322 | - // filter the query limit. Set to 0 to turn off garbage collection |
|
323 | - $limit = (int) abs( |
|
324 | - apply_filters( |
|
325 | - 'FHEE__TransientCacheStorage__clearExpiredTransients__limit', |
|
326 | - 50 |
|
327 | - ) |
|
328 | - ); |
|
329 | - // non-zero LIMIT means take out the trash |
|
330 | - if ($limit) { |
|
331 | - $transient_keys = array(); |
|
332 | - foreach ($this->transients as $transient_key => $expiration) { |
|
333 | - if ($expiration > $this->current_time) { |
|
334 | - continue; |
|
335 | - } |
|
336 | - if (! $expiration || ! $transient_key) { |
|
337 | - unset($this->transients[ $transient_key ]); |
|
338 | - $update = true; |
|
339 | - continue; |
|
340 | - } |
|
341 | - $transient_keys[] = $transient_key; |
|
342 | - } |
|
343 | - // delete expired keys, but maintain value of $update if nothing is deleted |
|
344 | - $update = $this->deleteTransientKeys($transient_keys, $limit) ? true : $update; |
|
345 | - do_action('FHEE__TransientCacheStorage__clearExpiredTransients__end', $this); |
|
346 | - } |
|
347 | - return $update; |
|
348 | - } |
|
349 | - |
|
350 | - |
|
351 | - /** |
|
352 | - * calls delete_transient() on each transient key provided, up to the specified limit |
|
353 | - * |
|
354 | - * @param array $transient_keys [required] |
|
355 | - * @param int $limit |
|
356 | - * @return bool |
|
357 | - */ |
|
358 | - private function deleteTransientKeys(array $transient_keys, $limit = 50) |
|
359 | - { |
|
360 | - if (empty($transient_keys)) { |
|
361 | - return false; |
|
362 | - } |
|
363 | - $counter = 0; |
|
364 | - foreach ($transient_keys as $transient_key) { |
|
365 | - if ($counter === $limit) { |
|
366 | - break; |
|
367 | - } |
|
368 | - // remove any transient prefixes |
|
369 | - $transient_key = strpos($transient_key, '_transient_timeout_') === 0 |
|
370 | - ? str_replace('_transient_timeout_', '', $transient_key) |
|
371 | - : $transient_key; |
|
372 | - $transient_key = strpos($transient_key, '_transient_') === 0 |
|
373 | - ? str_replace('_transient_', '', $transient_key) |
|
374 | - : $transient_key; |
|
375 | - delete_transient($transient_key); |
|
376 | - unset($this->transients[ $transient_key ]); |
|
377 | - $counter++; |
|
378 | - } |
|
379 | - return $counter > 0; |
|
380 | - } |
|
18 | + /** |
|
19 | + * wp-option option_name for tracking transients |
|
20 | + * |
|
21 | + * @type string |
|
22 | + */ |
|
23 | + const TRANSIENT_SCHEDULE_OPTIONS_KEY = 'ee_transient_schedule'; |
|
24 | + |
|
25 | + /** |
|
26 | + * @var int $current_time |
|
27 | + */ |
|
28 | + private $current_time; |
|
29 | + |
|
30 | + /** |
|
31 | + * how often to perform transient cleanup |
|
32 | + * |
|
33 | + * @var string $transient_cleanup_frequency |
|
34 | + */ |
|
35 | + private $transient_cleanup_frequency; |
|
36 | + |
|
37 | + /** |
|
38 | + * options for how often to perform transient cleanup |
|
39 | + * |
|
40 | + * @var array $transient_cleanup_frequency_options |
|
41 | + */ |
|
42 | + private $transient_cleanup_frequency_options = array(); |
|
43 | + |
|
44 | + /** |
|
45 | + * @var array $transients |
|
46 | + */ |
|
47 | + private $transients; |
|
48 | + |
|
49 | + |
|
50 | + /** |
|
51 | + * TransientCacheStorage constructor. |
|
52 | + */ |
|
53 | + public function __construct() |
|
54 | + { |
|
55 | + $this->transient_cleanup_frequency = $this->setTransientCleanupFrequency(); |
|
56 | + // round current time down to closest 5 minutes to simplify scheduling |
|
57 | + $this->current_time = $this->roundTimestamp(time(), '5-minutes', false); |
|
58 | + $this->transients = (array) get_option(TransientCacheStorage::TRANSIENT_SCHEDULE_OPTIONS_KEY, array()); |
|
59 | + if (! (defined('DOING_AJAX') && DOING_AJAX) && $this->transient_cleanup_frequency !== 'off') { |
|
60 | + add_action('shutdown', array($this, 'checkTransientCleanupSchedule'), 999); |
|
61 | + } |
|
62 | + } |
|
63 | + |
|
64 | + |
|
65 | + /** |
|
66 | + * Sets how often transient cleanup occurs |
|
67 | + * |
|
68 | + * @return string |
|
69 | + */ |
|
70 | + private function setTransientCleanupFrequency() |
|
71 | + { |
|
72 | + // sets how often transients are cleaned up |
|
73 | + $this->transient_cleanup_frequency_options = apply_filters( |
|
74 | + 'FHEE__TransientCacheStorage__transient_cleanup_schedule_options', |
|
75 | + array( |
|
76 | + 'off', |
|
77 | + '15-minutes', |
|
78 | + 'hour', |
|
79 | + '12-hours', |
|
80 | + 'day', |
|
81 | + ) |
|
82 | + ); |
|
83 | + $transient_cleanup_frequency = apply_filters( |
|
84 | + 'FHEE__TransientCacheStorage__transient_cleanup_schedule', |
|
85 | + 'hour' |
|
86 | + ); |
|
87 | + return in_array( |
|
88 | + $transient_cleanup_frequency, |
|
89 | + $this->transient_cleanup_frequency_options, |
|
90 | + true |
|
91 | + ) |
|
92 | + ? $transient_cleanup_frequency |
|
93 | + : 'hour'; |
|
94 | + } |
|
95 | + |
|
96 | + |
|
97 | + /** |
|
98 | + * we need to be able to round timestamps off to match the set transient cleanup frequency |
|
99 | + * so if a transient is set to expire at 1:17 pm for example, and our cleanup schedule is every hour, |
|
100 | + * then that timestamp needs to be rounded up to 2:00 pm so that it is removed |
|
101 | + * during the next scheduled cleanup after its expiration. |
|
102 | + * We also round off the current time timestamp to the closest 5 minutes |
|
103 | + * just to make the timestamps a little easier to round which helps with debugging. |
|
104 | + * |
|
105 | + * @param int $timestamp [required] |
|
106 | + * @param string $cleanup_frequency |
|
107 | + * @param bool $round_up |
|
108 | + * @return int |
|
109 | + */ |
|
110 | + private function roundTimestamp($timestamp, $cleanup_frequency = 'hour', $round_up = true) |
|
111 | + { |
|
112 | + $cleanup_frequency = $cleanup_frequency ? $cleanup_frequency : $this->transient_cleanup_frequency; |
|
113 | + // in order to round the time to the closest xx minutes (or hours), |
|
114 | + // we take the minutes (or hours) portion of the timestamp and divide it by xx, |
|
115 | + // round down to a whole number, then multiply by xx to bring us almost back up to where we were |
|
116 | + // why round down ? so the minutes (or hours) don't go over 60 (or 24) |
|
117 | + // and bump the hour, which could bump the day, which could bump the month, etc, |
|
118 | + // which would be bad because we don't always want to round up, |
|
119 | + // but when we do we can easily achieve that by simply adding the desired offset, |
|
120 | + $minutes = '00'; |
|
121 | + $hours = 'H'; |
|
122 | + switch ($cleanup_frequency) { |
|
123 | + case '5-minutes': |
|
124 | + $minutes = floor((int) date('i', $timestamp) / 5) * 5; |
|
125 | + $minutes = str_pad($minutes, 2, '0', STR_PAD_LEFT); |
|
126 | + $offset = MINUTE_IN_SECONDS * 5; |
|
127 | + break; |
|
128 | + case '15-minutes': |
|
129 | + $minutes = floor((int) date('i', $timestamp) / 15) * 15; |
|
130 | + $minutes = str_pad($minutes, 2, '0', STR_PAD_LEFT); |
|
131 | + $offset = MINUTE_IN_SECONDS * 15; |
|
132 | + break; |
|
133 | + case '12-hours': |
|
134 | + $hours = floor((int) date('H', $timestamp) / 12) * 12; |
|
135 | + $hours = str_pad($hours, 2, '0', STR_PAD_LEFT); |
|
136 | + $offset = HOUR_IN_SECONDS * 12; |
|
137 | + break; |
|
138 | + case 'day': |
|
139 | + $hours = '03'; // run cleanup at 3:00 am (or first site hit after that) |
|
140 | + $offset = DAY_IN_SECONDS; |
|
141 | + break; |
|
142 | + case 'hour': |
|
143 | + default: |
|
144 | + $offset = HOUR_IN_SECONDS; |
|
145 | + break; |
|
146 | + } |
|
147 | + $rounded_timestamp = (int) strtotime(date("Y-m-d {$hours}:{$minutes}:00", $timestamp)); |
|
148 | + $rounded_timestamp += $round_up ? $offset : 0; |
|
149 | + return apply_filters( |
|
150 | + 'FHEE__TransientCacheStorage__roundTimestamp__timestamp', |
|
151 | + $rounded_timestamp, |
|
152 | + $timestamp, |
|
153 | + $cleanup_frequency, |
|
154 | + $round_up |
|
155 | + ); |
|
156 | + } |
|
157 | + |
|
158 | + |
|
159 | + /** |
|
160 | + * Saves supplied data to a transient |
|
161 | + * if an expiration is set, then it automatically schedules the transient for cleanup |
|
162 | + * |
|
163 | + * @param string $transient_key [required] |
|
164 | + * @param string $data [required] |
|
165 | + * @param int $expiration number of seconds until the cache expires |
|
166 | + * @return bool |
|
167 | + */ |
|
168 | + public function add($transient_key, $data, $expiration = 0) |
|
169 | + { |
|
170 | + $expiration = (int) abs($expiration); |
|
171 | + $saved = set_transient($transient_key, $data, $expiration); |
|
172 | + if ($saved && $expiration) { |
|
173 | + $this->scheduleTransientCleanup($transient_key, $expiration); |
|
174 | + } |
|
175 | + return $saved; |
|
176 | + } |
|
177 | + |
|
178 | + |
|
179 | + /** |
|
180 | + * retrieves transient data |
|
181 | + * automatically triggers early cache refresh for standard cache items |
|
182 | + * in order to avoid cache stampedes on busy sites. |
|
183 | + * For non-standard cache items like PHP Session data where early refreshing is not wanted, |
|
184 | + * the $standard_cache parameter should be set to false when retrieving data |
|
185 | + * |
|
186 | + * @param string $transient_key [required] |
|
187 | + * @param bool $standard_cache |
|
188 | + * @return mixed|null |
|
189 | + */ |
|
190 | + public function get($transient_key, $standard_cache = true) |
|
191 | + { |
|
192 | + if (isset($this->transients[ $transient_key ])) { |
|
193 | + // to avoid cache stampedes (AKA:dogpiles) for standard cache items, |
|
194 | + // check if known cache expires within the next minute, |
|
195 | + // and if so, remove it from our tracking and and return nothing. |
|
196 | + // this should trigger the cache content to be regenerated during this request, |
|
197 | + // while allowing any following requests to still access the existing cache |
|
198 | + // until it gets replaced with the refreshed content |
|
199 | + if ( |
|
200 | + $standard_cache |
|
201 | + && $this->transients[ $transient_key ] - time() <= MINUTE_IN_SECONDS |
|
202 | + ) { |
|
203 | + unset($this->transients[ $transient_key ]); |
|
204 | + $this->updateTransients(); |
|
205 | + return null; |
|
206 | + } |
|
207 | + |
|
208 | + // for non standard cache items, remove the key from our tracking, |
|
209 | + // but proceed to retrieve the transient so that it also gets removed from the db |
|
210 | + if ($this->transients[ $transient_key ] <= time()) { |
|
211 | + unset($this->transients[ $transient_key ]); |
|
212 | + $this->updateTransients(); |
|
213 | + } |
|
214 | + } |
|
215 | + |
|
216 | + $content = get_transient($transient_key); |
|
217 | + return $content !== false ? $content : null; |
|
218 | + } |
|
219 | + |
|
220 | + |
|
221 | + /** |
|
222 | + * delete a single transient and remove tracking |
|
223 | + * |
|
224 | + * @param string $transient_key [required] full or partial transient key to be deleted |
|
225 | + */ |
|
226 | + public function delete($transient_key) |
|
227 | + { |
|
228 | + $this->deleteMany(array($transient_key)); |
|
229 | + } |
|
230 | + |
|
231 | + |
|
232 | + /** |
|
233 | + * delete multiple transients and remove tracking |
|
234 | + * |
|
235 | + * @param array $transient_keys [required] array of full or partial transient keys to be deleted |
|
236 | + * @param bool $force_delete [optional] if true, then will not check incoming keys against those being tracked |
|
237 | + * and proceed directly to deleting those entries from the cache storage |
|
238 | + */ |
|
239 | + public function deleteMany(array $transient_keys, $force_delete = false) |
|
240 | + { |
|
241 | + $full_transient_keys = $force_delete ? $transient_keys : array(); |
|
242 | + if (empty($full_transient_keys)) { |
|
243 | + foreach ($this->transients as $transient_key => $expiration) { |
|
244 | + foreach ($transient_keys as $transient_key_to_delete) { |
|
245 | + if (strpos($transient_key, $transient_key_to_delete) !== false) { |
|
246 | + $full_transient_keys[] = $transient_key; |
|
247 | + } |
|
248 | + } |
|
249 | + } |
|
250 | + } |
|
251 | + if ($this->deleteTransientKeys($full_transient_keys)) { |
|
252 | + $this->updateTransients(); |
|
253 | + } |
|
254 | + } |
|
255 | + |
|
256 | + |
|
257 | + /** |
|
258 | + * sorts transients numerically by timestamp |
|
259 | + * then saves the transient schedule to a WP option |
|
260 | + */ |
|
261 | + private function updateTransients() |
|
262 | + { |
|
263 | + asort($this->transients, SORT_NUMERIC); |
|
264 | + update_option( |
|
265 | + TransientCacheStorage::TRANSIENT_SCHEDULE_OPTIONS_KEY, |
|
266 | + $this->transients |
|
267 | + ); |
|
268 | + } |
|
269 | + |
|
270 | + |
|
271 | + /** |
|
272 | + * schedules a transient for cleanup by adding it to the transient tracking |
|
273 | + * |
|
274 | + * @param string $transient_key [required] |
|
275 | + * @param int $expiration [required] |
|
276 | + */ |
|
277 | + private function scheduleTransientCleanup($transient_key, $expiration) |
|
278 | + { |
|
279 | + // make sure a valid future timestamp is set |
|
280 | + $expiration += $expiration < time() ? time() : 0; |
|
281 | + // and round to the closest 15 minutes |
|
282 | + $expiration = $this->roundTimestamp($expiration); |
|
283 | + // save transients to clear using their ID as the key to avoid duplicates |
|
284 | + $this->transients[ $transient_key ] = $expiration; |
|
285 | + $this->updateTransients(); |
|
286 | + } |
|
287 | + |
|
288 | + |
|
289 | + /** |
|
290 | + * Since our tracked transients are sorted by their timestamps |
|
291 | + * we can grab the first transient and see when it is scheduled for cleanup. |
|
292 | + * If that timestamp is less than or equal to the current time, |
|
293 | + * then cleanup is triggered |
|
294 | + */ |
|
295 | + public function checkTransientCleanupSchedule() |
|
296 | + { |
|
297 | + if (empty($this->transients)) { |
|
298 | + return; |
|
299 | + } |
|
300 | + // when do we run the next cleanup job? |
|
301 | + reset($this->transients); |
|
302 | + $next_scheduled_cleanup = current($this->transients); |
|
303 | + // if the next cleanup job is scheduled for the current hour |
|
304 | + if ($next_scheduled_cleanup <= $this->current_time) { |
|
305 | + if ($this->cleanupExpiredTransients()) { |
|
306 | + $this->updateTransients(); |
|
307 | + } |
|
308 | + } |
|
309 | + } |
|
310 | + |
|
311 | + |
|
312 | + /** |
|
313 | + * loops through the array of tracked transients, |
|
314 | + * compiles a list of those that have expired, and sends that list off for deletion. |
|
315 | + * Also removes any bad records from the transients array |
|
316 | + * |
|
317 | + * @return bool |
|
318 | + */ |
|
319 | + private function cleanupExpiredTransients() |
|
320 | + { |
|
321 | + $update = false; |
|
322 | + // filter the query limit. Set to 0 to turn off garbage collection |
|
323 | + $limit = (int) abs( |
|
324 | + apply_filters( |
|
325 | + 'FHEE__TransientCacheStorage__clearExpiredTransients__limit', |
|
326 | + 50 |
|
327 | + ) |
|
328 | + ); |
|
329 | + // non-zero LIMIT means take out the trash |
|
330 | + if ($limit) { |
|
331 | + $transient_keys = array(); |
|
332 | + foreach ($this->transients as $transient_key => $expiration) { |
|
333 | + if ($expiration > $this->current_time) { |
|
334 | + continue; |
|
335 | + } |
|
336 | + if (! $expiration || ! $transient_key) { |
|
337 | + unset($this->transients[ $transient_key ]); |
|
338 | + $update = true; |
|
339 | + continue; |
|
340 | + } |
|
341 | + $transient_keys[] = $transient_key; |
|
342 | + } |
|
343 | + // delete expired keys, but maintain value of $update if nothing is deleted |
|
344 | + $update = $this->deleteTransientKeys($transient_keys, $limit) ? true : $update; |
|
345 | + do_action('FHEE__TransientCacheStorage__clearExpiredTransients__end', $this); |
|
346 | + } |
|
347 | + return $update; |
|
348 | + } |
|
349 | + |
|
350 | + |
|
351 | + /** |
|
352 | + * calls delete_transient() on each transient key provided, up to the specified limit |
|
353 | + * |
|
354 | + * @param array $transient_keys [required] |
|
355 | + * @param int $limit |
|
356 | + * @return bool |
|
357 | + */ |
|
358 | + private function deleteTransientKeys(array $transient_keys, $limit = 50) |
|
359 | + { |
|
360 | + if (empty($transient_keys)) { |
|
361 | + return false; |
|
362 | + } |
|
363 | + $counter = 0; |
|
364 | + foreach ($transient_keys as $transient_key) { |
|
365 | + if ($counter === $limit) { |
|
366 | + break; |
|
367 | + } |
|
368 | + // remove any transient prefixes |
|
369 | + $transient_key = strpos($transient_key, '_transient_timeout_') === 0 |
|
370 | + ? str_replace('_transient_timeout_', '', $transient_key) |
|
371 | + : $transient_key; |
|
372 | + $transient_key = strpos($transient_key, '_transient_') === 0 |
|
373 | + ? str_replace('_transient_', '', $transient_key) |
|
374 | + : $transient_key; |
|
375 | + delete_transient($transient_key); |
|
376 | + unset($this->transients[ $transient_key ]); |
|
377 | + $counter++; |
|
378 | + } |
|
379 | + return $counter > 0; |
|
380 | + } |
|
381 | 381 | } |