@@ -17,607 +17,607 @@ |
||
17 | 17 | class EE_Cron_Tasks extends EE_Base |
18 | 18 | { |
19 | 19 | |
20 | - /** |
|
21 | - * WordPress doesn't allow duplicate crons within 10 minutes of the original, |
|
22 | - * so we'll set our retry time for just over 10 minutes to avoid that |
|
23 | - */ |
|
24 | - const reschedule_timeout = 605; |
|
25 | - |
|
26 | - |
|
27 | - /** |
|
28 | - * @var EE_Cron_Tasks |
|
29 | - */ |
|
30 | - private static $_instance; |
|
31 | - |
|
32 | - |
|
33 | - /** |
|
34 | - * @return EE_Cron_Tasks |
|
35 | - * @throws ReflectionException |
|
36 | - * @throws EE_Error |
|
37 | - * @throws InvalidArgumentException |
|
38 | - * @throws InvalidInterfaceException |
|
39 | - * @throws InvalidDataTypeException |
|
40 | - */ |
|
41 | - public static function instance() |
|
42 | - { |
|
43 | - if (! self::$_instance instanceof EE_Cron_Tasks) { |
|
44 | - self::$_instance = new self(); |
|
45 | - } |
|
46 | - return self::$_instance; |
|
47 | - } |
|
48 | - |
|
49 | - |
|
50 | - /** |
|
51 | - * @access private |
|
52 | - * @throws InvalidDataTypeException |
|
53 | - * @throws InvalidInterfaceException |
|
54 | - * @throws InvalidArgumentException |
|
55 | - * @throws EE_Error |
|
56 | - * @throws ReflectionException |
|
57 | - */ |
|
58 | - private function __construct() |
|
59 | - { |
|
60 | - do_action('AHEE_log', __CLASS__, __FUNCTION__); |
|
61 | - // verify that WP Cron is enabled |
|
62 | - if ( |
|
63 | - defined('DISABLE_WP_CRON') |
|
64 | - && DISABLE_WP_CRON |
|
65 | - && is_admin() |
|
66 | - && ! get_option('ee_disabled_wp_cron_check') |
|
67 | - ) { |
|
68 | - /** |
|
69 | - * This needs to be delayed until after the config is loaded because EE_Cron_Tasks is constructed before |
|
70 | - * config is loaded. |
|
71 | - * This is intentionally using a anonymous function so that its not easily de-registered. Client code |
|
72 | - * wanting to not have this functionality can just register its own action at a priority after this one to |
|
73 | - * reverse any changes. |
|
74 | - */ |
|
75 | - add_action( |
|
76 | - 'AHEE__EE_System__load_core_configuration__complete', |
|
77 | - function () |
|
78 | - { |
|
79 | - EE_Registry::instance()->NET_CFG->core->do_messages_on_same_request = true; |
|
80 | - EE_Registry::instance()->NET_CFG->update_config(true, false); |
|
81 | - add_option('ee_disabled_wp_cron_check', 1, '', false); |
|
82 | - } |
|
83 | - ); |
|
84 | - } |
|
85 | - // UPDATE TRANSACTION WITH PAYMENT |
|
86 | - add_action( |
|
87 | - 'AHEE__EE_Cron_Tasks__update_transaction_with_payment_2', |
|
88 | - array('EE_Cron_Tasks', 'setup_update_for_transaction_with_payment'), |
|
89 | - 10, |
|
90 | - 2 |
|
91 | - ); |
|
92 | - // ABANDONED / EXPIRED TRANSACTION CHECK |
|
93 | - add_action( |
|
94 | - 'AHEE__EE_Cron_Tasks__expired_transaction_check', |
|
95 | - array('EE_Cron_Tasks', 'expired_transaction_check'), |
|
96 | - 10, |
|
97 | - 1 |
|
98 | - ); |
|
99 | - // CLEAN OUT JUNK TRANSACTIONS AND RELATED DATA |
|
100 | - add_action( |
|
101 | - 'AHEE__EE_Cron_Tasks__clean_up_junk_transactions', |
|
102 | - array('EE_Cron_Tasks', 'clean_out_junk_transactions') |
|
103 | - ); |
|
104 | - // logging |
|
105 | - add_action( |
|
106 | - 'AHEE__EE_System__load_core_configuration__complete', |
|
107 | - array('EE_Cron_Tasks', 'log_scheduled_ee_crons') |
|
108 | - ); |
|
109 | - EE_Registry::instance()->load_lib('Messages_Scheduler'); |
|
110 | - //clean out old gateway logs |
|
111 | - add_action( |
|
112 | - 'AHEE_EE_Cron_Tasks__clean_out_old_gateway_logs', |
|
113 | - array('EE_Cron_Tasks', 'clean_out_old_gateway_logs') |
|
114 | - ); |
|
115 | - } |
|
116 | - |
|
117 | - |
|
118 | - /** |
|
119 | - * @access protected |
|
120 | - * @return void |
|
121 | - */ |
|
122 | - public static function log_scheduled_ee_crons() |
|
123 | - { |
|
124 | - $ee_crons = array( |
|
125 | - 'AHEE__EE_Cron_Tasks__update_transaction_with_payment', |
|
126 | - 'AHEE__EE_Cron_Tasks__finalize_abandoned_transactions', |
|
127 | - 'AHEE__EE_Cron_Tasks__clean_up_junk_transactions', |
|
128 | - ); |
|
129 | - $crons = (array) get_option('cron'); |
|
130 | - if (! is_array($crons)) { |
|
131 | - return; |
|
132 | - } |
|
133 | - foreach ($crons as $timestamp => $cron) { |
|
134 | - /** @var array[] $cron */ |
|
135 | - foreach ($ee_crons as $ee_cron) { |
|
136 | - if (isset($cron[ $ee_cron ]) && is_array($cron[ $ee_cron ])) { |
|
137 | - do_action('AHEE_log', __CLASS__, __FUNCTION__, $ee_cron, 'scheduled EE cron'); |
|
138 | - foreach ($cron[ $ee_cron ] as $ee_cron_details) { |
|
139 | - if (! empty($ee_cron_details['args'])) { |
|
140 | - do_action( |
|
141 | - 'AHEE_log', |
|
142 | - __CLASS__, |
|
143 | - __FUNCTION__, |
|
144 | - print_r($ee_cron_details['args'], true), |
|
145 | - "{$ee_cron} args" |
|
146 | - ); |
|
147 | - } |
|
148 | - } |
|
149 | - } |
|
150 | - } |
|
151 | - } |
|
152 | - } |
|
153 | - |
|
154 | - |
|
155 | - |
|
156 | - /** |
|
157 | - * reschedule_cron_for_transactions_if_maintenance_mode |
|
158 | - * if Maintenance Mode is active, this will reschedule a cron to run again in 10 minutes |
|
159 | - * |
|
160 | - * @param string $cron_task |
|
161 | - * @param array $TXN_IDs |
|
162 | - * @return bool |
|
163 | - * @throws DomainException |
|
164 | - */ |
|
165 | - public static function reschedule_cron_for_transactions_if_maintenance_mode($cron_task, array $TXN_IDs) |
|
166 | - { |
|
167 | - if (! method_exists('EE_Cron_Tasks', $cron_task)) { |
|
168 | - throw new DomainException( |
|
169 | - sprintf( |
|
170 | - __('"%1$s" is not valid method on EE_Cron_Tasks.', 'event_espresso'), |
|
171 | - $cron_task |
|
172 | - ) |
|
173 | - ); |
|
174 | - } |
|
175 | - // reschedule the cron if we can't hit the db right now |
|
176 | - if (! EE_Maintenance_Mode::instance()->models_can_query()) { |
|
177 | - foreach ($TXN_IDs as $TXN_ID => $additional_vars) { |
|
178 | - // ensure $additional_vars is an array |
|
179 | - $additional_vars = is_array($additional_vars) ? $additional_vars : array($additional_vars); |
|
180 | - // reset cron job for the TXN |
|
181 | - call_user_func_array( |
|
182 | - array('EE_Cron_Tasks', $cron_task), |
|
183 | - array_merge( |
|
184 | - array( |
|
185 | - time() + (10 * MINUTE_IN_SECONDS), |
|
186 | - $TXN_ID, |
|
187 | - ), |
|
188 | - $additional_vars |
|
189 | - ) |
|
190 | - ); |
|
191 | - } |
|
192 | - return true; |
|
193 | - } |
|
194 | - return false; |
|
195 | - } |
|
196 | - |
|
197 | - |
|
198 | - |
|
199 | - |
|
200 | - /**************** UPDATE TRANSACTION WITH PAYMENT ****************/ |
|
201 | - |
|
202 | - |
|
203 | - |
|
204 | - /** |
|
205 | - * array of TXN IDs and the payment |
|
206 | - * |
|
207 | - * @var array |
|
208 | - */ |
|
209 | - protected static $_update_transactions_with_payment = array(); |
|
210 | - |
|
211 | - |
|
212 | - /** |
|
213 | - * schedule_update_transaction_with_payment |
|
214 | - * sets a wp_schedule_single_event() for updating any TXNs that may |
|
215 | - * require updating due to recently received payments |
|
216 | - * |
|
217 | - * @param int $timestamp |
|
218 | - * @param int $TXN_ID |
|
219 | - * @param int $PAY_ID |
|
220 | - */ |
|
221 | - public static function schedule_update_transaction_with_payment( |
|
222 | - $timestamp, |
|
223 | - $TXN_ID, |
|
224 | - $PAY_ID |
|
225 | - ) { |
|
226 | - do_action('AHEE_log', __CLASS__, __FUNCTION__); |
|
227 | - // validate $TXN_ID and $timestamp |
|
228 | - $TXN_ID = absint($TXN_ID); |
|
229 | - $timestamp = absint($timestamp); |
|
230 | - if ($TXN_ID && $timestamp) { |
|
231 | - wp_schedule_single_event( |
|
232 | - $timestamp, |
|
233 | - 'AHEE__EE_Cron_Tasks__update_transaction_with_payment_2', |
|
234 | - array($TXN_ID, $PAY_ID) |
|
235 | - ); |
|
236 | - } |
|
237 | - } |
|
238 | - |
|
239 | - |
|
240 | - /** |
|
241 | - * setup_update_for_transaction_with_payment |
|
242 | - * this is the callback for the action hook: |
|
243 | - * 'AHEE__EE_Cron_Tasks__update_transaction_with_payment' |
|
244 | - * which is setup by EE_Cron_Tasks::schedule_update_transaction_with_payment(). |
|
245 | - * The passed TXN_ID and associated payment gets added to an array, and then |
|
246 | - * the EE_Cron_Tasks::update_transaction_with_payment() function is hooked into |
|
247 | - * 'shutdown' which will actually handle the processing of any |
|
248 | - * transactions requiring updating, because doing so now would be too early |
|
249 | - * and the required resources may not be available |
|
250 | - * |
|
251 | - * @param int $TXN_ID |
|
252 | - * @param int $PAY_ID |
|
253 | - */ |
|
254 | - public static function setup_update_for_transaction_with_payment($TXN_ID = 0, $PAY_ID = 0) |
|
255 | - { |
|
256 | - do_action('AHEE_log', __CLASS__, __FUNCTION__, $TXN_ID, '$TXN_ID'); |
|
257 | - if (absint($TXN_ID)) { |
|
258 | - self::$_update_transactions_with_payment[ $TXN_ID ] = $PAY_ID; |
|
259 | - add_action( |
|
260 | - 'shutdown', |
|
261 | - array('EE_Cron_Tasks', 'update_transaction_with_payment'), |
|
262 | - 5 |
|
263 | - ); |
|
264 | - } |
|
265 | - } |
|
266 | - |
|
267 | - |
|
268 | - /** |
|
269 | - * update_transaction_with_payment |
|
270 | - * loops through the self::$_abandoned_transactions array |
|
271 | - * and attempts to finalize any TXNs that have not been completed |
|
272 | - * but have had their sessions expired, most likely due to a user not |
|
273 | - * returning from an off-site payment gateway |
|
274 | - * |
|
275 | - * @throws EE_Error |
|
276 | - * @throws DomainException |
|
277 | - * @throws InvalidDataTypeException |
|
278 | - * @throws InvalidInterfaceException |
|
279 | - * @throws InvalidArgumentException |
|
280 | - * @throws ReflectionException |
|
281 | - * @throws RuntimeException |
|
282 | - */ |
|
283 | - public static function update_transaction_with_payment() |
|
284 | - { |
|
285 | - do_action('AHEE_log', __CLASS__, __FUNCTION__); |
|
286 | - if ( |
|
287 | - // are there any TXNs that need cleaning up ? |
|
288 | - empty(self::$_update_transactions_with_payment) |
|
289 | - // reschedule the cron if we can't hit the db right now |
|
290 | - || EE_Cron_Tasks::reschedule_cron_for_transactions_if_maintenance_mode( |
|
291 | - 'schedule_update_transaction_with_payment', |
|
292 | - self::$_update_transactions_with_payment |
|
293 | - ) |
|
294 | - ) { |
|
295 | - return; |
|
296 | - } |
|
297 | - /** @type EE_Payment_Processor $payment_processor */ |
|
298 | - $payment_processor = EE_Registry::instance()->load_core('Payment_Processor'); |
|
299 | - // set revisit flag for payment processor |
|
300 | - $payment_processor->set_revisit(); |
|
301 | - // load EEM_Transaction |
|
302 | - EE_Registry::instance()->load_model('Transaction'); |
|
303 | - foreach (self::$_update_transactions_with_payment as $TXN_ID => $PAY_ID) { |
|
304 | - // reschedule the cron if we can't hit the db right now |
|
305 | - if (! EE_Maintenance_Mode::instance()->models_can_query()) { |
|
306 | - // reset cron job for updating the TXN |
|
307 | - EE_Cron_Tasks::schedule_update_transaction_with_payment( |
|
308 | - time() + EE_Cron_Tasks::reschedule_timeout, |
|
309 | - $TXN_ID, |
|
310 | - $PAY_ID |
|
311 | - ); |
|
312 | - continue; |
|
313 | - } |
|
314 | - $transaction = EEM_Transaction::instance()->get_one_by_ID($TXN_ID); |
|
315 | - $payment = EEM_Payment::instance()->get_one_by_ID($PAY_ID); |
|
316 | - // verify transaction |
|
317 | - if ($transaction instanceof EE_Transaction && $payment instanceof EE_Payment) { |
|
318 | - // now try to update the TXN with any payments |
|
319 | - $payment_processor->update_txn_based_on_payment($transaction, $payment, true, true); |
|
320 | - } |
|
321 | - unset(self::$_update_transactions_with_payment[ $TXN_ID ]); |
|
322 | - } |
|
323 | - } |
|
324 | - |
|
325 | - |
|
326 | - |
|
327 | - /************ END OF UPDATE TRANSACTION WITH PAYMENT ************/ |
|
328 | - |
|
329 | - |
|
330 | - |
|
331 | - /***************** EXPIRED TRANSACTION CHECK *****************/ |
|
332 | - |
|
333 | - |
|
334 | - |
|
335 | - /** |
|
336 | - * array of TXN IDs |
|
337 | - * |
|
338 | - * @var array |
|
339 | - */ |
|
340 | - protected static $_expired_transactions = array(); |
|
341 | - |
|
342 | - |
|
343 | - |
|
344 | - /** |
|
345 | - * schedule_expired_transaction_check |
|
346 | - * sets a wp_schedule_single_event() for following up on TXNs after their session has expired |
|
347 | - * |
|
348 | - * @param int $timestamp |
|
349 | - * @param int $TXN_ID |
|
350 | - */ |
|
351 | - public static function schedule_expired_transaction_check( |
|
352 | - $timestamp, |
|
353 | - $TXN_ID |
|
354 | - ) { |
|
355 | - // validate $TXN_ID and $timestamp |
|
356 | - $TXN_ID = absint($TXN_ID); |
|
357 | - $timestamp = absint($timestamp); |
|
358 | - if ($TXN_ID && $timestamp) { |
|
359 | - wp_schedule_single_event( |
|
360 | - $timestamp, |
|
361 | - 'AHEE__EE_Cron_Tasks__expired_transaction_check', |
|
362 | - array($TXN_ID) |
|
363 | - ); |
|
364 | - } |
|
365 | - } |
|
366 | - |
|
367 | - |
|
368 | - |
|
369 | - /** |
|
370 | - * expired_transaction_check |
|
371 | - * this is the callback for the action hook: |
|
372 | - * 'AHEE__EE_Cron_Tasks__transaction_session_expiration_check' |
|
373 | - * which is utilized by wp_schedule_single_event() |
|
374 | - * in \EED_Single_Page_Checkout::_initialize_transaction(). |
|
375 | - * The passed TXN_ID gets added to an array, and then the |
|
376 | - * process_expired_transactions() function is hooked into |
|
377 | - * 'AHEE__EE_System__core_loaded_and_ready' which will actually handle the |
|
378 | - * processing of any failed transactions, because doing so now would be |
|
379 | - * too early and the required resources may not be available |
|
380 | - * |
|
381 | - * @param int $TXN_ID |
|
382 | - */ |
|
383 | - public static function expired_transaction_check($TXN_ID = 0) |
|
384 | - { |
|
385 | - if (absint($TXN_ID)) { |
|
386 | - self::$_expired_transactions[ $TXN_ID ] = $TXN_ID; |
|
387 | - add_action( |
|
388 | - 'shutdown', |
|
389 | - array('EE_Cron_Tasks', 'process_expired_transactions'), |
|
390 | - 5 |
|
391 | - ); |
|
392 | - } |
|
393 | - } |
|
394 | - |
|
395 | - |
|
396 | - |
|
397 | - /** |
|
398 | - * process_expired_transactions |
|
399 | - * loops through the self::$_expired_transactions array and processes any failed TXNs |
|
400 | - * |
|
401 | - * @throws EE_Error |
|
402 | - * @throws InvalidDataTypeException |
|
403 | - * @throws InvalidInterfaceException |
|
404 | - * @throws InvalidArgumentException |
|
405 | - * @throws ReflectionException |
|
406 | - * @throws DomainException |
|
407 | - * @throws RuntimeException |
|
408 | - */ |
|
409 | - public static function process_expired_transactions() |
|
410 | - { |
|
411 | - if ( |
|
412 | - // are there any TXNs that need cleaning up ? |
|
413 | - empty(self::$_expired_transactions) |
|
414 | - // reschedule the cron if we can't hit the db right now |
|
415 | - || EE_Cron_Tasks::reschedule_cron_for_transactions_if_maintenance_mode( |
|
416 | - 'schedule_expired_transaction_check', |
|
417 | - self::$_expired_transactions |
|
418 | - ) |
|
419 | - ) { |
|
420 | - return; |
|
421 | - } |
|
422 | - /** @type EE_Transaction_Processor $transaction_processor */ |
|
423 | - $transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor'); |
|
424 | - // set revisit flag for txn processor |
|
425 | - $transaction_processor->set_revisit(); |
|
426 | - // load EEM_Transaction |
|
427 | - EE_Registry::instance()->load_model('Transaction'); |
|
428 | - foreach (self::$_expired_transactions as $TXN_ID) { |
|
429 | - $transaction = EEM_Transaction::instance()->get_one_by_ID($TXN_ID); |
|
430 | - // verify transaction and whether it is failed or not |
|
431 | - if ($transaction instanceof EE_Transaction) { |
|
432 | - switch ($transaction->status_ID()) { |
|
433 | - // Completed TXNs |
|
434 | - case EEM_Transaction::complete_status_code : |
|
435 | - do_action( |
|
436 | - 'AHEE__EE_Cron_Tasks__process_expired_transactions__completed_transaction', |
|
437 | - $transaction |
|
438 | - ); |
|
439 | - break; |
|
440 | - // Overpaid TXNs |
|
441 | - case EEM_Transaction::overpaid_status_code : |
|
442 | - do_action( |
|
443 | - 'AHEE__EE_Cron_Tasks__process_expired_transactions__overpaid_transaction', |
|
444 | - $transaction |
|
445 | - ); |
|
446 | - break; |
|
447 | - // Incomplete TXNs |
|
448 | - case EEM_Transaction::incomplete_status_code : |
|
449 | - do_action( |
|
450 | - 'AHEE__EE_Cron_Tasks__process_expired_transactions__incomplete_transaction', |
|
451 | - $transaction |
|
452 | - ); |
|
453 | - // todo : move business logic into EE_Transaction_Processor for finalizing abandoned transactions |
|
454 | - break; |
|
455 | - // Abandoned TXNs |
|
456 | - case EEM_Transaction::abandoned_status_code : |
|
457 | - // run hook before updating transaction, primarily so |
|
458 | - // EED_Ticket_Sales_Monitor::process_abandoned_transactions() can release reserved tickets |
|
459 | - do_action( |
|
460 | - 'AHEE__EE_Cron_Tasks__process_expired_transactions__abandoned_transaction', |
|
461 | - $transaction |
|
462 | - ); |
|
463 | - // don't finalize the TXN if it has already been completed |
|
464 | - if ($transaction->all_reg_steps_completed() !== true) { |
|
465 | - /** @type EE_Payment_Processor $payment_processor */ |
|
466 | - $payment_processor = EE_Registry::instance()->load_core('Payment_Processor'); |
|
467 | - // let's simulate an IPN here which will trigger any notifications that need to go out |
|
468 | - $payment_processor->update_txn_based_on_payment( |
|
469 | - $transaction, |
|
470 | - $transaction->last_payment(), |
|
471 | - true, |
|
472 | - true |
|
473 | - ); |
|
474 | - } |
|
475 | - break; |
|
476 | - // Failed TXNs |
|
477 | - case EEM_Transaction::failed_status_code : |
|
478 | - do_action( |
|
479 | - 'AHEE__EE_Cron_Tasks__process_expired_transactions__failed_transaction', |
|
480 | - $transaction |
|
481 | - ); |
|
482 | - // todo : perform garbage collection here and remove clean_out_junk_transactions() |
|
483 | - //$registrations = $transaction->registrations(); |
|
484 | - //if ( ! empty( $registrations ) ) { |
|
485 | - // foreach ( $registrations as $registration ) { |
|
486 | - // if ( $registration instanceof EE_Registration ) { |
|
487 | - //$delete_registration = true; |
|
488 | - //if ( $registration->attendee() instanceof EE_Attendee ) { |
|
489 | - // $delete_registration = false; |
|
490 | - //} |
|
491 | - //if ( $delete_registration ) { |
|
492 | - // $registration->delete_permanently(); |
|
493 | - // $registration->delete_related_permanently(); |
|
494 | - //} |
|
495 | - // } |
|
496 | - // } |
|
497 | - //} |
|
498 | - break; |
|
499 | - } |
|
500 | - } |
|
501 | - unset(self::$_expired_transactions[ $TXN_ID ]); |
|
502 | - } |
|
503 | - } |
|
504 | - |
|
505 | - |
|
506 | - |
|
507 | - /************* END OF EXPIRED TRANSACTION CHECK *************/ |
|
508 | - |
|
509 | - |
|
510 | - |
|
511 | - /************* START CLEAN UP BOT TRANSACTIONS **********************/ |
|
512 | - |
|
513 | - |
|
514 | - |
|
515 | - /** |
|
516 | - * callback for 'AHEE__EE_Cron_Tasks__clean_up_junk_transactions' |
|
517 | - * which is setup during activation to run on an hourly cron |
|
518 | - * |
|
519 | - * @throws EE_Error |
|
520 | - * @throws InvalidArgumentException |
|
521 | - * @throws InvalidDataTypeException |
|
522 | - * @throws InvalidInterfaceException |
|
523 | - * @throws DomainException |
|
524 | - */ |
|
525 | - public static function clean_out_junk_transactions() |
|
526 | - { |
|
527 | - if (EE_Maintenance_Mode::instance()->models_can_query()) { |
|
528 | - EED_Ticket_Sales_Monitor::reset_reservation_counts(); |
|
529 | - EEM_Transaction::instance('')->delete_junk_transactions(); |
|
530 | - EEM_Registration::instance('')->delete_registrations_with_no_transaction(); |
|
531 | - EEM_Line_Item::instance('')->delete_line_items_with_no_transaction(); |
|
532 | - } |
|
533 | - } |
|
534 | - |
|
535 | - |
|
536 | - |
|
537 | - /** |
|
538 | - * Deletes old gateway logs. After about a week we usually don't need them for debugging. But folks can filter that. |
|
539 | - * |
|
540 | - * @throws EE_Error |
|
541 | - * @throws InvalidDataTypeException |
|
542 | - * @throws InvalidInterfaceException |
|
543 | - * @throws InvalidArgumentException |
|
544 | - */ |
|
545 | - public static function clean_out_old_gateway_logs() |
|
546 | - { |
|
547 | - if (EE_Maintenance_Mode::instance()->models_can_query()) { |
|
548 | - $time_diff_for_comparison = apply_filters( |
|
549 | - 'FHEE__EE_Cron_Tasks__clean_out_old_gateway_logs__time_diff_for_comparison', |
|
550 | - '-1 week' |
|
551 | - ); |
|
552 | - EEM_Change_Log::instance()->delete_gateway_logs_older_than(new DateTime($time_diff_for_comparison)); |
|
553 | - } |
|
554 | - } |
|
555 | - |
|
556 | - |
|
557 | - /***************** FINALIZE ABANDONED TRANSACTIONS *****************/ |
|
558 | - |
|
559 | - |
|
560 | - |
|
561 | - /** |
|
562 | - * @var array |
|
563 | - */ |
|
564 | - protected static $_abandoned_transactions = array(); |
|
565 | - |
|
566 | - |
|
567 | - /** |
|
568 | - * @deprecated |
|
569 | - * @param int $timestamp |
|
570 | - * @param int $TXN_ID |
|
571 | - */ |
|
572 | - public static function schedule_finalize_abandoned_transactions_check($timestamp, $TXN_ID) |
|
573 | - { |
|
574 | - EE_Cron_Tasks::schedule_expired_transaction_check($timestamp, $TXN_ID); |
|
575 | - } |
|
576 | - |
|
577 | - |
|
578 | - /** |
|
579 | - * @deprecated |
|
580 | - * @param int $TXN_ID |
|
581 | - */ |
|
582 | - public static function check_for_abandoned_transactions($TXN_ID = 0) |
|
583 | - { |
|
584 | - EE_Cron_Tasks::expired_transaction_check($TXN_ID); |
|
585 | - } |
|
586 | - |
|
587 | - |
|
588 | - /** |
|
589 | - * @deprecated |
|
590 | - * @throws EE_Error |
|
591 | - * @throws DomainException |
|
592 | - * @throws InvalidDataTypeException |
|
593 | - * @throws InvalidInterfaceException |
|
594 | - * @throws InvalidArgumentException |
|
595 | - * @throws ReflectionException |
|
596 | - * @throws RuntimeException |
|
597 | - */ |
|
598 | - public static function finalize_abandoned_transactions() |
|
599 | - { |
|
600 | - do_action('AHEE_log', __CLASS__, __FUNCTION__); |
|
601 | - if ( |
|
602 | - // are there any TXNs that need cleaning up ? |
|
603 | - empty(self::$_abandoned_transactions) |
|
604 | - // reschedule the cron if we can't hit the db right now |
|
605 | - || EE_Cron_Tasks::reschedule_cron_for_transactions_if_maintenance_mode( |
|
606 | - 'schedule_expired_transaction_check', |
|
607 | - self::$_abandoned_transactions |
|
608 | - ) |
|
609 | - ) { |
|
610 | - return; |
|
611 | - } |
|
612 | - // combine our arrays of transaction IDs |
|
613 | - self::$_expired_transactions = self::$_abandoned_transactions + self::$_expired_transactions; |
|
614 | - // and deal with abandoned transactions here now... |
|
615 | - EE_Cron_Tasks::process_expired_transactions(); |
|
616 | - } |
|
617 | - |
|
618 | - |
|
619 | - |
|
620 | - /************* END OF FINALIZE ABANDONED TRANSACTIONS *************/ |
|
20 | + /** |
|
21 | + * WordPress doesn't allow duplicate crons within 10 minutes of the original, |
|
22 | + * so we'll set our retry time for just over 10 minutes to avoid that |
|
23 | + */ |
|
24 | + const reschedule_timeout = 605; |
|
25 | + |
|
26 | + |
|
27 | + /** |
|
28 | + * @var EE_Cron_Tasks |
|
29 | + */ |
|
30 | + private static $_instance; |
|
31 | + |
|
32 | + |
|
33 | + /** |
|
34 | + * @return EE_Cron_Tasks |
|
35 | + * @throws ReflectionException |
|
36 | + * @throws EE_Error |
|
37 | + * @throws InvalidArgumentException |
|
38 | + * @throws InvalidInterfaceException |
|
39 | + * @throws InvalidDataTypeException |
|
40 | + */ |
|
41 | + public static function instance() |
|
42 | + { |
|
43 | + if (! self::$_instance instanceof EE_Cron_Tasks) { |
|
44 | + self::$_instance = new self(); |
|
45 | + } |
|
46 | + return self::$_instance; |
|
47 | + } |
|
48 | + |
|
49 | + |
|
50 | + /** |
|
51 | + * @access private |
|
52 | + * @throws InvalidDataTypeException |
|
53 | + * @throws InvalidInterfaceException |
|
54 | + * @throws InvalidArgumentException |
|
55 | + * @throws EE_Error |
|
56 | + * @throws ReflectionException |
|
57 | + */ |
|
58 | + private function __construct() |
|
59 | + { |
|
60 | + do_action('AHEE_log', __CLASS__, __FUNCTION__); |
|
61 | + // verify that WP Cron is enabled |
|
62 | + if ( |
|
63 | + defined('DISABLE_WP_CRON') |
|
64 | + && DISABLE_WP_CRON |
|
65 | + && is_admin() |
|
66 | + && ! get_option('ee_disabled_wp_cron_check') |
|
67 | + ) { |
|
68 | + /** |
|
69 | + * This needs to be delayed until after the config is loaded because EE_Cron_Tasks is constructed before |
|
70 | + * config is loaded. |
|
71 | + * This is intentionally using a anonymous function so that its not easily de-registered. Client code |
|
72 | + * wanting to not have this functionality can just register its own action at a priority after this one to |
|
73 | + * reverse any changes. |
|
74 | + */ |
|
75 | + add_action( |
|
76 | + 'AHEE__EE_System__load_core_configuration__complete', |
|
77 | + function () |
|
78 | + { |
|
79 | + EE_Registry::instance()->NET_CFG->core->do_messages_on_same_request = true; |
|
80 | + EE_Registry::instance()->NET_CFG->update_config(true, false); |
|
81 | + add_option('ee_disabled_wp_cron_check', 1, '', false); |
|
82 | + } |
|
83 | + ); |
|
84 | + } |
|
85 | + // UPDATE TRANSACTION WITH PAYMENT |
|
86 | + add_action( |
|
87 | + 'AHEE__EE_Cron_Tasks__update_transaction_with_payment_2', |
|
88 | + array('EE_Cron_Tasks', 'setup_update_for_transaction_with_payment'), |
|
89 | + 10, |
|
90 | + 2 |
|
91 | + ); |
|
92 | + // ABANDONED / EXPIRED TRANSACTION CHECK |
|
93 | + add_action( |
|
94 | + 'AHEE__EE_Cron_Tasks__expired_transaction_check', |
|
95 | + array('EE_Cron_Tasks', 'expired_transaction_check'), |
|
96 | + 10, |
|
97 | + 1 |
|
98 | + ); |
|
99 | + // CLEAN OUT JUNK TRANSACTIONS AND RELATED DATA |
|
100 | + add_action( |
|
101 | + 'AHEE__EE_Cron_Tasks__clean_up_junk_transactions', |
|
102 | + array('EE_Cron_Tasks', 'clean_out_junk_transactions') |
|
103 | + ); |
|
104 | + // logging |
|
105 | + add_action( |
|
106 | + 'AHEE__EE_System__load_core_configuration__complete', |
|
107 | + array('EE_Cron_Tasks', 'log_scheduled_ee_crons') |
|
108 | + ); |
|
109 | + EE_Registry::instance()->load_lib('Messages_Scheduler'); |
|
110 | + //clean out old gateway logs |
|
111 | + add_action( |
|
112 | + 'AHEE_EE_Cron_Tasks__clean_out_old_gateway_logs', |
|
113 | + array('EE_Cron_Tasks', 'clean_out_old_gateway_logs') |
|
114 | + ); |
|
115 | + } |
|
116 | + |
|
117 | + |
|
118 | + /** |
|
119 | + * @access protected |
|
120 | + * @return void |
|
121 | + */ |
|
122 | + public static function log_scheduled_ee_crons() |
|
123 | + { |
|
124 | + $ee_crons = array( |
|
125 | + 'AHEE__EE_Cron_Tasks__update_transaction_with_payment', |
|
126 | + 'AHEE__EE_Cron_Tasks__finalize_abandoned_transactions', |
|
127 | + 'AHEE__EE_Cron_Tasks__clean_up_junk_transactions', |
|
128 | + ); |
|
129 | + $crons = (array) get_option('cron'); |
|
130 | + if (! is_array($crons)) { |
|
131 | + return; |
|
132 | + } |
|
133 | + foreach ($crons as $timestamp => $cron) { |
|
134 | + /** @var array[] $cron */ |
|
135 | + foreach ($ee_crons as $ee_cron) { |
|
136 | + if (isset($cron[ $ee_cron ]) && is_array($cron[ $ee_cron ])) { |
|
137 | + do_action('AHEE_log', __CLASS__, __FUNCTION__, $ee_cron, 'scheduled EE cron'); |
|
138 | + foreach ($cron[ $ee_cron ] as $ee_cron_details) { |
|
139 | + if (! empty($ee_cron_details['args'])) { |
|
140 | + do_action( |
|
141 | + 'AHEE_log', |
|
142 | + __CLASS__, |
|
143 | + __FUNCTION__, |
|
144 | + print_r($ee_cron_details['args'], true), |
|
145 | + "{$ee_cron} args" |
|
146 | + ); |
|
147 | + } |
|
148 | + } |
|
149 | + } |
|
150 | + } |
|
151 | + } |
|
152 | + } |
|
153 | + |
|
154 | + |
|
155 | + |
|
156 | + /** |
|
157 | + * reschedule_cron_for_transactions_if_maintenance_mode |
|
158 | + * if Maintenance Mode is active, this will reschedule a cron to run again in 10 minutes |
|
159 | + * |
|
160 | + * @param string $cron_task |
|
161 | + * @param array $TXN_IDs |
|
162 | + * @return bool |
|
163 | + * @throws DomainException |
|
164 | + */ |
|
165 | + public static function reschedule_cron_for_transactions_if_maintenance_mode($cron_task, array $TXN_IDs) |
|
166 | + { |
|
167 | + if (! method_exists('EE_Cron_Tasks', $cron_task)) { |
|
168 | + throw new DomainException( |
|
169 | + sprintf( |
|
170 | + __('"%1$s" is not valid method on EE_Cron_Tasks.', 'event_espresso'), |
|
171 | + $cron_task |
|
172 | + ) |
|
173 | + ); |
|
174 | + } |
|
175 | + // reschedule the cron if we can't hit the db right now |
|
176 | + if (! EE_Maintenance_Mode::instance()->models_can_query()) { |
|
177 | + foreach ($TXN_IDs as $TXN_ID => $additional_vars) { |
|
178 | + // ensure $additional_vars is an array |
|
179 | + $additional_vars = is_array($additional_vars) ? $additional_vars : array($additional_vars); |
|
180 | + // reset cron job for the TXN |
|
181 | + call_user_func_array( |
|
182 | + array('EE_Cron_Tasks', $cron_task), |
|
183 | + array_merge( |
|
184 | + array( |
|
185 | + time() + (10 * MINUTE_IN_SECONDS), |
|
186 | + $TXN_ID, |
|
187 | + ), |
|
188 | + $additional_vars |
|
189 | + ) |
|
190 | + ); |
|
191 | + } |
|
192 | + return true; |
|
193 | + } |
|
194 | + return false; |
|
195 | + } |
|
196 | + |
|
197 | + |
|
198 | + |
|
199 | + |
|
200 | + /**************** UPDATE TRANSACTION WITH PAYMENT ****************/ |
|
201 | + |
|
202 | + |
|
203 | + |
|
204 | + /** |
|
205 | + * array of TXN IDs and the payment |
|
206 | + * |
|
207 | + * @var array |
|
208 | + */ |
|
209 | + protected static $_update_transactions_with_payment = array(); |
|
210 | + |
|
211 | + |
|
212 | + /** |
|
213 | + * schedule_update_transaction_with_payment |
|
214 | + * sets a wp_schedule_single_event() for updating any TXNs that may |
|
215 | + * require updating due to recently received payments |
|
216 | + * |
|
217 | + * @param int $timestamp |
|
218 | + * @param int $TXN_ID |
|
219 | + * @param int $PAY_ID |
|
220 | + */ |
|
221 | + public static function schedule_update_transaction_with_payment( |
|
222 | + $timestamp, |
|
223 | + $TXN_ID, |
|
224 | + $PAY_ID |
|
225 | + ) { |
|
226 | + do_action('AHEE_log', __CLASS__, __FUNCTION__); |
|
227 | + // validate $TXN_ID and $timestamp |
|
228 | + $TXN_ID = absint($TXN_ID); |
|
229 | + $timestamp = absint($timestamp); |
|
230 | + if ($TXN_ID && $timestamp) { |
|
231 | + wp_schedule_single_event( |
|
232 | + $timestamp, |
|
233 | + 'AHEE__EE_Cron_Tasks__update_transaction_with_payment_2', |
|
234 | + array($TXN_ID, $PAY_ID) |
|
235 | + ); |
|
236 | + } |
|
237 | + } |
|
238 | + |
|
239 | + |
|
240 | + /** |
|
241 | + * setup_update_for_transaction_with_payment |
|
242 | + * this is the callback for the action hook: |
|
243 | + * 'AHEE__EE_Cron_Tasks__update_transaction_with_payment' |
|
244 | + * which is setup by EE_Cron_Tasks::schedule_update_transaction_with_payment(). |
|
245 | + * The passed TXN_ID and associated payment gets added to an array, and then |
|
246 | + * the EE_Cron_Tasks::update_transaction_with_payment() function is hooked into |
|
247 | + * 'shutdown' which will actually handle the processing of any |
|
248 | + * transactions requiring updating, because doing so now would be too early |
|
249 | + * and the required resources may not be available |
|
250 | + * |
|
251 | + * @param int $TXN_ID |
|
252 | + * @param int $PAY_ID |
|
253 | + */ |
|
254 | + public static function setup_update_for_transaction_with_payment($TXN_ID = 0, $PAY_ID = 0) |
|
255 | + { |
|
256 | + do_action('AHEE_log', __CLASS__, __FUNCTION__, $TXN_ID, '$TXN_ID'); |
|
257 | + if (absint($TXN_ID)) { |
|
258 | + self::$_update_transactions_with_payment[ $TXN_ID ] = $PAY_ID; |
|
259 | + add_action( |
|
260 | + 'shutdown', |
|
261 | + array('EE_Cron_Tasks', 'update_transaction_with_payment'), |
|
262 | + 5 |
|
263 | + ); |
|
264 | + } |
|
265 | + } |
|
266 | + |
|
267 | + |
|
268 | + /** |
|
269 | + * update_transaction_with_payment |
|
270 | + * loops through the self::$_abandoned_transactions array |
|
271 | + * and attempts to finalize any TXNs that have not been completed |
|
272 | + * but have had their sessions expired, most likely due to a user not |
|
273 | + * returning from an off-site payment gateway |
|
274 | + * |
|
275 | + * @throws EE_Error |
|
276 | + * @throws DomainException |
|
277 | + * @throws InvalidDataTypeException |
|
278 | + * @throws InvalidInterfaceException |
|
279 | + * @throws InvalidArgumentException |
|
280 | + * @throws ReflectionException |
|
281 | + * @throws RuntimeException |
|
282 | + */ |
|
283 | + public static function update_transaction_with_payment() |
|
284 | + { |
|
285 | + do_action('AHEE_log', __CLASS__, __FUNCTION__); |
|
286 | + if ( |
|
287 | + // are there any TXNs that need cleaning up ? |
|
288 | + empty(self::$_update_transactions_with_payment) |
|
289 | + // reschedule the cron if we can't hit the db right now |
|
290 | + || EE_Cron_Tasks::reschedule_cron_for_transactions_if_maintenance_mode( |
|
291 | + 'schedule_update_transaction_with_payment', |
|
292 | + self::$_update_transactions_with_payment |
|
293 | + ) |
|
294 | + ) { |
|
295 | + return; |
|
296 | + } |
|
297 | + /** @type EE_Payment_Processor $payment_processor */ |
|
298 | + $payment_processor = EE_Registry::instance()->load_core('Payment_Processor'); |
|
299 | + // set revisit flag for payment processor |
|
300 | + $payment_processor->set_revisit(); |
|
301 | + // load EEM_Transaction |
|
302 | + EE_Registry::instance()->load_model('Transaction'); |
|
303 | + foreach (self::$_update_transactions_with_payment as $TXN_ID => $PAY_ID) { |
|
304 | + // reschedule the cron if we can't hit the db right now |
|
305 | + if (! EE_Maintenance_Mode::instance()->models_can_query()) { |
|
306 | + // reset cron job for updating the TXN |
|
307 | + EE_Cron_Tasks::schedule_update_transaction_with_payment( |
|
308 | + time() + EE_Cron_Tasks::reschedule_timeout, |
|
309 | + $TXN_ID, |
|
310 | + $PAY_ID |
|
311 | + ); |
|
312 | + continue; |
|
313 | + } |
|
314 | + $transaction = EEM_Transaction::instance()->get_one_by_ID($TXN_ID); |
|
315 | + $payment = EEM_Payment::instance()->get_one_by_ID($PAY_ID); |
|
316 | + // verify transaction |
|
317 | + if ($transaction instanceof EE_Transaction && $payment instanceof EE_Payment) { |
|
318 | + // now try to update the TXN with any payments |
|
319 | + $payment_processor->update_txn_based_on_payment($transaction, $payment, true, true); |
|
320 | + } |
|
321 | + unset(self::$_update_transactions_with_payment[ $TXN_ID ]); |
|
322 | + } |
|
323 | + } |
|
324 | + |
|
325 | + |
|
326 | + |
|
327 | + /************ END OF UPDATE TRANSACTION WITH PAYMENT ************/ |
|
328 | + |
|
329 | + |
|
330 | + |
|
331 | + /***************** EXPIRED TRANSACTION CHECK *****************/ |
|
332 | + |
|
333 | + |
|
334 | + |
|
335 | + /** |
|
336 | + * array of TXN IDs |
|
337 | + * |
|
338 | + * @var array |
|
339 | + */ |
|
340 | + protected static $_expired_transactions = array(); |
|
341 | + |
|
342 | + |
|
343 | + |
|
344 | + /** |
|
345 | + * schedule_expired_transaction_check |
|
346 | + * sets a wp_schedule_single_event() for following up on TXNs after their session has expired |
|
347 | + * |
|
348 | + * @param int $timestamp |
|
349 | + * @param int $TXN_ID |
|
350 | + */ |
|
351 | + public static function schedule_expired_transaction_check( |
|
352 | + $timestamp, |
|
353 | + $TXN_ID |
|
354 | + ) { |
|
355 | + // validate $TXN_ID and $timestamp |
|
356 | + $TXN_ID = absint($TXN_ID); |
|
357 | + $timestamp = absint($timestamp); |
|
358 | + if ($TXN_ID && $timestamp) { |
|
359 | + wp_schedule_single_event( |
|
360 | + $timestamp, |
|
361 | + 'AHEE__EE_Cron_Tasks__expired_transaction_check', |
|
362 | + array($TXN_ID) |
|
363 | + ); |
|
364 | + } |
|
365 | + } |
|
366 | + |
|
367 | + |
|
368 | + |
|
369 | + /** |
|
370 | + * expired_transaction_check |
|
371 | + * this is the callback for the action hook: |
|
372 | + * 'AHEE__EE_Cron_Tasks__transaction_session_expiration_check' |
|
373 | + * which is utilized by wp_schedule_single_event() |
|
374 | + * in \EED_Single_Page_Checkout::_initialize_transaction(). |
|
375 | + * The passed TXN_ID gets added to an array, and then the |
|
376 | + * process_expired_transactions() function is hooked into |
|
377 | + * 'AHEE__EE_System__core_loaded_and_ready' which will actually handle the |
|
378 | + * processing of any failed transactions, because doing so now would be |
|
379 | + * too early and the required resources may not be available |
|
380 | + * |
|
381 | + * @param int $TXN_ID |
|
382 | + */ |
|
383 | + public static function expired_transaction_check($TXN_ID = 0) |
|
384 | + { |
|
385 | + if (absint($TXN_ID)) { |
|
386 | + self::$_expired_transactions[ $TXN_ID ] = $TXN_ID; |
|
387 | + add_action( |
|
388 | + 'shutdown', |
|
389 | + array('EE_Cron_Tasks', 'process_expired_transactions'), |
|
390 | + 5 |
|
391 | + ); |
|
392 | + } |
|
393 | + } |
|
394 | + |
|
395 | + |
|
396 | + |
|
397 | + /** |
|
398 | + * process_expired_transactions |
|
399 | + * loops through the self::$_expired_transactions array and processes any failed TXNs |
|
400 | + * |
|
401 | + * @throws EE_Error |
|
402 | + * @throws InvalidDataTypeException |
|
403 | + * @throws InvalidInterfaceException |
|
404 | + * @throws InvalidArgumentException |
|
405 | + * @throws ReflectionException |
|
406 | + * @throws DomainException |
|
407 | + * @throws RuntimeException |
|
408 | + */ |
|
409 | + public static function process_expired_transactions() |
|
410 | + { |
|
411 | + if ( |
|
412 | + // are there any TXNs that need cleaning up ? |
|
413 | + empty(self::$_expired_transactions) |
|
414 | + // reschedule the cron if we can't hit the db right now |
|
415 | + || EE_Cron_Tasks::reschedule_cron_for_transactions_if_maintenance_mode( |
|
416 | + 'schedule_expired_transaction_check', |
|
417 | + self::$_expired_transactions |
|
418 | + ) |
|
419 | + ) { |
|
420 | + return; |
|
421 | + } |
|
422 | + /** @type EE_Transaction_Processor $transaction_processor */ |
|
423 | + $transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor'); |
|
424 | + // set revisit flag for txn processor |
|
425 | + $transaction_processor->set_revisit(); |
|
426 | + // load EEM_Transaction |
|
427 | + EE_Registry::instance()->load_model('Transaction'); |
|
428 | + foreach (self::$_expired_transactions as $TXN_ID) { |
|
429 | + $transaction = EEM_Transaction::instance()->get_one_by_ID($TXN_ID); |
|
430 | + // verify transaction and whether it is failed or not |
|
431 | + if ($transaction instanceof EE_Transaction) { |
|
432 | + switch ($transaction->status_ID()) { |
|
433 | + // Completed TXNs |
|
434 | + case EEM_Transaction::complete_status_code : |
|
435 | + do_action( |
|
436 | + 'AHEE__EE_Cron_Tasks__process_expired_transactions__completed_transaction', |
|
437 | + $transaction |
|
438 | + ); |
|
439 | + break; |
|
440 | + // Overpaid TXNs |
|
441 | + case EEM_Transaction::overpaid_status_code : |
|
442 | + do_action( |
|
443 | + 'AHEE__EE_Cron_Tasks__process_expired_transactions__overpaid_transaction', |
|
444 | + $transaction |
|
445 | + ); |
|
446 | + break; |
|
447 | + // Incomplete TXNs |
|
448 | + case EEM_Transaction::incomplete_status_code : |
|
449 | + do_action( |
|
450 | + 'AHEE__EE_Cron_Tasks__process_expired_transactions__incomplete_transaction', |
|
451 | + $transaction |
|
452 | + ); |
|
453 | + // todo : move business logic into EE_Transaction_Processor for finalizing abandoned transactions |
|
454 | + break; |
|
455 | + // Abandoned TXNs |
|
456 | + case EEM_Transaction::abandoned_status_code : |
|
457 | + // run hook before updating transaction, primarily so |
|
458 | + // EED_Ticket_Sales_Monitor::process_abandoned_transactions() can release reserved tickets |
|
459 | + do_action( |
|
460 | + 'AHEE__EE_Cron_Tasks__process_expired_transactions__abandoned_transaction', |
|
461 | + $transaction |
|
462 | + ); |
|
463 | + // don't finalize the TXN if it has already been completed |
|
464 | + if ($transaction->all_reg_steps_completed() !== true) { |
|
465 | + /** @type EE_Payment_Processor $payment_processor */ |
|
466 | + $payment_processor = EE_Registry::instance()->load_core('Payment_Processor'); |
|
467 | + // let's simulate an IPN here which will trigger any notifications that need to go out |
|
468 | + $payment_processor->update_txn_based_on_payment( |
|
469 | + $transaction, |
|
470 | + $transaction->last_payment(), |
|
471 | + true, |
|
472 | + true |
|
473 | + ); |
|
474 | + } |
|
475 | + break; |
|
476 | + // Failed TXNs |
|
477 | + case EEM_Transaction::failed_status_code : |
|
478 | + do_action( |
|
479 | + 'AHEE__EE_Cron_Tasks__process_expired_transactions__failed_transaction', |
|
480 | + $transaction |
|
481 | + ); |
|
482 | + // todo : perform garbage collection here and remove clean_out_junk_transactions() |
|
483 | + //$registrations = $transaction->registrations(); |
|
484 | + //if ( ! empty( $registrations ) ) { |
|
485 | + // foreach ( $registrations as $registration ) { |
|
486 | + // if ( $registration instanceof EE_Registration ) { |
|
487 | + //$delete_registration = true; |
|
488 | + //if ( $registration->attendee() instanceof EE_Attendee ) { |
|
489 | + // $delete_registration = false; |
|
490 | + //} |
|
491 | + //if ( $delete_registration ) { |
|
492 | + // $registration->delete_permanently(); |
|
493 | + // $registration->delete_related_permanently(); |
|
494 | + //} |
|
495 | + // } |
|
496 | + // } |
|
497 | + //} |
|
498 | + break; |
|
499 | + } |
|
500 | + } |
|
501 | + unset(self::$_expired_transactions[ $TXN_ID ]); |
|
502 | + } |
|
503 | + } |
|
504 | + |
|
505 | + |
|
506 | + |
|
507 | + /************* END OF EXPIRED TRANSACTION CHECK *************/ |
|
508 | + |
|
509 | + |
|
510 | + |
|
511 | + /************* START CLEAN UP BOT TRANSACTIONS **********************/ |
|
512 | + |
|
513 | + |
|
514 | + |
|
515 | + /** |
|
516 | + * callback for 'AHEE__EE_Cron_Tasks__clean_up_junk_transactions' |
|
517 | + * which is setup during activation to run on an hourly cron |
|
518 | + * |
|
519 | + * @throws EE_Error |
|
520 | + * @throws InvalidArgumentException |
|
521 | + * @throws InvalidDataTypeException |
|
522 | + * @throws InvalidInterfaceException |
|
523 | + * @throws DomainException |
|
524 | + */ |
|
525 | + public static function clean_out_junk_transactions() |
|
526 | + { |
|
527 | + if (EE_Maintenance_Mode::instance()->models_can_query()) { |
|
528 | + EED_Ticket_Sales_Monitor::reset_reservation_counts(); |
|
529 | + EEM_Transaction::instance('')->delete_junk_transactions(); |
|
530 | + EEM_Registration::instance('')->delete_registrations_with_no_transaction(); |
|
531 | + EEM_Line_Item::instance('')->delete_line_items_with_no_transaction(); |
|
532 | + } |
|
533 | + } |
|
534 | + |
|
535 | + |
|
536 | + |
|
537 | + /** |
|
538 | + * Deletes old gateway logs. After about a week we usually don't need them for debugging. But folks can filter that. |
|
539 | + * |
|
540 | + * @throws EE_Error |
|
541 | + * @throws InvalidDataTypeException |
|
542 | + * @throws InvalidInterfaceException |
|
543 | + * @throws InvalidArgumentException |
|
544 | + */ |
|
545 | + public static function clean_out_old_gateway_logs() |
|
546 | + { |
|
547 | + if (EE_Maintenance_Mode::instance()->models_can_query()) { |
|
548 | + $time_diff_for_comparison = apply_filters( |
|
549 | + 'FHEE__EE_Cron_Tasks__clean_out_old_gateway_logs__time_diff_for_comparison', |
|
550 | + '-1 week' |
|
551 | + ); |
|
552 | + EEM_Change_Log::instance()->delete_gateway_logs_older_than(new DateTime($time_diff_for_comparison)); |
|
553 | + } |
|
554 | + } |
|
555 | + |
|
556 | + |
|
557 | + /***************** FINALIZE ABANDONED TRANSACTIONS *****************/ |
|
558 | + |
|
559 | + |
|
560 | + |
|
561 | + /** |
|
562 | + * @var array |
|
563 | + */ |
|
564 | + protected static $_abandoned_transactions = array(); |
|
565 | + |
|
566 | + |
|
567 | + /** |
|
568 | + * @deprecated |
|
569 | + * @param int $timestamp |
|
570 | + * @param int $TXN_ID |
|
571 | + */ |
|
572 | + public static function schedule_finalize_abandoned_transactions_check($timestamp, $TXN_ID) |
|
573 | + { |
|
574 | + EE_Cron_Tasks::schedule_expired_transaction_check($timestamp, $TXN_ID); |
|
575 | + } |
|
576 | + |
|
577 | + |
|
578 | + /** |
|
579 | + * @deprecated |
|
580 | + * @param int $TXN_ID |
|
581 | + */ |
|
582 | + public static function check_for_abandoned_transactions($TXN_ID = 0) |
|
583 | + { |
|
584 | + EE_Cron_Tasks::expired_transaction_check($TXN_ID); |
|
585 | + } |
|
586 | + |
|
587 | + |
|
588 | + /** |
|
589 | + * @deprecated |
|
590 | + * @throws EE_Error |
|
591 | + * @throws DomainException |
|
592 | + * @throws InvalidDataTypeException |
|
593 | + * @throws InvalidInterfaceException |
|
594 | + * @throws InvalidArgumentException |
|
595 | + * @throws ReflectionException |
|
596 | + * @throws RuntimeException |
|
597 | + */ |
|
598 | + public static function finalize_abandoned_transactions() |
|
599 | + { |
|
600 | + do_action('AHEE_log', __CLASS__, __FUNCTION__); |
|
601 | + if ( |
|
602 | + // are there any TXNs that need cleaning up ? |
|
603 | + empty(self::$_abandoned_transactions) |
|
604 | + // reschedule the cron if we can't hit the db right now |
|
605 | + || EE_Cron_Tasks::reschedule_cron_for_transactions_if_maintenance_mode( |
|
606 | + 'schedule_expired_transaction_check', |
|
607 | + self::$_abandoned_transactions |
|
608 | + ) |
|
609 | + ) { |
|
610 | + return; |
|
611 | + } |
|
612 | + // combine our arrays of transaction IDs |
|
613 | + self::$_expired_transactions = self::$_abandoned_transactions + self::$_expired_transactions; |
|
614 | + // and deal with abandoned transactions here now... |
|
615 | + EE_Cron_Tasks::process_expired_transactions(); |
|
616 | + } |
|
617 | + |
|
618 | + |
|
619 | + |
|
620 | + /************* END OF FINALIZE ABANDONED TRANSACTIONS *************/ |
|
621 | 621 | } |
622 | 622 | // End of file EE_Cron_Tasks.core.php |
623 | 623 | // Location: /EE_Cron_Tasks.core.php |
@@ -40,7 +40,7 @@ discard block |
||
40 | 40 | */ |
41 | 41 | public static function instance() |
42 | 42 | { |
43 | - if (! self::$_instance instanceof EE_Cron_Tasks) { |
|
43 | + if ( ! self::$_instance instanceof EE_Cron_Tasks) { |
|
44 | 44 | self::$_instance = new self(); |
45 | 45 | } |
46 | 46 | return self::$_instance; |
@@ -74,7 +74,7 @@ discard block |
||
74 | 74 | */ |
75 | 75 | add_action( |
76 | 76 | 'AHEE__EE_System__load_core_configuration__complete', |
77 | - function () |
|
77 | + function() |
|
78 | 78 | { |
79 | 79 | EE_Registry::instance()->NET_CFG->core->do_messages_on_same_request = true; |
80 | 80 | EE_Registry::instance()->NET_CFG->update_config(true, false); |
@@ -126,17 +126,17 @@ discard block |
||
126 | 126 | 'AHEE__EE_Cron_Tasks__finalize_abandoned_transactions', |
127 | 127 | 'AHEE__EE_Cron_Tasks__clean_up_junk_transactions', |
128 | 128 | ); |
129 | - $crons = (array) get_option('cron'); |
|
130 | - if (! is_array($crons)) { |
|
129 | + $crons = (array) get_option('cron'); |
|
130 | + if ( ! is_array($crons)) { |
|
131 | 131 | return; |
132 | 132 | } |
133 | 133 | foreach ($crons as $timestamp => $cron) { |
134 | 134 | /** @var array[] $cron */ |
135 | 135 | foreach ($ee_crons as $ee_cron) { |
136 | - if (isset($cron[ $ee_cron ]) && is_array($cron[ $ee_cron ])) { |
|
136 | + if (isset($cron[$ee_cron]) && is_array($cron[$ee_cron])) { |
|
137 | 137 | do_action('AHEE_log', __CLASS__, __FUNCTION__, $ee_cron, 'scheduled EE cron'); |
138 | - foreach ($cron[ $ee_cron ] as $ee_cron_details) { |
|
139 | - if (! empty($ee_cron_details['args'])) { |
|
138 | + foreach ($cron[$ee_cron] as $ee_cron_details) { |
|
139 | + if ( ! empty($ee_cron_details['args'])) { |
|
140 | 140 | do_action( |
141 | 141 | 'AHEE_log', |
142 | 142 | __CLASS__, |
@@ -164,7 +164,7 @@ discard block |
||
164 | 164 | */ |
165 | 165 | public static function reschedule_cron_for_transactions_if_maintenance_mode($cron_task, array $TXN_IDs) |
166 | 166 | { |
167 | - if (! method_exists('EE_Cron_Tasks', $cron_task)) { |
|
167 | + if ( ! method_exists('EE_Cron_Tasks', $cron_task)) { |
|
168 | 168 | throw new DomainException( |
169 | 169 | sprintf( |
170 | 170 | __('"%1$s" is not valid method on EE_Cron_Tasks.', 'event_espresso'), |
@@ -173,7 +173,7 @@ discard block |
||
173 | 173 | ); |
174 | 174 | } |
175 | 175 | // reschedule the cron if we can't hit the db right now |
176 | - if (! EE_Maintenance_Mode::instance()->models_can_query()) { |
|
176 | + if ( ! EE_Maintenance_Mode::instance()->models_can_query()) { |
|
177 | 177 | foreach ($TXN_IDs as $TXN_ID => $additional_vars) { |
178 | 178 | // ensure $additional_vars is an array |
179 | 179 | $additional_vars = is_array($additional_vars) ? $additional_vars : array($additional_vars); |
@@ -255,7 +255,7 @@ discard block |
||
255 | 255 | { |
256 | 256 | do_action('AHEE_log', __CLASS__, __FUNCTION__, $TXN_ID, '$TXN_ID'); |
257 | 257 | if (absint($TXN_ID)) { |
258 | - self::$_update_transactions_with_payment[ $TXN_ID ] = $PAY_ID; |
|
258 | + self::$_update_transactions_with_payment[$TXN_ID] = $PAY_ID; |
|
259 | 259 | add_action( |
260 | 260 | 'shutdown', |
261 | 261 | array('EE_Cron_Tasks', 'update_transaction_with_payment'), |
@@ -302,7 +302,7 @@ discard block |
||
302 | 302 | EE_Registry::instance()->load_model('Transaction'); |
303 | 303 | foreach (self::$_update_transactions_with_payment as $TXN_ID => $PAY_ID) { |
304 | 304 | // reschedule the cron if we can't hit the db right now |
305 | - if (! EE_Maintenance_Mode::instance()->models_can_query()) { |
|
305 | + if ( ! EE_Maintenance_Mode::instance()->models_can_query()) { |
|
306 | 306 | // reset cron job for updating the TXN |
307 | 307 | EE_Cron_Tasks::schedule_update_transaction_with_payment( |
308 | 308 | time() + EE_Cron_Tasks::reschedule_timeout, |
@@ -318,7 +318,7 @@ discard block |
||
318 | 318 | // now try to update the TXN with any payments |
319 | 319 | $payment_processor->update_txn_based_on_payment($transaction, $payment, true, true); |
320 | 320 | } |
321 | - unset(self::$_update_transactions_with_payment[ $TXN_ID ]); |
|
321 | + unset(self::$_update_transactions_with_payment[$TXN_ID]); |
|
322 | 322 | } |
323 | 323 | } |
324 | 324 | |
@@ -383,7 +383,7 @@ discard block |
||
383 | 383 | public static function expired_transaction_check($TXN_ID = 0) |
384 | 384 | { |
385 | 385 | if (absint($TXN_ID)) { |
386 | - self::$_expired_transactions[ $TXN_ID ] = $TXN_ID; |
|
386 | + self::$_expired_transactions[$TXN_ID] = $TXN_ID; |
|
387 | 387 | add_action( |
388 | 388 | 'shutdown', |
389 | 389 | array('EE_Cron_Tasks', 'process_expired_transactions'), |
@@ -498,7 +498,7 @@ discard block |
||
498 | 498 | break; |
499 | 499 | } |
500 | 500 | } |
501 | - unset(self::$_expired_transactions[ $TXN_ID ]); |
|
501 | + unset(self::$_expired_transactions[$TXN_ID]); |
|
502 | 502 | } |
503 | 503 | } |
504 | 504 |
@@ -4,7 +4,7 @@ discard block |
||
4 | 4 | use EventEspresso\core\exceptions\InvalidInterfaceException; |
5 | 5 | |
6 | 6 | if ( ! defined('EVENT_ESPRESSO_VERSION')) { |
7 | - exit('No direct script access allowed'); |
|
7 | + exit('No direct script access allowed'); |
|
8 | 8 | } |
9 | 9 | require_once(EE_MODELS . 'EEM_Base.model.php'); |
10 | 10 | |
@@ -20,193 +20,193 @@ discard block |
||
20 | 20 | class EEM_Transaction extends EEM_Base |
21 | 21 | { |
22 | 22 | |
23 | - // private instance of the Transaction object |
|
24 | - protected static $_instance; |
|
25 | - |
|
26 | - /** |
|
27 | - * Status ID(STS_ID on esp_status table) to indicate the transaction is complete, |
|
28 | - * but payment is pending. This is the state for transactions where payment is promised |
|
29 | - * from an offline gateway. |
|
30 | - */ |
|
31 | - // const open_status_code = 'TPN'; |
|
32 | - |
|
33 | - /** |
|
34 | - * Status ID(STS_ID on esp_status table) to indicate the transaction failed, |
|
35 | - * either due to a technical reason (server or computer crash during registration), |
|
36 | - * or some other reason that prevent the collection of any useful contact information from any of the registrants |
|
37 | - */ |
|
38 | - const failed_status_code = 'TFL'; |
|
39 | - |
|
40 | - /** |
|
41 | - * Status ID(STS_ID on esp_status table) to indicate the transaction was abandoned, |
|
42 | - * either due to a technical reason (server or computer crash during registration), |
|
43 | - * or due to an abandoned cart after registrant chose not to complete the registration process |
|
44 | - * HOWEVER... |
|
45 | - * an abandoned TXN differs from a failed TXN in that it was able to capture contact information for at least one |
|
46 | - * registrant |
|
47 | - */ |
|
48 | - const abandoned_status_code = 'TAB'; |
|
49 | - |
|
50 | - /** |
|
51 | - * Status ID(STS_ID on esp_status table) to indicate an incomplete transaction, |
|
52 | - * meaning that monies are still owing: TXN_paid < TXN_total |
|
53 | - */ |
|
54 | - const incomplete_status_code = 'TIN'; |
|
55 | - |
|
56 | - /** |
|
57 | - * Status ID (STS_ID on esp_status table) to indicate a complete transaction. |
|
58 | - * meaning that NO monies are owing: TXN_paid == TXN_total |
|
59 | - */ |
|
60 | - const complete_status_code = 'TCM'; |
|
61 | - |
|
62 | - /** |
|
63 | - * Status ID(STS_ID on esp_status table) to indicate the transaction is overpaid. |
|
64 | - * This is the same as complete, but site admins actually owe clients the moneys! TXN_paid > TXN_total |
|
65 | - */ |
|
66 | - const overpaid_status_code = 'TOP'; |
|
67 | - |
|
68 | - |
|
69 | - /** |
|
70 | - * private constructor to prevent direct creation |
|
71 | - * |
|
72 | - * @Constructor |
|
73 | - * @access protected |
|
74 | - * |
|
75 | - * @param string $timezone string representing the timezone we want to set for returned Date Time Strings (and any |
|
76 | - * incoming timezone data that gets saved). Note this just sends the timezone info to the |
|
77 | - * date time model field objects. Default is NULL (and will be assumed using the set |
|
78 | - * timezone in the 'timezone_string' wp option) |
|
79 | - * |
|
80 | - * @return EEM_Transaction |
|
81 | - * @throws \EE_Error |
|
82 | - */ |
|
83 | - protected function __construct($timezone) |
|
84 | - { |
|
85 | - $this->singular_item = __('Transaction', 'event_espresso'); |
|
86 | - $this->plural_item = __('Transactions', 'event_espresso'); |
|
87 | - |
|
88 | - $this->_tables = array( |
|
89 | - 'TransactionTable' => new EE_Primary_Table('esp_transaction', 'TXN_ID') |
|
90 | - ); |
|
91 | - $this->_fields = array( |
|
92 | - 'TransactionTable' => array( |
|
93 | - 'TXN_ID' => new EE_Primary_Key_Int_Field('TXN_ID', __('Transaction ID', 'event_espresso')), |
|
94 | - 'TXN_timestamp' => new EE_Datetime_Field('TXN_timestamp', |
|
95 | - __('date when transaction was created', 'event_espresso'), false, EE_Datetime_Field::now, |
|
96 | - $timezone), |
|
97 | - 'TXN_total' => new EE_Money_Field('TXN_total', |
|
98 | - __('Total value of Transaction', 'event_espresso'), false, 0), |
|
99 | - 'TXN_paid' => new EE_Money_Field('TXN_paid', |
|
100 | - __('Amount paid towards transaction to date', 'event_espresso'), false, 0), |
|
101 | - 'STS_ID' => new EE_Foreign_Key_String_Field('STS_ID', __('Status ID', 'event_espresso'), |
|
102 | - false, EEM_Transaction::failed_status_code, 'Status'), |
|
103 | - 'TXN_session_data' => new EE_Serialized_Text_Field('TXN_session_data', |
|
104 | - __('Serialized session data', 'event_espresso'), true, ''), |
|
105 | - 'TXN_hash_salt' => new EE_Plain_Text_Field('TXN_hash_salt', |
|
106 | - __('Transaction Hash Salt', 'event_espresso'), true, ''), |
|
107 | - 'PMD_ID' => new EE_Foreign_Key_Int_Field('PMD_ID', |
|
108 | - __("Last Used Payment Method", 'event_espresso'), true, null, 'Payment_Method'), |
|
109 | - 'TXN_reg_steps' => new EE_Serialized_Text_Field('TXN_reg_steps', |
|
110 | - __('Registration Steps', 'event_espresso'), false, array()), |
|
111 | - ) |
|
112 | - ); |
|
113 | - $this->_model_relations = array( |
|
114 | - 'Registration' => new EE_Has_Many_Relation(), |
|
115 | - 'Payment' => new EE_Has_Many_Relation(), |
|
116 | - 'Status' => new EE_Belongs_To_Relation(), |
|
117 | - 'Line_Item' => new EE_Has_Many_Relation(false), |
|
118 | - //you can delete a transaction without needing to delete its line items |
|
119 | - 'Payment_Method' => new EE_Belongs_To_Relation(), |
|
120 | - 'Message' => new EE_Has_Many_Relation() |
|
121 | - ); |
|
122 | - $this->_model_chain_to_wp_user = 'Registration.Event'; |
|
123 | - parent::__construct($timezone); |
|
124 | - |
|
125 | - } |
|
126 | - |
|
127 | - |
|
128 | - /** |
|
129 | - * txn_status_array |
|
130 | - * get list of transaction statuses |
|
131 | - * |
|
132 | - * @access public |
|
133 | - * @return array |
|
134 | - */ |
|
135 | - public static function txn_status_array() |
|
136 | - { |
|
137 | - return apply_filters( |
|
138 | - 'FHEE__EEM_Transaction__txn_status_array', |
|
139 | - array( |
|
140 | - EEM_Transaction::overpaid_status_code, |
|
141 | - EEM_Transaction::complete_status_code, |
|
142 | - EEM_Transaction::incomplete_status_code, |
|
143 | - EEM_Transaction::abandoned_status_code, |
|
144 | - EEM_Transaction::failed_status_code, |
|
145 | - ) |
|
146 | - ); |
|
147 | - } |
|
148 | - |
|
149 | - /** |
|
150 | - * get the revenue per day for the Transaction Admin page Reports Tab |
|
151 | - * |
|
152 | - * @access public |
|
153 | - * |
|
154 | - * @param string $period |
|
155 | - * |
|
156 | - * @return \stdClass[] |
|
157 | - */ |
|
158 | - public function get_revenue_per_day_report($period = '-1 month') |
|
159 | - { |
|
160 | - $sql_date = $this->convert_datetime_for_query('TXN_timestamp', date('Y-m-d H:i:s', strtotime($period)), |
|
161 | - 'Y-m-d H:i:s', 'UTC'); |
|
162 | - |
|
163 | - $query_interval = EEH_DTT_Helper::get_sql_query_interval_for_offset($this->get_timezone(), 'TXN_timestamp'); |
|
164 | - |
|
165 | - return $this->_get_all_wpdb_results( |
|
166 | - array( |
|
167 | - array( |
|
168 | - 'TXN_timestamp' => array('>=', $sql_date) |
|
169 | - ), |
|
170 | - 'group_by' => 'txnDate', |
|
171 | - 'order_by' => array('TXN_timestamp' => 'ASC') |
|
172 | - ), |
|
173 | - OBJECT, |
|
174 | - array( |
|
175 | - 'txnDate' => array('DATE(' . $query_interval . ')', '%s'), |
|
176 | - 'revenue' => array('SUM(TransactionTable.TXN_paid)', '%d') |
|
177 | - ) |
|
178 | - ); |
|
179 | - } |
|
180 | - |
|
181 | - |
|
182 | - /** |
|
183 | - * get the revenue per event for the Transaction Admin page Reports Tab |
|
184 | - * |
|
185 | - * @access public |
|
186 | - * |
|
187 | - * @param string $period |
|
188 | - * |
|
189 | - * @throws \EE_Error |
|
190 | - * @return mixed |
|
191 | - */ |
|
192 | - public function get_revenue_per_event_report($period = '-1 month') |
|
193 | - { |
|
194 | - global $wpdb; |
|
195 | - $transaction_table = $wpdb->prefix . 'esp_transaction'; |
|
196 | - $registration_table = $wpdb->prefix . 'esp_registration'; |
|
197 | - $registration_payment_table = $wpdb->prefix . 'esp_registration_payment'; |
|
198 | - $event_table = $wpdb->posts; |
|
199 | - $payment_table = $wpdb->prefix . 'esp_payment'; |
|
200 | - $sql_date = date('Y-m-d H:i:s', strtotime($period)); |
|
201 | - $approved_payment_status = EEM_Payment::status_id_approved; |
|
202 | - $extra_event_on_join = ''; |
|
203 | - //exclude events not authored by user if permissions in effect |
|
204 | - if ( ! EE_Registry::instance()->CAP->current_user_can('ee_read_others_registrations', 'reg_per_event_report')) { |
|
205 | - $extra_event_on_join = ' AND Event.post_author = ' . get_current_user_id(); |
|
206 | - } |
|
207 | - |
|
208 | - return $wpdb->get_results( |
|
209 | - "SELECT |
|
23 | + // private instance of the Transaction object |
|
24 | + protected static $_instance; |
|
25 | + |
|
26 | + /** |
|
27 | + * Status ID(STS_ID on esp_status table) to indicate the transaction is complete, |
|
28 | + * but payment is pending. This is the state for transactions where payment is promised |
|
29 | + * from an offline gateway. |
|
30 | + */ |
|
31 | + // const open_status_code = 'TPN'; |
|
32 | + |
|
33 | + /** |
|
34 | + * Status ID(STS_ID on esp_status table) to indicate the transaction failed, |
|
35 | + * either due to a technical reason (server or computer crash during registration), |
|
36 | + * or some other reason that prevent the collection of any useful contact information from any of the registrants |
|
37 | + */ |
|
38 | + const failed_status_code = 'TFL'; |
|
39 | + |
|
40 | + /** |
|
41 | + * Status ID(STS_ID on esp_status table) to indicate the transaction was abandoned, |
|
42 | + * either due to a technical reason (server or computer crash during registration), |
|
43 | + * or due to an abandoned cart after registrant chose not to complete the registration process |
|
44 | + * HOWEVER... |
|
45 | + * an abandoned TXN differs from a failed TXN in that it was able to capture contact information for at least one |
|
46 | + * registrant |
|
47 | + */ |
|
48 | + const abandoned_status_code = 'TAB'; |
|
49 | + |
|
50 | + /** |
|
51 | + * Status ID(STS_ID on esp_status table) to indicate an incomplete transaction, |
|
52 | + * meaning that monies are still owing: TXN_paid < TXN_total |
|
53 | + */ |
|
54 | + const incomplete_status_code = 'TIN'; |
|
55 | + |
|
56 | + /** |
|
57 | + * Status ID (STS_ID on esp_status table) to indicate a complete transaction. |
|
58 | + * meaning that NO monies are owing: TXN_paid == TXN_total |
|
59 | + */ |
|
60 | + const complete_status_code = 'TCM'; |
|
61 | + |
|
62 | + /** |
|
63 | + * Status ID(STS_ID on esp_status table) to indicate the transaction is overpaid. |
|
64 | + * This is the same as complete, but site admins actually owe clients the moneys! TXN_paid > TXN_total |
|
65 | + */ |
|
66 | + const overpaid_status_code = 'TOP'; |
|
67 | + |
|
68 | + |
|
69 | + /** |
|
70 | + * private constructor to prevent direct creation |
|
71 | + * |
|
72 | + * @Constructor |
|
73 | + * @access protected |
|
74 | + * |
|
75 | + * @param string $timezone string representing the timezone we want to set for returned Date Time Strings (and any |
|
76 | + * incoming timezone data that gets saved). Note this just sends the timezone info to the |
|
77 | + * date time model field objects. Default is NULL (and will be assumed using the set |
|
78 | + * timezone in the 'timezone_string' wp option) |
|
79 | + * |
|
80 | + * @return EEM_Transaction |
|
81 | + * @throws \EE_Error |
|
82 | + */ |
|
83 | + protected function __construct($timezone) |
|
84 | + { |
|
85 | + $this->singular_item = __('Transaction', 'event_espresso'); |
|
86 | + $this->plural_item = __('Transactions', 'event_espresso'); |
|
87 | + |
|
88 | + $this->_tables = array( |
|
89 | + 'TransactionTable' => new EE_Primary_Table('esp_transaction', 'TXN_ID') |
|
90 | + ); |
|
91 | + $this->_fields = array( |
|
92 | + 'TransactionTable' => array( |
|
93 | + 'TXN_ID' => new EE_Primary_Key_Int_Field('TXN_ID', __('Transaction ID', 'event_espresso')), |
|
94 | + 'TXN_timestamp' => new EE_Datetime_Field('TXN_timestamp', |
|
95 | + __('date when transaction was created', 'event_espresso'), false, EE_Datetime_Field::now, |
|
96 | + $timezone), |
|
97 | + 'TXN_total' => new EE_Money_Field('TXN_total', |
|
98 | + __('Total value of Transaction', 'event_espresso'), false, 0), |
|
99 | + 'TXN_paid' => new EE_Money_Field('TXN_paid', |
|
100 | + __('Amount paid towards transaction to date', 'event_espresso'), false, 0), |
|
101 | + 'STS_ID' => new EE_Foreign_Key_String_Field('STS_ID', __('Status ID', 'event_espresso'), |
|
102 | + false, EEM_Transaction::failed_status_code, 'Status'), |
|
103 | + 'TXN_session_data' => new EE_Serialized_Text_Field('TXN_session_data', |
|
104 | + __('Serialized session data', 'event_espresso'), true, ''), |
|
105 | + 'TXN_hash_salt' => new EE_Plain_Text_Field('TXN_hash_salt', |
|
106 | + __('Transaction Hash Salt', 'event_espresso'), true, ''), |
|
107 | + 'PMD_ID' => new EE_Foreign_Key_Int_Field('PMD_ID', |
|
108 | + __("Last Used Payment Method", 'event_espresso'), true, null, 'Payment_Method'), |
|
109 | + 'TXN_reg_steps' => new EE_Serialized_Text_Field('TXN_reg_steps', |
|
110 | + __('Registration Steps', 'event_espresso'), false, array()), |
|
111 | + ) |
|
112 | + ); |
|
113 | + $this->_model_relations = array( |
|
114 | + 'Registration' => new EE_Has_Many_Relation(), |
|
115 | + 'Payment' => new EE_Has_Many_Relation(), |
|
116 | + 'Status' => new EE_Belongs_To_Relation(), |
|
117 | + 'Line_Item' => new EE_Has_Many_Relation(false), |
|
118 | + //you can delete a transaction without needing to delete its line items |
|
119 | + 'Payment_Method' => new EE_Belongs_To_Relation(), |
|
120 | + 'Message' => new EE_Has_Many_Relation() |
|
121 | + ); |
|
122 | + $this->_model_chain_to_wp_user = 'Registration.Event'; |
|
123 | + parent::__construct($timezone); |
|
124 | + |
|
125 | + } |
|
126 | + |
|
127 | + |
|
128 | + /** |
|
129 | + * txn_status_array |
|
130 | + * get list of transaction statuses |
|
131 | + * |
|
132 | + * @access public |
|
133 | + * @return array |
|
134 | + */ |
|
135 | + public static function txn_status_array() |
|
136 | + { |
|
137 | + return apply_filters( |
|
138 | + 'FHEE__EEM_Transaction__txn_status_array', |
|
139 | + array( |
|
140 | + EEM_Transaction::overpaid_status_code, |
|
141 | + EEM_Transaction::complete_status_code, |
|
142 | + EEM_Transaction::incomplete_status_code, |
|
143 | + EEM_Transaction::abandoned_status_code, |
|
144 | + EEM_Transaction::failed_status_code, |
|
145 | + ) |
|
146 | + ); |
|
147 | + } |
|
148 | + |
|
149 | + /** |
|
150 | + * get the revenue per day for the Transaction Admin page Reports Tab |
|
151 | + * |
|
152 | + * @access public |
|
153 | + * |
|
154 | + * @param string $period |
|
155 | + * |
|
156 | + * @return \stdClass[] |
|
157 | + */ |
|
158 | + public function get_revenue_per_day_report($period = '-1 month') |
|
159 | + { |
|
160 | + $sql_date = $this->convert_datetime_for_query('TXN_timestamp', date('Y-m-d H:i:s', strtotime($period)), |
|
161 | + 'Y-m-d H:i:s', 'UTC'); |
|
162 | + |
|
163 | + $query_interval = EEH_DTT_Helper::get_sql_query_interval_for_offset($this->get_timezone(), 'TXN_timestamp'); |
|
164 | + |
|
165 | + return $this->_get_all_wpdb_results( |
|
166 | + array( |
|
167 | + array( |
|
168 | + 'TXN_timestamp' => array('>=', $sql_date) |
|
169 | + ), |
|
170 | + 'group_by' => 'txnDate', |
|
171 | + 'order_by' => array('TXN_timestamp' => 'ASC') |
|
172 | + ), |
|
173 | + OBJECT, |
|
174 | + array( |
|
175 | + 'txnDate' => array('DATE(' . $query_interval . ')', '%s'), |
|
176 | + 'revenue' => array('SUM(TransactionTable.TXN_paid)', '%d') |
|
177 | + ) |
|
178 | + ); |
|
179 | + } |
|
180 | + |
|
181 | + |
|
182 | + /** |
|
183 | + * get the revenue per event for the Transaction Admin page Reports Tab |
|
184 | + * |
|
185 | + * @access public |
|
186 | + * |
|
187 | + * @param string $period |
|
188 | + * |
|
189 | + * @throws \EE_Error |
|
190 | + * @return mixed |
|
191 | + */ |
|
192 | + public function get_revenue_per_event_report($period = '-1 month') |
|
193 | + { |
|
194 | + global $wpdb; |
|
195 | + $transaction_table = $wpdb->prefix . 'esp_transaction'; |
|
196 | + $registration_table = $wpdb->prefix . 'esp_registration'; |
|
197 | + $registration_payment_table = $wpdb->prefix . 'esp_registration_payment'; |
|
198 | + $event_table = $wpdb->posts; |
|
199 | + $payment_table = $wpdb->prefix . 'esp_payment'; |
|
200 | + $sql_date = date('Y-m-d H:i:s', strtotime($period)); |
|
201 | + $approved_payment_status = EEM_Payment::status_id_approved; |
|
202 | + $extra_event_on_join = ''; |
|
203 | + //exclude events not authored by user if permissions in effect |
|
204 | + if ( ! EE_Registry::instance()->CAP->current_user_can('ee_read_others_registrations', 'reg_per_event_report')) { |
|
205 | + $extra_event_on_join = ' AND Event.post_author = ' . get_current_user_id(); |
|
206 | + } |
|
207 | + |
|
208 | + return $wpdb->get_results( |
|
209 | + "SELECT |
|
210 | 210 | Transaction_Event.event_name AS event_name, |
211 | 211 | SUM(Transaction_Event.paid) AS revenue |
212 | 212 | FROM |
@@ -234,223 +234,223 @@ discard block |
||
234 | 234 | $extra_event_on_join |
235 | 235 | ) AS Transaction_Event |
236 | 236 | GROUP BY event_name", |
237 | - OBJECT |
|
238 | - ); |
|
239 | - } |
|
240 | - |
|
241 | - |
|
242 | - /** |
|
243 | - * Gets the current transaction given the reg_url_link, or assumes the reg_url_link is in the |
|
244 | - * $_REQUEST global variable. Either way, tries to find the current transaction (through |
|
245 | - * the registration pointed to by reg_url_link), if not returns null |
|
246 | - * |
|
247 | - * @param string $reg_url_link |
|
248 | - * |
|
249 | - * @return EE_Transaction |
|
250 | - */ |
|
251 | - public function get_transaction_from_reg_url_link($reg_url_link = '') |
|
252 | - { |
|
253 | - return $this->get_one(array( |
|
254 | - array( |
|
255 | - 'Registration.REG_url_link' => ! empty($reg_url_link) ? $reg_url_link : EE_Registry::instance()->REQ->get('e_reg_url_link', |
|
256 | - '') |
|
257 | - ) |
|
258 | - )); |
|
259 | - } |
|
260 | - |
|
261 | - |
|
262 | - /** |
|
263 | - * Updates the provided EE_Transaction with all the applicable payments |
|
264 | - * (or fetch the EE_Transaction from its ID) |
|
265 | - * |
|
266 | - * @deprecated |
|
267 | - * |
|
268 | - * @param EE_Transaction|int $transaction_obj_or_id |
|
269 | - * @param boolean $save_txn whether or not to save the transaction during this function call |
|
270 | - * |
|
271 | - * @return boolean |
|
272 | - * @throws \EE_Error |
|
273 | - */ |
|
274 | - public function update_based_on_payments($transaction_obj_or_id, $save_txn = true) |
|
275 | - { |
|
276 | - EE_Error::doing_it_wrong( |
|
277 | - __CLASS__ . '::' . __FUNCTION__, |
|
278 | - sprintf(__('This method is deprecated. Please use "%s" instead', 'event_espresso'), |
|
279 | - 'EE_Transaction_Processor::update_transaction_and_registrations_after_checkout_or_payment()'), |
|
280 | - '4.6.0' |
|
281 | - ); |
|
282 | - /** @type EE_Transaction_Processor $transaction_processor */ |
|
283 | - $transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor'); |
|
284 | - |
|
285 | - return $transaction_processor->update_transaction_and_registrations_after_checkout_or_payment( |
|
286 | - $this->ensure_is_obj($transaction_obj_or_id) |
|
287 | - ); |
|
288 | - } |
|
289 | - |
|
290 | - /** |
|
291 | - * Deletes "junk" transactions that were probably added by bots. There might be TONS |
|
292 | - * of these, so we are very careful to NOT select (which the models do even when deleting), |
|
293 | - * and so we only use wpdb directly and only do minimal joins. |
|
294 | - * Transactions are considered "junk" if they're failed for longer than a week. |
|
295 | - * Also, there is an extra check for payments related to the transaction, because if a transaction has a payment on |
|
296 | - * it, it's probably not junk (regardless of what status it has). |
|
297 | - * The downside to this approach is that is addons are listening for object deletions |
|
298 | - * on EEM_Base::delete() they won't be notified of this. However, there is an action that plugins can hook into |
|
299 | - * to catch these types of deletions. |
|
300 | - * |
|
301 | - * @global WPDB $wpdb |
|
302 | - * @return mixed |
|
303 | - */ |
|
304 | - public function delete_junk_transactions() |
|
305 | - { |
|
306 | - /** @type WPDB $wpdb */ |
|
307 | - global $wpdb; |
|
308 | - $deleted = false; |
|
309 | - $time_to_leave_alone = apply_filters( |
|
310 | - 'FHEE__EEM_Transaction__delete_junk_transactions__time_to_leave_alone' |
|
311 | - , WEEK_IN_SECONDS |
|
312 | - ); |
|
313 | - |
|
314 | - |
|
315 | - /** |
|
316 | - * This allows code to filter the query arguments used for retrieving the transaction IDs to delete. |
|
317 | - * Useful for plugins that want to exclude transactions matching certain query parameters. |
|
318 | - * The query parameters should be in the format accepted by the EEM_Base model queries. |
|
319 | - */ |
|
320 | - $ids_query = apply_filters( |
|
321 | - 'FHEE__EEM_Transaction__delete_junk_transactions__initial_query_args', |
|
322 | - array( |
|
323 | - 0 => array( |
|
324 | - 'STS_ID' => EEM_Transaction::failed_status_code, |
|
325 | - 'Payment.PAY_ID' => array( 'IS NULL' ), |
|
326 | - 'TXN_timestamp' => array('<', time() - $time_to_leave_alone) |
|
327 | - ) |
|
328 | - ), |
|
329 | - $time_to_leave_alone |
|
330 | - ); |
|
331 | - |
|
332 | - |
|
333 | - /** |
|
334 | - * This filter is for when code needs to filter the list of transaction ids that represent transactions |
|
335 | - * about to be deleted based on some other criteria that isn't easily done via the query args filter. |
|
336 | - */ |
|
337 | - $txn_ids = apply_filters( |
|
338 | - 'FHEE__EEM_Transaction__delete_junk_transactions__transaction_ids_to_delete', |
|
339 | - EEM_Transaction::instance()->get_col($ids_query, 'TXN_ID'), |
|
340 | - $time_to_leave_alone |
|
341 | - ); |
|
342 | - //now that we have the ids to delete |
|
343 | - if (! empty($txn_ids) && is_array($txn_ids)) { |
|
344 | - // first, make sure these TXN's are removed the "ee_locked_transactions" array |
|
345 | - EEM_Transaction::unset_locked_transactions($txn_ids); |
|
346 | - // let's get deletin'... |
|
347 | - // Why no wpdb->prepare? Because the data is trusted. |
|
348 | - // We got the ids from the original query to get them FROM |
|
349 | - // the db (which is sanitized) so no need to prepare them again. |
|
350 | - $query = ' |
|
237 | + OBJECT |
|
238 | + ); |
|
239 | + } |
|
240 | + |
|
241 | + |
|
242 | + /** |
|
243 | + * Gets the current transaction given the reg_url_link, or assumes the reg_url_link is in the |
|
244 | + * $_REQUEST global variable. Either way, tries to find the current transaction (through |
|
245 | + * the registration pointed to by reg_url_link), if not returns null |
|
246 | + * |
|
247 | + * @param string $reg_url_link |
|
248 | + * |
|
249 | + * @return EE_Transaction |
|
250 | + */ |
|
251 | + public function get_transaction_from_reg_url_link($reg_url_link = '') |
|
252 | + { |
|
253 | + return $this->get_one(array( |
|
254 | + array( |
|
255 | + 'Registration.REG_url_link' => ! empty($reg_url_link) ? $reg_url_link : EE_Registry::instance()->REQ->get('e_reg_url_link', |
|
256 | + '') |
|
257 | + ) |
|
258 | + )); |
|
259 | + } |
|
260 | + |
|
261 | + |
|
262 | + /** |
|
263 | + * Updates the provided EE_Transaction with all the applicable payments |
|
264 | + * (or fetch the EE_Transaction from its ID) |
|
265 | + * |
|
266 | + * @deprecated |
|
267 | + * |
|
268 | + * @param EE_Transaction|int $transaction_obj_or_id |
|
269 | + * @param boolean $save_txn whether or not to save the transaction during this function call |
|
270 | + * |
|
271 | + * @return boolean |
|
272 | + * @throws \EE_Error |
|
273 | + */ |
|
274 | + public function update_based_on_payments($transaction_obj_or_id, $save_txn = true) |
|
275 | + { |
|
276 | + EE_Error::doing_it_wrong( |
|
277 | + __CLASS__ . '::' . __FUNCTION__, |
|
278 | + sprintf(__('This method is deprecated. Please use "%s" instead', 'event_espresso'), |
|
279 | + 'EE_Transaction_Processor::update_transaction_and_registrations_after_checkout_or_payment()'), |
|
280 | + '4.6.0' |
|
281 | + ); |
|
282 | + /** @type EE_Transaction_Processor $transaction_processor */ |
|
283 | + $transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor'); |
|
284 | + |
|
285 | + return $transaction_processor->update_transaction_and_registrations_after_checkout_or_payment( |
|
286 | + $this->ensure_is_obj($transaction_obj_or_id) |
|
287 | + ); |
|
288 | + } |
|
289 | + |
|
290 | + /** |
|
291 | + * Deletes "junk" transactions that were probably added by bots. There might be TONS |
|
292 | + * of these, so we are very careful to NOT select (which the models do even when deleting), |
|
293 | + * and so we only use wpdb directly and only do minimal joins. |
|
294 | + * Transactions are considered "junk" if they're failed for longer than a week. |
|
295 | + * Also, there is an extra check for payments related to the transaction, because if a transaction has a payment on |
|
296 | + * it, it's probably not junk (regardless of what status it has). |
|
297 | + * The downside to this approach is that is addons are listening for object deletions |
|
298 | + * on EEM_Base::delete() they won't be notified of this. However, there is an action that plugins can hook into |
|
299 | + * to catch these types of deletions. |
|
300 | + * |
|
301 | + * @global WPDB $wpdb |
|
302 | + * @return mixed |
|
303 | + */ |
|
304 | + public function delete_junk_transactions() |
|
305 | + { |
|
306 | + /** @type WPDB $wpdb */ |
|
307 | + global $wpdb; |
|
308 | + $deleted = false; |
|
309 | + $time_to_leave_alone = apply_filters( |
|
310 | + 'FHEE__EEM_Transaction__delete_junk_transactions__time_to_leave_alone' |
|
311 | + , WEEK_IN_SECONDS |
|
312 | + ); |
|
313 | + |
|
314 | + |
|
315 | + /** |
|
316 | + * This allows code to filter the query arguments used for retrieving the transaction IDs to delete. |
|
317 | + * Useful for plugins that want to exclude transactions matching certain query parameters. |
|
318 | + * The query parameters should be in the format accepted by the EEM_Base model queries. |
|
319 | + */ |
|
320 | + $ids_query = apply_filters( |
|
321 | + 'FHEE__EEM_Transaction__delete_junk_transactions__initial_query_args', |
|
322 | + array( |
|
323 | + 0 => array( |
|
324 | + 'STS_ID' => EEM_Transaction::failed_status_code, |
|
325 | + 'Payment.PAY_ID' => array( 'IS NULL' ), |
|
326 | + 'TXN_timestamp' => array('<', time() - $time_to_leave_alone) |
|
327 | + ) |
|
328 | + ), |
|
329 | + $time_to_leave_alone |
|
330 | + ); |
|
331 | + |
|
332 | + |
|
333 | + /** |
|
334 | + * This filter is for when code needs to filter the list of transaction ids that represent transactions |
|
335 | + * about to be deleted based on some other criteria that isn't easily done via the query args filter. |
|
336 | + */ |
|
337 | + $txn_ids = apply_filters( |
|
338 | + 'FHEE__EEM_Transaction__delete_junk_transactions__transaction_ids_to_delete', |
|
339 | + EEM_Transaction::instance()->get_col($ids_query, 'TXN_ID'), |
|
340 | + $time_to_leave_alone |
|
341 | + ); |
|
342 | + //now that we have the ids to delete |
|
343 | + if (! empty($txn_ids) && is_array($txn_ids)) { |
|
344 | + // first, make sure these TXN's are removed the "ee_locked_transactions" array |
|
345 | + EEM_Transaction::unset_locked_transactions($txn_ids); |
|
346 | + // let's get deletin'... |
|
347 | + // Why no wpdb->prepare? Because the data is trusted. |
|
348 | + // We got the ids from the original query to get them FROM |
|
349 | + // the db (which is sanitized) so no need to prepare them again. |
|
350 | + $query = ' |
|
351 | 351 | DELETE |
352 | 352 | FROM ' . $this->table() . ' |
353 | 353 | WHERE |
354 | 354 | TXN_ID IN ( ' . implode(",", $txn_ids) . ')'; |
355 | - $deleted = $wpdb->query($query); |
|
356 | - } |
|
357 | - if ($deleted) { |
|
358 | - /** |
|
359 | - * Allows code to do something after the transactions have been deleted. |
|
360 | - */ |
|
361 | - do_action('AHEE__EEM_Transaction__delete_junk_transactions__successful_deletion', $txn_ids); |
|
362 | - } |
|
363 | - |
|
364 | - return $deleted; |
|
365 | - } |
|
366 | - |
|
367 | - |
|
368 | - /** |
|
369 | - * @param array $transaction_IDs |
|
370 | - * |
|
371 | - * @return bool |
|
372 | - */ |
|
373 | - public static function unset_locked_transactions(array $transaction_IDs) |
|
374 | - { |
|
375 | - $locked_transactions = get_option('ee_locked_transactions', array()); |
|
376 | - $update = false; |
|
377 | - foreach ($transaction_IDs as $TXN_ID) { |
|
378 | - if (isset($locked_transactions[$TXN_ID])) { |
|
379 | - unset($locked_transactions[$TXN_ID]); |
|
380 | - $update = true; |
|
381 | - } |
|
382 | - } |
|
383 | - if ($update) { |
|
384 | - update_option('ee_locked_transactions', $locked_transactions); |
|
385 | - } |
|
386 | - |
|
387 | - return $update; |
|
388 | - } |
|
389 | - |
|
390 | - |
|
391 | - |
|
392 | - /** |
|
393 | - * returns an array of EE_Transaction objects whose timestamp is greater than |
|
394 | - * the current time minus the session lifespan, which defaults to 60 minutes |
|
395 | - * |
|
396 | - * @return EE_Base_Class[]|EE_Transaction[] |
|
397 | - * @throws EE_Error |
|
398 | - * @throws InvalidArgumentException |
|
399 | - * @throws InvalidDataTypeException |
|
400 | - * @throws InvalidInterfaceException |
|
401 | - */ |
|
402 | - public function get_transactions_in_progress() |
|
403 | - { |
|
404 | - return $this->_get_transactions_in_progress(); |
|
405 | - } |
|
406 | - |
|
407 | - |
|
408 | - |
|
409 | - /** |
|
410 | - * returns an array of EE_Transaction objects whose timestamp is less than |
|
411 | - * the current time minus the session lifespan, which defaults to 60 minutes |
|
412 | - * |
|
413 | - * @return EE_Base_Class[]|EE_Transaction[] |
|
414 | - * @throws EE_Error |
|
415 | - * @throws InvalidArgumentException |
|
416 | - * @throws InvalidDataTypeException |
|
417 | - * @throws InvalidInterfaceException |
|
418 | - */ |
|
419 | - public function get_transactions_not_in_progress() |
|
420 | - { |
|
421 | - return $this->_get_transactions_in_progress('<='); |
|
422 | - } |
|
423 | - |
|
424 | - |
|
425 | - |
|
426 | - /** |
|
427 | - * @param string $comparison |
|
428 | - * @return EE_Base_Class[]|EE_Transaction[] |
|
429 | - * @throws EE_Error |
|
430 | - * @throws InvalidArgumentException |
|
431 | - * @throws InvalidDataTypeException |
|
432 | - * @throws InvalidInterfaceException |
|
433 | - */ |
|
434 | - private function _get_transactions_in_progress($comparison = '>=') |
|
435 | - { |
|
436 | - $comparison = $comparison === '>=' || $comparison === '<=' |
|
437 | - ? $comparison |
|
438 | - : '>='; |
|
439 | - return $this->get_all( |
|
440 | - array( |
|
441 | - array( |
|
442 | - 'TXN_timestamp' => array( |
|
443 | - $comparison, |
|
444 | - time() - EE_Registry::instance()->SSN->lifespan() |
|
445 | - ), |
|
446 | - 'STS_ID' => array( |
|
447 | - '!=', |
|
448 | - EEM_Transaction::complete_status_code |
|
449 | - ), |
|
450 | - ) |
|
451 | - ) |
|
452 | - ); |
|
453 | - } |
|
355 | + $deleted = $wpdb->query($query); |
|
356 | + } |
|
357 | + if ($deleted) { |
|
358 | + /** |
|
359 | + * Allows code to do something after the transactions have been deleted. |
|
360 | + */ |
|
361 | + do_action('AHEE__EEM_Transaction__delete_junk_transactions__successful_deletion', $txn_ids); |
|
362 | + } |
|
363 | + |
|
364 | + return $deleted; |
|
365 | + } |
|
366 | + |
|
367 | + |
|
368 | + /** |
|
369 | + * @param array $transaction_IDs |
|
370 | + * |
|
371 | + * @return bool |
|
372 | + */ |
|
373 | + public static function unset_locked_transactions(array $transaction_IDs) |
|
374 | + { |
|
375 | + $locked_transactions = get_option('ee_locked_transactions', array()); |
|
376 | + $update = false; |
|
377 | + foreach ($transaction_IDs as $TXN_ID) { |
|
378 | + if (isset($locked_transactions[$TXN_ID])) { |
|
379 | + unset($locked_transactions[$TXN_ID]); |
|
380 | + $update = true; |
|
381 | + } |
|
382 | + } |
|
383 | + if ($update) { |
|
384 | + update_option('ee_locked_transactions', $locked_transactions); |
|
385 | + } |
|
386 | + |
|
387 | + return $update; |
|
388 | + } |
|
389 | + |
|
390 | + |
|
391 | + |
|
392 | + /** |
|
393 | + * returns an array of EE_Transaction objects whose timestamp is greater than |
|
394 | + * the current time minus the session lifespan, which defaults to 60 minutes |
|
395 | + * |
|
396 | + * @return EE_Base_Class[]|EE_Transaction[] |
|
397 | + * @throws EE_Error |
|
398 | + * @throws InvalidArgumentException |
|
399 | + * @throws InvalidDataTypeException |
|
400 | + * @throws InvalidInterfaceException |
|
401 | + */ |
|
402 | + public function get_transactions_in_progress() |
|
403 | + { |
|
404 | + return $this->_get_transactions_in_progress(); |
|
405 | + } |
|
406 | + |
|
407 | + |
|
408 | + |
|
409 | + /** |
|
410 | + * returns an array of EE_Transaction objects whose timestamp is less than |
|
411 | + * the current time minus the session lifespan, which defaults to 60 minutes |
|
412 | + * |
|
413 | + * @return EE_Base_Class[]|EE_Transaction[] |
|
414 | + * @throws EE_Error |
|
415 | + * @throws InvalidArgumentException |
|
416 | + * @throws InvalidDataTypeException |
|
417 | + * @throws InvalidInterfaceException |
|
418 | + */ |
|
419 | + public function get_transactions_not_in_progress() |
|
420 | + { |
|
421 | + return $this->_get_transactions_in_progress('<='); |
|
422 | + } |
|
423 | + |
|
424 | + |
|
425 | + |
|
426 | + /** |
|
427 | + * @param string $comparison |
|
428 | + * @return EE_Base_Class[]|EE_Transaction[] |
|
429 | + * @throws EE_Error |
|
430 | + * @throws InvalidArgumentException |
|
431 | + * @throws InvalidDataTypeException |
|
432 | + * @throws InvalidInterfaceException |
|
433 | + */ |
|
434 | + private function _get_transactions_in_progress($comparison = '>=') |
|
435 | + { |
|
436 | + $comparison = $comparison === '>=' || $comparison === '<=' |
|
437 | + ? $comparison |
|
438 | + : '>='; |
|
439 | + return $this->get_all( |
|
440 | + array( |
|
441 | + array( |
|
442 | + 'TXN_timestamp' => array( |
|
443 | + $comparison, |
|
444 | + time() - EE_Registry::instance()->SSN->lifespan() |
|
445 | + ), |
|
446 | + 'STS_ID' => array( |
|
447 | + '!=', |
|
448 | + EEM_Transaction::complete_status_code |
|
449 | + ), |
|
450 | + ) |
|
451 | + ) |
|
452 | + ); |
|
453 | + } |
|
454 | 454 | |
455 | 455 | |
456 | 456 | } |
@@ -31,8 +31,8 @@ discard block |
||
31 | 31 | */ |
32 | 32 | public function __construct() { |
33 | 33 | parent::__construct( |
34 | - __( 'Event Espresso Upcoming Events', 'event_espresso' ), |
|
35 | - array( 'description' => __( 'A widget to display your upcoming events.', 'event_espresso' )) |
|
34 | + __('Event Espresso Upcoming Events', 'event_espresso'), |
|
35 | + array('description' => __('A widget to display your upcoming events.', 'event_espresso')) |
|
36 | 36 | ); |
37 | 37 | } |
38 | 38 | |
@@ -45,9 +45,9 @@ discard block |
||
45 | 45 | * @param array $instance Previously saved values from database. |
46 | 46 | * @return string|void |
47 | 47 | */ |
48 | - public function form( $instance ) { |
|
48 | + public function form($instance) { |
|
49 | 49 | |
50 | - EE_Registry::instance()->load_class( 'Question_Option', array(), FALSE, FALSE, TRUE ); |
|
50 | + EE_Registry::instance()->load_class('Question_Option', array(), FALSE, FALSE, TRUE); |
|
51 | 51 | // Set up some default widget settings. |
52 | 52 | $defaults = array( |
53 | 53 | 'title' => __('Upcoming Events', 'event_espresso'), |
@@ -63,16 +63,16 @@ discard block |
||
63 | 63 | 'image_size' => 'medium' |
64 | 64 | ); |
65 | 65 | |
66 | - $instance = wp_parse_args( (array) $instance, $defaults ); |
|
66 | + $instance = wp_parse_args((array) $instance, $defaults); |
|
67 | 67 | // don't add HTML labels for EE_Form_Fields generated inputs |
68 | - add_filter( 'FHEE__EEH_Form_Fields__label_html', '__return_empty_string' ); |
|
68 | + add_filter('FHEE__EEH_Form_Fields__label_html', '__return_empty_string'); |
|
69 | 69 | $yes_no_values = array( |
70 | - EE_Question_Option::new_instance( array( 'QSO_value' => FALSE, 'QSO_desc' => __('No', 'event_espresso'))), |
|
71 | - EE_Question_Option::new_instance( array( 'QSO_value' => TRUE, 'QSO_desc' => __('Yes', 'event_espresso'))) |
|
70 | + EE_Question_Option::new_instance(array('QSO_value' => FALSE, 'QSO_desc' => __('No', 'event_espresso'))), |
|
71 | + EE_Question_Option::new_instance(array('QSO_value' => TRUE, 'QSO_desc' => __('Yes', 'event_espresso'))) |
|
72 | 72 | ); |
73 | 73 | $sort_values = array( |
74 | - EE_Question_Option::new_instance( array( 'QSO_value' => 'ASC', 'QSO_desc' => __('ASC', 'event_espresso'))), |
|
75 | - EE_Question_Option::new_instance( array( 'QSO_value' => 'DESC', 'QSO_desc' => __('DESC', 'event_espresso'))) |
|
74 | + EE_Question_Option::new_instance(array('QSO_value' => 'ASC', 'QSO_desc' => __('ASC', 'event_espresso'))), |
|
75 | + EE_Question_Option::new_instance(array('QSO_value' => 'DESC', 'QSO_desc' => __('DESC', 'event_espresso'))) |
|
76 | 76 | ); |
77 | 77 | |
78 | 78 | ?> |
@@ -83,7 +83,7 @@ discard block |
||
83 | 83 | <label for="<?php echo $this->get_field_id('title'); ?>"> |
84 | 84 | <?php _e('Title:', 'event_espresso'); ?> |
85 | 85 | </label> |
86 | - <input id="<?php echo $this->get_field_id('title'); ?>" class="widefat" name="<?php echo $this->get_field_name('title'); ?>" value="<?php echo esc_attr( $instance['title'] ); ?>" type="text" /> |
|
86 | + <input id="<?php echo $this->get_field_id('title'); ?>" class="widefat" name="<?php echo $this->get_field_name('title'); ?>" value="<?php echo esc_attr($instance['title']); ?>" type="text" /> |
|
87 | 87 | </p> |
88 | 88 | <p> |
89 | 89 | <label for="<?php echo $this->get_field_id('category_name'); ?>"> |
@@ -92,16 +92,16 @@ discard block |
||
92 | 92 | <?php |
93 | 93 | $event_categories = array(); |
94 | 94 | /** @type EEM_Term $EEM_Term */ |
95 | - $EEM_Term = EE_Registry::instance()->load_model( 'Term' ); |
|
96 | - $categories = $EEM_Term->get_all_ee_categories( TRUE ); |
|
97 | - if ( $categories ) { |
|
98 | - foreach ( $categories as $category ) { |
|
99 | - if ( $category instanceof EE_Term ) { |
|
100 | - $event_categories[] = EE_Question_Option::new_instance( array( 'QSO_value' => $category->get( 'slug' ), 'QSO_desc' => $category->get( 'name' ))); |
|
95 | + $EEM_Term = EE_Registry::instance()->load_model('Term'); |
|
96 | + $categories = $EEM_Term->get_all_ee_categories(TRUE); |
|
97 | + if ($categories) { |
|
98 | + foreach ($categories as $category) { |
|
99 | + if ($category instanceof EE_Term) { |
|
100 | + $event_categories[] = EE_Question_Option::new_instance(array('QSO_value' => $category->get('slug'), 'QSO_desc' => $category->get('name'))); |
|
101 | 101 | } |
102 | 102 | } |
103 | 103 | } |
104 | - array_unshift( $event_categories, EE_Question_Option::new_instance( array( 'QSO_value' => '', 'QSO_desc' => __(' - display all - ', 'event_espresso')))); |
|
104 | + array_unshift($event_categories, EE_Question_Option::new_instance(array('QSO_value' => '', 'QSO_desc' => __(' - display all - ', 'event_espresso')))); |
|
105 | 105 | echo EEH_Form_Fields::select( |
106 | 106 | __('Event Category:', 'event_espresso'), |
107 | 107 | $instance['category_name'], |
@@ -126,9 +126,9 @@ discard block |
||
126 | 126 | __('Show Expired Events:', 'event_espresso'), |
127 | 127 | $instance['show_expired'], |
128 | 128 | array( |
129 | - EE_Question_Option::new_instance( array( 'QSO_value' => 0, 'QSO_desc' => __('No', 'event_espresso'))), |
|
130 | - EE_Question_Option::new_instance( array( 'QSO_value' => 1, 'QSO_desc' => __('Yes', 'event_espresso'))), |
|
131 | - EE_Question_Option::new_instance( array( 'QSO_value' => 2, 'QSO_desc' => __('Show Only Expired', 'event_espresso'))), |
|
129 | + EE_Question_Option::new_instance(array('QSO_value' => 0, 'QSO_desc' => __('No', 'event_espresso'))), |
|
130 | + EE_Question_Option::new_instance(array('QSO_value' => 1, 'QSO_desc' => __('Yes', 'event_espresso'))), |
|
131 | + EE_Question_Option::new_instance(array('QSO_value' => 2, 'QSO_desc' => __('Show Only Expired', 'event_espresso'))), |
|
132 | 132 | ), |
133 | 133 | $this->get_field_name('show_expired'), |
134 | 134 | $this->get_field_id('show_expired') |
@@ -156,16 +156,16 @@ discard block |
||
156 | 156 | <?php |
157 | 157 | $image_sizes = array(); |
158 | 158 | $sizes = get_intermediate_image_sizes(); |
159 | - if ( $sizes ) { |
|
159 | + if ($sizes) { |
|
160 | 160 | // loop thru images and create option objects out of them |
161 | - foreach ( $sizes as $image_size ) { |
|
162 | - $image_size = trim( $image_size ); |
|
161 | + foreach ($sizes as $image_size) { |
|
162 | + $image_size = trim($image_size); |
|
163 | 163 | // no big images plz |
164 | - if ( ! in_array( $image_size, array( 'large', 'post-thumbnail' ))) { |
|
165 | - $image_sizes[] = EE_Question_Option::new_instance( array( 'QSO_value' => $image_size, 'QSO_desc' => $image_size )); |
|
164 | + if ( ! in_array($image_size, array('large', 'post-thumbnail'))) { |
|
165 | + $image_sizes[] = EE_Question_Option::new_instance(array('QSO_value' => $image_size, 'QSO_desc' => $image_size)); |
|
166 | 166 | } |
167 | 167 | } |
168 | - $image_sizes[] = EE_Question_Option::new_instance( array( 'QSO_value' => 'none', 'QSO_desc' => __('don\'t show images', 'event_espresso') )); |
|
168 | + $image_sizes[] = EE_Question_Option::new_instance(array('QSO_value' => 'none', 'QSO_desc' => __('don\'t show images', 'event_espresso'))); |
|
169 | 169 | } |
170 | 170 | echo EEH_Form_Fields::select( |
171 | 171 | __('Image Size:', 'event_espresso'), |
@@ -223,7 +223,7 @@ discard block |
||
223 | 223 | <label for="<?php echo $this->get_field_id('date_limit'); ?>"> |
224 | 224 | <?php _e('Number of Dates to Display:', 'event_espresso'); ?> |
225 | 225 | </label> |
226 | - <input id="<?php echo $this->get_field_id('date_limit'); ?>" name="<?php echo $this->get_field_name('date_limit'); ?>" value="<?php echo esc_attr( $instance['date_limit'] ); ?>" size="3" type="text" /> |
|
226 | + <input id="<?php echo $this->get_field_id('date_limit'); ?>" name="<?php echo $this->get_field_name('date_limit'); ?>" value="<?php echo esc_attr($instance['date_limit']); ?>" size="3" type="text" /> |
|
227 | 227 | </p> |
228 | 228 | <p> |
229 | 229 | <label for="<?php echo $this->get_field_id('date_range'); ?>"> |
@@ -255,9 +255,9 @@ discard block |
||
255 | 255 | * |
256 | 256 | * @return array Updated safe values to be saved. |
257 | 257 | */ |
258 | - public function update( $new_instance, $old_instance ) { |
|
258 | + public function update($new_instance, $old_instance) { |
|
259 | 259 | $instance = $old_instance; |
260 | - $instance['title'] = ! empty( $new_instance['title'] ) ? strip_tags( $new_instance['title'] ) : ''; |
|
260 | + $instance['title'] = ! empty($new_instance['title']) ? strip_tags($new_instance['title']) : ''; |
|
261 | 261 | $instance['category_name'] = $new_instance['category_name']; |
262 | 262 | $instance['show_expired'] = $new_instance['show_expired']; |
263 | 263 | $instance['limit'] = $new_instance['limit']; |
@@ -281,18 +281,18 @@ discard block |
||
281 | 281 | * @param array $args Widget arguments. |
282 | 282 | * @param array $instance Saved values from database. |
283 | 283 | */ |
284 | - public function widget( $args, $instance ) { |
|
284 | + public function widget($args, $instance) { |
|
285 | 285 | |
286 | 286 | global $post; |
287 | 287 | // make sure there is some kinda post object |
288 | - if ( $post instanceof WP_Post ) { |
|
288 | + if ($post instanceof WP_Post) { |
|
289 | 289 | $before_widget = ''; |
290 | 290 | $before_title = ''; |
291 | 291 | $after_title = ''; |
292 | 292 | $after_widget = ''; |
293 | 293 | // but NOT an events archives page, cuz that would be like two event lists on the same page |
294 | - $show_everywhere = isset( $instance['show_everywhere'] ) ? (bool) absint( $instance['show_everywhere'] ) : TRUE; |
|
295 | - if ( $show_everywhere || ! ( $post->post_type == 'espresso_events' && is_archive() )) { |
|
294 | + $show_everywhere = isset($instance['show_everywhere']) ? (bool) absint($instance['show_everywhere']) : TRUE; |
|
295 | + if ($show_everywhere || ! ($post->post_type == 'espresso_events' && is_archive())) { |
|
296 | 296 | // let's use some of the event helper functions' |
297 | 297 | // make separate vars out of attributes |
298 | 298 | |
@@ -311,88 +311,88 @@ discard block |
||
311 | 311 | // Before widget (defined by themes). |
312 | 312 | echo $before_widget; |
313 | 313 | // Display the widget title if one was input (before and after defined by themes). |
314 | - if ( ! empty( $title )) { |
|
315 | - echo $before_title . $title . $after_title; |
|
314 | + if ( ! empty($title)) { |
|
315 | + echo $before_title.$title.$after_title; |
|
316 | 316 | } |
317 | 317 | // grab widget settings |
318 | - $category = isset( $instance['category_name'] ) && ! empty( $instance['category_name'] ) ? $instance['category_name'] : FALSE; |
|
319 | - $show_expired = isset( $instance['show_expired'] ) ? absint( $instance['show_expired'] ) : 0; |
|
320 | - $image_size = isset( $instance['image_size'] ) && ! empty( $instance['image_size'] ) ? $instance['image_size'] : 'medium'; |
|
321 | - $show_desc = isset( $instance['show_desc'] ) ? (bool) absint( $instance['show_desc'] ) : TRUE; |
|
322 | - $show_dates = isset( $instance['show_dates'] ) ? (bool) absint( $instance['show_dates'] ) : TRUE; |
|
323 | - $date_limit = isset( $instance['date_limit'] ) && ! empty( $instance['date_limit'] ) ? $instance['date_limit'] : NULL; |
|
324 | - $date_range = isset( $instance['date_range'] ) && ! empty( $instance['date_range'] ) ? $instance['date_range'] : FALSE; |
|
318 | + $category = isset($instance['category_name']) && ! empty($instance['category_name']) ? $instance['category_name'] : FALSE; |
|
319 | + $show_expired = isset($instance['show_expired']) ? absint($instance['show_expired']) : 0; |
|
320 | + $image_size = isset($instance['image_size']) && ! empty($instance['image_size']) ? $instance['image_size'] : 'medium'; |
|
321 | + $show_desc = isset($instance['show_desc']) ? (bool) absint($instance['show_desc']) : TRUE; |
|
322 | + $show_dates = isset($instance['show_dates']) ? (bool) absint($instance['show_dates']) : TRUE; |
|
323 | + $date_limit = isset($instance['date_limit']) && ! empty($instance['date_limit']) ? $instance['date_limit'] : NULL; |
|
324 | + $date_range = isset($instance['date_range']) && ! empty($instance['date_range']) ? $instance['date_range'] : FALSE; |
|
325 | 325 | // start to build our where clause |
326 | 326 | $where = array( |
327 | 327 | // 'Datetime.DTT_is_primary' => 1, |
328 | - 'status' => array( 'IN', array( 'publish', 'sold_out' ) ) |
|
328 | + 'status' => array('IN', array('publish', 'sold_out')) |
|
329 | 329 | ); |
330 | 330 | // add category |
331 | - if ( $category ) { |
|
331 | + if ($category) { |
|
332 | 332 | $where['Term_Taxonomy.taxonomy'] = 'espresso_event_categories'; |
333 | 333 | $where['Term_Taxonomy.Term.slug'] = $category; |
334 | 334 | } |
335 | 335 | // if NOT expired then we want events that start today or in the future |
336 | 336 | // if NOT show expired then we want events that start today or in the future |
337 | - if ( $show_expired == 0 ) { |
|
338 | - $where['Datetime.DTT_EVT_end'] = array( '>=', EEM_Datetime::instance()->current_time_for_query( 'DTT_EVT_end' ) ); |
|
337 | + if ($show_expired == 0) { |
|
338 | + $where['Datetime.DTT_EVT_end'] = array('>=', EEM_Datetime::instance()->current_time_for_query('DTT_EVT_end')); |
|
339 | 339 | } |
340 | 340 | // if show ONLY expired we want events that ended prior to today |
341 | - if ( $show_expired == 2 ) { |
|
342 | - $where['Datetime.DTT_EVT_end'] = array( '<=', EEM_Datetime::instance()->current_time_for_query( 'DTT_EVT_start' ) ); |
|
341 | + if ($show_expired == 2) { |
|
342 | + $where['Datetime.DTT_EVT_end'] = array('<=', EEM_Datetime::instance()->current_time_for_query('DTT_EVT_start')); |
|
343 | 343 | } |
344 | 344 | // allow $where to be filtered |
345 | - $where = apply_filters( 'FHEE__EEW_Upcoming_Events__widget__where', $where, $category, $show_expired ); |
|
345 | + $where = apply_filters('FHEE__EEW_Upcoming_Events__widget__where', $where, $category, $show_expired); |
|
346 | 346 | // run the query |
347 | - $events = EE_Registry::instance()->load_model( 'Event' )->get_all( array( |
|
347 | + $events = EE_Registry::instance()->load_model('Event')->get_all(array( |
|
348 | 348 | $where, |
349 | - 'limit' => $instance['limit'] > 0 ? '0,' . $instance['limit'] : '0,10', |
|
349 | + 'limit' => $instance['limit'] > 0 ? '0,'.$instance['limit'] : '0,10', |
|
350 | 350 | 'order_by' => 'Datetime.DTT_EVT_start', |
351 | 351 | 'order' => isset($instance['sort']) ? $instance['sort'] : 'ASC', |
352 | 352 | 'group_by' => 'EVT_ID' |
353 | 353 | )); |
354 | 354 | |
355 | - if ( ! empty( $events )) { |
|
355 | + if ( ! empty($events)) { |
|
356 | 356 | echo '<ul class="ee-upcoming-events-widget-ul">'; |
357 | - foreach ( $events as $event ) { |
|
358 | - if ( $event instanceof EE_Event && ( !is_single() || $post->ID != $event->ID() ) ) { |
|
357 | + foreach ($events as $event) { |
|
358 | + if ($event instanceof EE_Event && ( ! is_single() || $post->ID != $event->ID())) { |
|
359 | 359 | //printr( $event, '$event <br /><span style="font-size:10px;font-weight:normal;">' . __FILE__ . '<br />line no: ' . __LINE__ . '</span>', 'auto' ); |
360 | - echo '<li id="ee-upcoming-events-widget-li-' . $event->ID() . '" class="ee-upcoming-events-widget-li">'; |
|
360 | + echo '<li id="ee-upcoming-events-widget-li-'.$event->ID().'" class="ee-upcoming-events-widget-li">'; |
|
361 | 361 | // how big is the event name ? |
362 | - $name_length = strlen( $event->name() ); |
|
363 | - switch( $name_length ) { |
|
362 | + $name_length = strlen($event->name()); |
|
363 | + switch ($name_length) { |
|
364 | 364 | case $name_length > 70 : |
365 | - $len_class = ' three-line'; |
|
365 | + $len_class = ' three-line'; |
|
366 | 366 | break; |
367 | 367 | case $name_length > 35 : |
368 | - $len_class = ' two-line'; |
|
368 | + $len_class = ' two-line'; |
|
369 | 369 | break; |
370 | 370 | default : |
371 | - $len_class = ' one-line'; |
|
371 | + $len_class = ' one-line'; |
|
372 | 372 | } |
373 | - $event_url = apply_filters( 'FHEE_EEW_Upcoming_Events__widget__event_url', $event->get_permalink(), $event ); |
|
374 | - echo '<h5 class="ee-upcoming-events-widget-title-h5"><a class="ee-widget-event-name-a' . $len_class . '" href="' . $event_url . '">' . $event->name() . '</a></h5>'; |
|
375 | - if ( post_password_required( $event->ID() ) ) { |
|
376 | - $pswd_form = apply_filters( 'FHEE_EEW_Upcoming_Events__widget__password_form', get_the_password_form( $event->ID() ), $event ); |
|
373 | + $event_url = apply_filters('FHEE_EEW_Upcoming_Events__widget__event_url', $event->get_permalink(), $event); |
|
374 | + echo '<h5 class="ee-upcoming-events-widget-title-h5"><a class="ee-widget-event-name-a'.$len_class.'" href="'.$event_url.'">'.$event->name().'</a></h5>'; |
|
375 | + if (post_password_required($event->ID())) { |
|
376 | + $pswd_form = apply_filters('FHEE_EEW_Upcoming_Events__widget__password_form', get_the_password_form($event->ID()), $event); |
|
377 | 377 | echo $pswd_form; |
378 | 378 | } else { |
379 | - if ( has_post_thumbnail( $event->ID() ) && $image_size != 'none' ) { |
|
380 | - echo '<div class="ee-upcoming-events-widget-img-dv"><a class="ee-upcoming-events-widget-img" href="' . $event_url . '">' . get_the_post_thumbnail( $event->ID(), $image_size ) . '</a></div>'; |
|
379 | + if (has_post_thumbnail($event->ID()) && $image_size != 'none') { |
|
380 | + echo '<div class="ee-upcoming-events-widget-img-dv"><a class="ee-upcoming-events-widget-img" href="'.$event_url.'">'.get_the_post_thumbnail($event->ID(), $image_size).'</a></div>'; |
|
381 | 381 | } |
382 | - $desc = $event->short_description( 25 ); |
|
383 | - if ( $show_dates ) { |
|
384 | - $date_format = apply_filters( 'FHEE__espresso_event_date_range__date_format', get_option( 'date_format' )); |
|
385 | - $time_format = apply_filters( 'FHEE__espresso_event_date_range__time_format', get_option( 'time_format' )); |
|
386 | - $single_date_format = apply_filters( 'FHEE__espresso_event_date_range__single_date_format', get_option( 'date_format' )); |
|
387 | - $single_time_format = apply_filters( 'FHEE__espresso_event_date_range__single_time_format', get_option( 'time_format' )); |
|
388 | - if ( $date_range == TRUE ) { |
|
389 | - echo espresso_event_date_range( $date_format, $time_format, $single_date_format, $single_time_format, $event->ID() ); |
|
390 | - }else{ |
|
391 | - echo espresso_list_of_event_dates( $event->ID(), $date_format, $time_format, FALSE, NULL, TRUE, TRUE, $date_limit ); |
|
382 | + $desc = $event->short_description(25); |
|
383 | + if ($show_dates) { |
|
384 | + $date_format = apply_filters('FHEE__espresso_event_date_range__date_format', get_option('date_format')); |
|
385 | + $time_format = apply_filters('FHEE__espresso_event_date_range__time_format', get_option('time_format')); |
|
386 | + $single_date_format = apply_filters('FHEE__espresso_event_date_range__single_date_format', get_option('date_format')); |
|
387 | + $single_time_format = apply_filters('FHEE__espresso_event_date_range__single_time_format', get_option('time_format')); |
|
388 | + if ($date_range == TRUE) { |
|
389 | + echo espresso_event_date_range($date_format, $time_format, $single_date_format, $single_time_format, $event->ID()); |
|
390 | + } else { |
|
391 | + echo espresso_list_of_event_dates($event->ID(), $date_format, $time_format, FALSE, NULL, TRUE, TRUE, $date_limit); |
|
392 | 392 | } |
393 | 393 | } |
394 | - if ( $show_desc && $desc ) { |
|
395 | - echo '<p style="margin-top: .5em">' . $desc . '</p>'; |
|
394 | + if ($show_desc && $desc) { |
|
395 | + echo '<p style="margin-top: .5em">'.$desc.'</p>'; |
|
396 | 396 | } |
397 | 397 | } |
398 | 398 | echo '</li>'; |
@@ -416,7 +416,7 @@ discard block |
||
416 | 416 | * @return string |
417 | 417 | */ |
418 | 418 | public function make_the_title_a_link($title) { |
419 | - return '<a href="' . EEH_Event_View::event_archive_url() . '">' . $title . '</a>'; |
|
419 | + return '<a href="'.EEH_Event_View::event_archive_url().'">'.$title.'</a>'; |
|
420 | 420 | } |
421 | 421 | |
422 | 422 | } |
@@ -2,7 +2,7 @@ discard block |
||
2 | 2 | use \EventEspresso\core\exceptions\SendMessageException; |
3 | 3 | |
4 | 4 | if (! defined('EVENT_ESPRESSO_VERSION')) { |
5 | - exit('No direct script access allowed'); |
|
5 | + exit('No direct script access allowed'); |
|
6 | 6 | } |
7 | 7 | |
8 | 8 | /** |
@@ -18,693 +18,693 @@ discard block |
||
18 | 18 | { |
19 | 19 | |
20 | 20 | |
21 | - /** |
|
22 | - * @type string reference for sending action |
|
23 | - */ |
|
24 | - const action_sending = 'sending'; |
|
25 | - |
|
26 | - /** |
|
27 | - * @type string reference for generation action |
|
28 | - */ |
|
29 | - const action_generating = 'generation'; |
|
30 | - |
|
31 | - |
|
32 | - /** |
|
33 | - * @type EE_Message_Repository $_message_repository |
|
34 | - */ |
|
35 | - protected $_message_repository; |
|
36 | - |
|
37 | - /** |
|
38 | - * Sets the limit of how many messages are generated per process. |
|
39 | - * |
|
40 | - * @type int |
|
41 | - */ |
|
42 | - protected $_batch_count; |
|
43 | - |
|
44 | - |
|
45 | - /** |
|
46 | - * This is an array of cached queue items being stored in this object. |
|
47 | - * The array keys will be the ID of the EE_Message in the db if saved. If the EE_Message |
|
48 | - * is not saved to the db then its key will be an increment of "UNS" (i.e. UNS1, UNS2 etc.) |
|
49 | - * |
|
50 | - * @type EE_Message[] |
|
51 | - */ |
|
52 | - protected $_cached_queue_items; |
|
53 | - |
|
54 | - /** |
|
55 | - * Tracks the number of unsaved queue items. |
|
56 | - * |
|
57 | - * @type int |
|
58 | - */ |
|
59 | - protected $_unsaved_count = 0; |
|
60 | - |
|
61 | - /** |
|
62 | - * used to record if a do_messenger_hooks has already been called for a message type. This prevents multiple |
|
63 | - * hooks getting fired if users have setup their action/filter hooks to prevent duplicate calls. |
|
64 | - * |
|
65 | - * @type array |
|
66 | - */ |
|
67 | - protected $_did_hook = array(); |
|
68 | - |
|
69 | - |
|
70 | - /** |
|
71 | - * Constructor. |
|
72 | - * Setup all the initial properties and load a EE_Message_Repository. |
|
73 | - * |
|
74 | - * @param \EE_Message_Repository $message_repository |
|
75 | - */ |
|
76 | - public function __construct(EE_Message_Repository $message_repository) |
|
77 | - { |
|
78 | - $this->_batch_count = apply_filters('FHEE__EE_Messages_Queue___batch_count', 50); |
|
79 | - $this->_message_repository = $message_repository; |
|
80 | - } |
|
81 | - |
|
82 | - |
|
83 | - /** |
|
84 | - * Add a EE_Message object to the queue |
|
85 | - * |
|
86 | - * @param EE_Message $message |
|
87 | - * @param array $data This will be an array of data to attach to the object in the repository. If the |
|
88 | - * object is persisted, this data will be saved on an extra_meta object related to |
|
89 | - * EE_Message. |
|
90 | - * @param bool $preview Whether this EE_Message represents a preview or not. |
|
91 | - * @param bool $test_send This indicates whether to do a test send instead of actual send. A test send will |
|
92 | - * use the messenger send method but typically is based on preview data. |
|
93 | - * @return bool Whether the message was successfully added to the repository or not. |
|
94 | - */ |
|
95 | - public function add(EE_Message $message, $data = array(), $preview = false, $test_send = false) |
|
96 | - { |
|
97 | - $data['preview'] = $preview; |
|
98 | - $data['test_send'] = $test_send; |
|
99 | - return $this->_message_repository->add($message, $data); |
|
100 | - } |
|
101 | - |
|
102 | - |
|
103 | - /** |
|
104 | - * Removes EE_Message from _queue that matches the given EE_Message if the pointer is on a matching EE_Message |
|
105 | - * |
|
106 | - * @param EE_Message $message The message to detach from the queue |
|
107 | - * @param bool $persist This flag indicates whether to attempt to delete the object from the db as well. |
|
108 | - * @return bool |
|
109 | - */ |
|
110 | - public function remove(EE_Message $message, $persist = false) |
|
111 | - { |
|
112 | - if ($persist && $this->_message_repository->current() !== $message) { |
|
113 | - //get pointer on right message |
|
114 | - if ($this->_message_repository->has($message)) { |
|
115 | - $this->_message_repository->rewind(); |
|
116 | - while ($this->_message_repository->valid()) { |
|
117 | - if ($this->_message_repository->current() === $message) { |
|
118 | - break; |
|
119 | - } |
|
120 | - $this->_message_repository->next(); |
|
121 | - } |
|
122 | - } else { |
|
123 | - return false; |
|
124 | - } |
|
125 | - } |
|
126 | - return $persist ? $this->_message_repository->delete() : $this->_message_repository->remove($message); |
|
127 | - } |
|
128 | - |
|
129 | - |
|
130 | - /** |
|
131 | - * Persists all queued EE_Message objects to the db. |
|
132 | - * |
|
133 | - * @param bool $do_hooks_only @see EE_Message_Repository::saveAll |
|
134 | - * @return array @see EE_Messages_Repository::saveAll() for return values. |
|
135 | - */ |
|
136 | - public function save($do_hooks_only = false) |
|
137 | - { |
|
138 | - return $this->_message_repository->saveAll($do_hooks_only); |
|
139 | - } |
|
140 | - |
|
141 | - |
|
142 | - /** |
|
143 | - * @return EE_Message_Repository |
|
144 | - */ |
|
145 | - public function get_message_repository() |
|
146 | - { |
|
147 | - return $this->_message_repository; |
|
148 | - } |
|
149 | - |
|
150 | - |
|
151 | - /** |
|
152 | - * This does the following things: |
|
153 | - * 1. Checks if there is a lock on generation (prevents race conditions). If there is a lock then exits (return |
|
154 | - * false). |
|
155 | - * 2. If no lock, sets lock, then retrieves a batch of non-generated EE_Message objects and adds to queue |
|
156 | - * 3. Returns bool. True = batch ready. False = no batch ready (or nothing available for generation). |
|
157 | - * Note: Callers should make sure they release the lock otherwise batch generation will be prevented from |
|
158 | - * continuing. The lock is on a transient that is set to expire after one hour as a fallback in case locks are not |
|
159 | - * removed. |
|
160 | - * |
|
161 | - * @return bool true if successfully retrieved batch, false no batch ready. |
|
162 | - */ |
|
163 | - public function get_batch_to_generate() |
|
164 | - { |
|
165 | - if ($this->is_locked(EE_Messages_Queue::action_generating)) { |
|
166 | - return false; |
|
167 | - } |
|
168 | - |
|
169 | - //lock batch generation to prevent race conditions. |
|
170 | - $this->lock_queue(EE_Messages_Queue::action_generating); |
|
171 | - |
|
172 | - $query_args = array( |
|
173 | - // key 0 = where conditions |
|
174 | - 0 => array('STS_ID' => EEM_Message::status_incomplete), |
|
175 | - 'order_by' => $this->_get_priority_orderby(), |
|
176 | - 'limit' => $this->_batch_count, |
|
177 | - ); |
|
178 | - $messages = EEM_Message::instance()->get_all($query_args); |
|
179 | - |
|
180 | - if ( ! $messages) { |
|
181 | - return false; //nothing to generate |
|
182 | - } |
|
183 | - |
|
184 | - foreach ($messages as $message) { |
|
185 | - if ($message instanceof EE_Message) { |
|
186 | - $data = $message->all_extra_meta_array(); |
|
187 | - $this->add($message, $data); |
|
188 | - } |
|
189 | - } |
|
190 | - return true; |
|
191 | - } |
|
192 | - |
|
193 | - |
|
194 | - /** |
|
195 | - * This does the following things: |
|
196 | - * 1. Checks if there is a lock on sending (prevents race conditions). If there is a lock then exits (return |
|
197 | - * false). |
|
198 | - * 2. Grabs the allowed number of messages to send for the rate_limit. If cannot send any more messages, then |
|
199 | - * return false. |
|
200 | - * 2. If no lock, sets lock, then retrieves a batch of EE_Message objects, adds to queue and triggers execution. |
|
201 | - * 3. On success or unsuccessful send, sets status appropriately. |
|
202 | - * 4. Saves messages via the queue |
|
203 | - * 5. Releases lock. |
|
204 | - * |
|
205 | - * @return bool true on success, false if something preventing sending (i.e. lock set). Note: true does not |
|
206 | - * necessarily mean that all messages were successfully sent. It just means that this method |
|
207 | - * successfully completed. On true, client may want to call $this->count_STS_in_queue( |
|
208 | - * EEM_Message::status_failed ) to see if any failed EE_Message objects. Each failed message object |
|
209 | - * will also have a saved error message on it to assist with notifying user. |
|
210 | - */ |
|
211 | - public function get_to_send_batch_and_send() |
|
212 | - { |
|
213 | - $rate_limit = $this->get_rate_limit(); |
|
214 | - if ($rate_limit < 1 || $this->is_locked(EE_Messages_Queue::action_sending)) { |
|
215 | - return false; |
|
216 | - } |
|
217 | - |
|
218 | - $this->lock_queue(EE_Messages_Queue::action_sending); |
|
219 | - |
|
220 | - $batch = $this->_batch_count < $rate_limit ? $this->_batch_count : $rate_limit; |
|
221 | - |
|
222 | - $query_args = array( |
|
223 | - // key 0 = where conditions |
|
224 | - 0 => array('STS_ID' => array('IN', EEM_Message::instance()->stati_indicating_to_send())), |
|
225 | - 'order_by' => $this->_get_priority_orderby(), |
|
226 | - 'limit' => $batch, |
|
227 | - ); |
|
228 | - |
|
229 | - $messages_to_send = EEM_Message::instance()->get_all($query_args); |
|
230 | - |
|
231 | - |
|
232 | - //any to send? |
|
233 | - if ( ! $messages_to_send) { |
|
234 | - $this->unlock_queue(EE_Messages_Queue::action_sending); |
|
235 | - return false; |
|
236 | - } |
|
237 | - |
|
238 | - $queue_count = 0; |
|
239 | - |
|
240 | - //add to queue. |
|
241 | - foreach ($messages_to_send as $message) { |
|
242 | - if ($message instanceof EE_Message) { |
|
243 | - $queue_count++; |
|
244 | - $this->add($message); |
|
245 | - } |
|
246 | - } |
|
247 | - |
|
248 | - //send messages (this also updates the rate limit) |
|
249 | - $this->execute(); |
|
250 | - |
|
251 | - //release lock |
|
252 | - $this->unlock_queue(EE_Messages_Queue::action_sending); |
|
253 | - //update rate limit |
|
254 | - $this->set_rate_limit($queue_count); |
|
255 | - return true; |
|
256 | - } |
|
257 | - |
|
258 | - |
|
259 | - /** |
|
260 | - * Locks the queue so that no other queues can call the "batch" methods. |
|
261 | - * |
|
262 | - * @param string $type The type of queue being locked. |
|
263 | - */ |
|
264 | - public function lock_queue($type = EE_Messages_Queue::action_generating) |
|
265 | - { |
|
266 | - update_option($this->_get_lock_key($type), $this->_get_lock_expiry($type)); |
|
267 | - } |
|
268 | - |
|
269 | - |
|
270 | - /** |
|
271 | - * Unlocks the queue so that batch methods can be used. |
|
272 | - * |
|
273 | - * @param string $type The type of queue being unlocked. |
|
274 | - */ |
|
275 | - public function unlock_queue($type = EE_Messages_Queue::action_generating) |
|
276 | - { |
|
277 | - delete_option($this->_get_lock_key($type)); |
|
278 | - } |
|
279 | - |
|
280 | - |
|
281 | - /** |
|
282 | - * Retrieve the key used for the lock transient. |
|
283 | - * |
|
284 | - * @param string $type The type of lock. |
|
285 | - * @return string |
|
286 | - */ |
|
287 | - protected function _get_lock_key($type = EE_Messages_Queue::action_generating) |
|
288 | - { |
|
289 | - return '_ee_lock_' . $type; |
|
290 | - } |
|
291 | - |
|
292 | - |
|
293 | - /** |
|
294 | - * Retrieve the expiry time for the lock transient. |
|
295 | - * |
|
296 | - * @param string $type The type of lock |
|
297 | - * @return int time to expiry in seconds. |
|
298 | - */ |
|
299 | - protected function _get_lock_expiry($type = EE_Messages_Queue::action_generating) |
|
300 | - { |
|
301 | - return time() + (int) apply_filters('FHEE__EE_Messages_Queue__lock_expiry', HOUR_IN_SECONDS, $type); |
|
302 | - } |
|
303 | - |
|
304 | - |
|
305 | - /** |
|
306 | - * Returns the key used for rate limit transient. |
|
307 | - * |
|
308 | - * @return string |
|
309 | - */ |
|
310 | - protected function _get_rate_limit_key() |
|
311 | - { |
|
312 | - return '_ee_rate_limit'; |
|
313 | - } |
|
314 | - |
|
315 | - |
|
316 | - /** |
|
317 | - * Returns the rate limit expiry time. |
|
318 | - * |
|
319 | - * @return int |
|
320 | - */ |
|
321 | - protected function _get_rate_limit_expiry() |
|
322 | - { |
|
323 | - return time() + (int) apply_filters('FHEE__EE_Messages_Queue__rate_limit_expiry', HOUR_IN_SECONDS); |
|
324 | - } |
|
325 | - |
|
326 | - |
|
327 | - /** |
|
328 | - * Returns the default rate limit for sending messages. |
|
329 | - * |
|
330 | - * @return int |
|
331 | - */ |
|
332 | - protected function _default_rate_limit() |
|
333 | - { |
|
334 | - return (int) apply_filters('FHEE__EE_Messages_Queue___rate_limit', 200); |
|
335 | - } |
|
336 | - |
|
337 | - |
|
338 | - /** |
|
339 | - * Return the orderby array for priority. |
|
340 | - * |
|
341 | - * @return array |
|
342 | - */ |
|
343 | - protected function _get_priority_orderby() |
|
344 | - { |
|
345 | - return array( |
|
346 | - 'MSG_priority' => 'ASC', |
|
347 | - 'MSG_modified' => 'DESC', |
|
348 | - ); |
|
349 | - } |
|
350 | - |
|
351 | - |
|
352 | - /** |
|
353 | - * Returns whether batch methods are "locked" or not. |
|
354 | - * |
|
355 | - * @param string $type The type of lock being checked for. |
|
356 | - * @return bool |
|
357 | - */ |
|
358 | - public function is_locked($type = EE_Messages_Queue::action_generating) |
|
359 | - { |
|
360 | - $lock = (int) get_option($this->_get_lock_key($type), 0); |
|
361 | - /** |
|
362 | - * This filters the default is_locked behaviour. |
|
363 | - */ |
|
364 | - $is_locked = filter_var( |
|
365 | - apply_filters( |
|
366 | - 'FHEE__EE_Messages_Queue__is_locked', |
|
367 | - $lock > time(), |
|
368 | - $this |
|
369 | - ), |
|
370 | - FILTER_VALIDATE_BOOLEAN |
|
371 | - ); |
|
372 | - |
|
373 | - /** |
|
374 | - * @see usage of this filter in EE_Messages_Queue::initiate_request_by_priority() method. |
|
375 | - * Also implemented here because messages processed on the same request should not have any locks applied. |
|
376 | - */ |
|
377 | - if ( |
|
378 | - apply_filters('FHEE__EE_Messages_Processor__initiate_request_by_priority__do_immediate_processing', false) |
|
379 | - || EE_Registry::instance()->NET_CFG->core->do_messages_on_same_request |
|
380 | - ) { |
|
381 | - $is_locked = false; |
|
382 | - } |
|
383 | - |
|
384 | - |
|
385 | - return $is_locked; |
|
386 | - } |
|
387 | - |
|
388 | - |
|
389 | - /** |
|
390 | - * Retrieves the rate limit that may be cached as a transient. |
|
391 | - * If the rate limit is not set, then this sets the default rate limit and expiry and returns it. |
|
392 | - * |
|
393 | - * @param bool $return_expiry If true then return the expiry time not the rate_limit. |
|
394 | - * @return int |
|
395 | - */ |
|
396 | - protected function get_rate_limit($return_expiry = false) |
|
397 | - { |
|
398 | - $stored_rate_info = get_option($this->_get_rate_limit_key(), array()); |
|
399 | - $rate_limit = isset($stored_rate_info[0]) |
|
400 | - ? (int) $stored_rate_info[0] |
|
401 | - : 0; |
|
402 | - $expiry = isset($stored_rate_info[1]) |
|
403 | - ? (int) $stored_rate_info[1] |
|
404 | - : 0; |
|
405 | - //set the default for tracking? |
|
406 | - if (empty($stored_rate_info) || time() > $expiry) { |
|
407 | - $expiry = $this->_get_rate_limit_expiry(); |
|
408 | - $rate_limit = $this->_default_rate_limit(); |
|
409 | - update_option($this->_get_rate_limit_key(), array($rate_limit, $expiry)); |
|
410 | - } |
|
411 | - return $return_expiry ? $expiry : $rate_limit; |
|
412 | - } |
|
413 | - |
|
414 | - |
|
415 | - /** |
|
416 | - * This updates existing rate limit with the new limit which is the old minus the batch. |
|
417 | - * |
|
418 | - * @param int $batch_completed This sets the new rate limit based on the given batch that was completed. |
|
419 | - */ |
|
420 | - protected function set_rate_limit($batch_completed) |
|
421 | - { |
|
422 | - //first get the most up to date rate limit (in case its expired and reset) |
|
423 | - $rate_limit = $this->get_rate_limit(); |
|
424 | - $expiry = $this->get_rate_limit(true); |
|
425 | - $new_limit = $rate_limit - $batch_completed; |
|
426 | - //updating the transient option directly to avoid resetting the expiry. |
|
427 | - |
|
428 | - update_option($this->_get_rate_limit_key(), array($new_limit, $expiry)); |
|
429 | - } |
|
430 | - |
|
431 | - |
|
432 | - /** |
|
433 | - * This method checks the queue for ANY EE_Message objects with a priority matching the given priority passed in. |
|
434 | - * If that exists, then we immediately initiate a non-blocking request to do the requested action type. |
|
435 | - * Note: Keep in mind that there is the possibility that the request will not execute if there is already another |
|
436 | - * request running on a queue for the given task. |
|
437 | - * |
|
438 | - * @param string $task This indicates what type of request is going to be initiated. |
|
439 | - * @param int $priority This indicates the priority that triggers initiating the request. |
|
440 | - */ |
|
441 | - public function initiate_request_by_priority($task = 'generate', $priority = EEM_Message::priority_high) |
|
442 | - { |
|
443 | - //determine what status is matched with the priority as part of the trigger conditions. |
|
444 | - $status = $task == 'generate' |
|
445 | - ? EEM_Message::status_incomplete |
|
446 | - : EEM_Message::instance()->stati_indicating_to_send(); |
|
447 | - // always make sure we save because either this will get executed immediately on a separate request |
|
448 | - // or remains in the queue for the regularly scheduled queue batch. |
|
449 | - $this->save(); |
|
450 | - /** |
|
451 | - * This filter/option allows users to override processing of messages on separate requests and instead have everything |
|
452 | - * happen on the same request. If this is utilized remember: |
|
453 | - * - message priorities don't matter |
|
454 | - * - existing unprocessed messages in the queue will not get processed unless manually triggered. |
|
455 | - * - things will be perceived to take longer to happen for end users (i.e. registrations) because of the additional |
|
456 | - * processing happening on the same request. |
|
457 | - * - any race condition protection (locks) are removed because they don't apply when things are processed on |
|
458 | - * the same request. |
|
459 | - */ |
|
460 | - if ( |
|
461 | - apply_filters('FHEE__EE_Messages_Processor__initiate_request_by_priority__do_immediate_processing', false) |
|
462 | - || EE_Registry::instance()->NET_CFG->core->do_messages_on_same_request |
|
463 | - ) { |
|
464 | - $messages_processor = EE_Registry::instance()->load_lib('Messages_Processor'); |
|
465 | - if ($messages_processor instanceof EE_Messages_Processor) { |
|
466 | - return $messages_processor->process_immediately_from_queue($this); |
|
467 | - } |
|
468 | - //if we get here then that means the messages processor couldn't be loaded so messages will just remain |
|
469 | - //queued for manual triggering by end user. |
|
470 | - } |
|
471 | - |
|
472 | - if ($this->_message_repository->count_by_priority_and_status($priority, $status)) { |
|
473 | - EE_Messages_Scheduler::initiate_scheduled_non_blocking_request($task); |
|
474 | - } |
|
475 | - } |
|
476 | - |
|
477 | - |
|
478 | - /** |
|
479 | - * Loops through the EE_Message objects in the _queue and calls the messenger send methods for each message. |
|
480 | - * |
|
481 | - * @param bool $save Used to indicate whether to save the message queue after sending |
|
482 | - * (default will save). |
|
483 | - * @param mixed $sending_messenger (optional) When the sending messenger is different than |
|
484 | - * what is on the EE_Message object in the queue. |
|
485 | - * For instance, showing the browser view of an email message, |
|
486 | - * or giving a pdf generated view of an html document. |
|
487 | - * This should be an instance of EE_messenger but if you call this |
|
488 | - * method |
|
489 | - * intending it to be a sending messenger but a valid one could not be |
|
490 | - * retrieved then send in an instance of EE_Error that contains the |
|
491 | - * related error message. |
|
492 | - * @param bool|int $by_priority When set, this indicates that only messages |
|
493 | - * matching the given priority should be executed. |
|
494 | - * @return int Number of messages sent. Note, 0 does not mean that no messages were processed. |
|
495 | - * Also, if the messenger is an request type messenger (or a preview), |
|
496 | - * its entirely possible that the messenger will exit before |
|
497 | - */ |
|
498 | - public function execute($save = true, $sending_messenger = null, $by_priority = false) |
|
499 | - { |
|
500 | - $messages_sent = 0; |
|
501 | - $this->_did_hook = array(); |
|
502 | - $this->_message_repository->rewind(); |
|
503 | - |
|
504 | - while ($this->_message_repository->valid()) { |
|
505 | - $error_messages = array(); |
|
506 | - /** @type EE_Message $message */ |
|
507 | - $message = $this->_message_repository->current(); |
|
508 | - //only process things that are queued for sending |
|
509 | - if (! in_array($message->STS_ID(), EEM_Message::instance()->stati_indicating_to_send())) { |
|
510 | - $this->_message_repository->next(); |
|
511 | - continue; |
|
512 | - } |
|
513 | - //if $by_priority is set and does not match then continue; |
|
514 | - if ($by_priority && $by_priority != $message->priority()) { |
|
515 | - $this->_message_repository->next(); |
|
516 | - continue; |
|
517 | - } |
|
518 | - //error checking |
|
519 | - if (! $message->valid_messenger()) { |
|
520 | - $error_messages[] = sprintf( |
|
521 | - __('The %s messenger is not active at time of sending.', 'event_espresso'), |
|
522 | - $message->messenger() |
|
523 | - ); |
|
524 | - } |
|
525 | - if (! $message->valid_message_type()) { |
|
526 | - $error_messages[] = sprintf( |
|
527 | - __('The %s message type is not active at the time of sending.', 'event_espresso'), |
|
528 | - $message->message_type() |
|
529 | - ); |
|
530 | - } |
|
531 | - // if there was supposed to be a sending messenger for this message, but it was invalid/inactive, |
|
532 | - // then it will instead be an EE_Error object, so let's check for that |
|
533 | - if ($sending_messenger instanceof EE_Error) { |
|
534 | - $error_messages[] = $sending_messenger->getMessage(); |
|
535 | - } |
|
536 | - // if there are no errors, then let's process the message |
|
537 | - if (empty($error_messages)) { |
|
538 | - if ($save) { |
|
539 | - $message->set_messenger_is_executing(); |
|
540 | - } |
|
541 | - if ($this->_process_message($message, $sending_messenger)) { |
|
542 | - $messages_sent++; |
|
543 | - } |
|
544 | - } |
|
545 | - $this->_set_error_message($message, $error_messages); |
|
546 | - //add modified time |
|
547 | - $message->set_modified(time()); |
|
548 | - //we save each message after its processed to make sure its status persists in case PHP times-out or runs |
|
549 | - //out of memory. @see https://events.codebasehq.com/projects/event-espresso/tickets/10281 |
|
550 | - if ($save) { |
|
551 | - $message->save(); |
|
552 | - } |
|
553 | - |
|
554 | - $this->_message_repository->next(); |
|
555 | - } |
|
556 | - if ($save) { |
|
557 | - $this->save(true); |
|
558 | - } |
|
559 | - return $messages_sent; |
|
560 | - } |
|
561 | - |
|
562 | - |
|
563 | - /** |
|
564 | - * _process_message |
|
565 | - * |
|
566 | - * @param EE_Message $message |
|
567 | - * @param mixed $sending_messenger (optional) |
|
568 | - * @return bool |
|
569 | - */ |
|
570 | - protected function _process_message(EE_Message $message, $sending_messenger = null) |
|
571 | - { |
|
572 | - // these *should* have been validated in the execute() method above |
|
573 | - $messenger = $message->messenger_object(); |
|
574 | - $message_type = $message->message_type_object(); |
|
575 | - //do actions for sending messenger if it differs from generating messenger and swap values. |
|
576 | - if ( |
|
577 | - $sending_messenger instanceof EE_messenger |
|
578 | - && $messenger instanceof EE_messenger |
|
579 | - && $sending_messenger->name != $messenger->name |
|
580 | - ) { |
|
581 | - $messenger->do_secondary_messenger_hooks($sending_messenger->name); |
|
582 | - $messenger = $sending_messenger; |
|
583 | - } |
|
584 | - // send using messenger, but double check objects |
|
585 | - if ($messenger instanceof EE_messenger && $message_type instanceof EE_message_type) { |
|
586 | - //set hook for message type (but only if not using another messenger to send). |
|
587 | - if ( ! isset($this->_did_hook[$message_type->name])) { |
|
588 | - $message_type->do_messenger_hooks($messenger); |
|
589 | - $this->_did_hook[$message_type->name] = 1; |
|
590 | - } |
|
591 | - //if preview then use preview method |
|
592 | - return $this->_message_repository->is_preview() |
|
593 | - ? $this->_do_preview($message, $messenger, $message_type, $this->_message_repository->is_test_send()) |
|
594 | - : $this->_do_send($message, $messenger, $message_type); |
|
595 | - } |
|
596 | - return false; |
|
597 | - } |
|
598 | - |
|
599 | - |
|
600 | - /** |
|
601 | - * The intention of this method is to count how many EE_Message objects |
|
602 | - * are in the queue with a given status. |
|
603 | - * Example usage: |
|
604 | - * After a caller calls the "EE_Message_Queue::execute()" method, the caller can check if there were any failed |
|
605 | - * sends by calling $queue->count_STS_in_queue( EEM_Message_Queue::status_failed ). |
|
606 | - * |
|
607 | - * @param array|string $status Stati to check for in queue |
|
608 | - * @return int Count of EE_Message's matching the given status. |
|
609 | - */ |
|
610 | - public function count_STS_in_queue($status) |
|
611 | - { |
|
612 | - $count = 0; |
|
613 | - $status = is_array($status) ? $status : array($status); |
|
614 | - $this->_message_repository->rewind(); |
|
615 | - foreach ($this->_message_repository as $message) { |
|
616 | - if (in_array($message->STS_ID(), $status)) { |
|
617 | - $count++; |
|
618 | - } |
|
619 | - } |
|
620 | - return $count; |
|
621 | - } |
|
622 | - |
|
623 | - |
|
624 | - /** |
|
625 | - * Executes the get_preview method on the provided messenger. |
|
626 | - * |
|
627 | - * @param EE_Message $message |
|
628 | - * @param EE_messenger $messenger |
|
629 | - * @param EE_message_type $message_type |
|
630 | - * @param $test_send |
|
631 | - * @return bool true means all went well, false means, not so much. |
|
632 | - */ |
|
633 | - protected function _do_preview( |
|
634 | - EE_Message $message, |
|
635 | - EE_messenger $messenger, |
|
636 | - EE_message_type $message_type, |
|
637 | - $test_send |
|
638 | - ) { |
|
639 | - if ($preview = $messenger->get_preview($message, $message_type, $test_send)) { |
|
640 | - if ( ! $test_send) { |
|
641 | - $message->set_content($preview); |
|
642 | - } |
|
643 | - $message->set_STS_ID(EEM_Message::status_sent); |
|
644 | - return true; |
|
645 | - } else { |
|
646 | - $message->set_STS_ID(EEM_Message::status_failed); |
|
647 | - return false; |
|
648 | - } |
|
649 | - } |
|
650 | - |
|
651 | - |
|
652 | - /** |
|
653 | - * Executes the send method on the provided messenger |
|
654 | - * EE_Messengers are expected to: |
|
655 | - * - return true if the send was successful. |
|
656 | - * - return false if the send was unsuccessful but can be tried again. |
|
657 | - * - throw an Exception if the send was unsuccessful and cannot be tried again. |
|
658 | - * |
|
659 | - * @param EE_Message $message |
|
660 | - * @param EE_messenger $messenger |
|
661 | - * @param EE_message_type $message_type |
|
662 | - * @return bool true means all went well, false means, not so much. |
|
663 | - */ |
|
664 | - protected function _do_send(EE_Message $message, EE_messenger $messenger, EE_message_type $message_type) |
|
665 | - { |
|
666 | - try { |
|
667 | - if ($messenger->send_message($message, $message_type)) { |
|
668 | - $message->set_STS_ID(EEM_Message::status_sent); |
|
669 | - return true; |
|
670 | - } else { |
|
671 | - $message->set_STS_ID(EEM_Message::status_retry); |
|
672 | - return false; |
|
673 | - } |
|
674 | - } catch (SendMessageException $e) { |
|
675 | - $message->set_STS_ID(EEM_Message::status_failed); |
|
676 | - $message->set_error_message($e->getMessage()); |
|
677 | - return false; |
|
678 | - } |
|
679 | - } |
|
680 | - |
|
681 | - |
|
682 | - /** |
|
683 | - * This sets any necessary error messages on the message object and its status to failed. |
|
684 | - * |
|
685 | - * @param EE_Message $message |
|
686 | - * @param array $error_messages the response from the messenger. |
|
687 | - */ |
|
688 | - protected function _set_error_message(EE_Message $message, $error_messages) |
|
689 | - { |
|
690 | - $error_messages = (array)$error_messages; |
|
691 | - if (in_array($message->STS_ID(), EEM_Message::instance()->stati_indicating_failed_sending())) { |
|
692 | - $notices = EE_Error::has_notices(); |
|
693 | - $error_messages[] = __( |
|
694 | - 'Messenger and Message Type were valid and active, but the messenger send method failed.', |
|
695 | - 'event_espresso' |
|
696 | - ); |
|
697 | - if ($notices === 1) { |
|
698 | - $notices = EE_Error::get_vanilla_notices(); |
|
699 | - $notices['errors'] = isset($notices['errors']) ? $notices['errors'] : array(); |
|
700 | - $error_messages[] = implode("\n", $notices['errors']); |
|
701 | - } |
|
702 | - } |
|
703 | - if (count($error_messages) > 0) { |
|
704 | - $msg = __('Message was not executed successfully.', 'event_espresso'); |
|
705 | - $msg = $msg . "\n" . implode("\n", $error_messages); |
|
706 | - $message->set_error_message($msg); |
|
707 | - } |
|
708 | - } |
|
21 | + /** |
|
22 | + * @type string reference for sending action |
|
23 | + */ |
|
24 | + const action_sending = 'sending'; |
|
25 | + |
|
26 | + /** |
|
27 | + * @type string reference for generation action |
|
28 | + */ |
|
29 | + const action_generating = 'generation'; |
|
30 | + |
|
31 | + |
|
32 | + /** |
|
33 | + * @type EE_Message_Repository $_message_repository |
|
34 | + */ |
|
35 | + protected $_message_repository; |
|
36 | + |
|
37 | + /** |
|
38 | + * Sets the limit of how many messages are generated per process. |
|
39 | + * |
|
40 | + * @type int |
|
41 | + */ |
|
42 | + protected $_batch_count; |
|
43 | + |
|
44 | + |
|
45 | + /** |
|
46 | + * This is an array of cached queue items being stored in this object. |
|
47 | + * The array keys will be the ID of the EE_Message in the db if saved. If the EE_Message |
|
48 | + * is not saved to the db then its key will be an increment of "UNS" (i.e. UNS1, UNS2 etc.) |
|
49 | + * |
|
50 | + * @type EE_Message[] |
|
51 | + */ |
|
52 | + protected $_cached_queue_items; |
|
53 | + |
|
54 | + /** |
|
55 | + * Tracks the number of unsaved queue items. |
|
56 | + * |
|
57 | + * @type int |
|
58 | + */ |
|
59 | + protected $_unsaved_count = 0; |
|
60 | + |
|
61 | + /** |
|
62 | + * used to record if a do_messenger_hooks has already been called for a message type. This prevents multiple |
|
63 | + * hooks getting fired if users have setup their action/filter hooks to prevent duplicate calls. |
|
64 | + * |
|
65 | + * @type array |
|
66 | + */ |
|
67 | + protected $_did_hook = array(); |
|
68 | + |
|
69 | + |
|
70 | + /** |
|
71 | + * Constructor. |
|
72 | + * Setup all the initial properties and load a EE_Message_Repository. |
|
73 | + * |
|
74 | + * @param \EE_Message_Repository $message_repository |
|
75 | + */ |
|
76 | + public function __construct(EE_Message_Repository $message_repository) |
|
77 | + { |
|
78 | + $this->_batch_count = apply_filters('FHEE__EE_Messages_Queue___batch_count', 50); |
|
79 | + $this->_message_repository = $message_repository; |
|
80 | + } |
|
81 | + |
|
82 | + |
|
83 | + /** |
|
84 | + * Add a EE_Message object to the queue |
|
85 | + * |
|
86 | + * @param EE_Message $message |
|
87 | + * @param array $data This will be an array of data to attach to the object in the repository. If the |
|
88 | + * object is persisted, this data will be saved on an extra_meta object related to |
|
89 | + * EE_Message. |
|
90 | + * @param bool $preview Whether this EE_Message represents a preview or not. |
|
91 | + * @param bool $test_send This indicates whether to do a test send instead of actual send. A test send will |
|
92 | + * use the messenger send method but typically is based on preview data. |
|
93 | + * @return bool Whether the message was successfully added to the repository or not. |
|
94 | + */ |
|
95 | + public function add(EE_Message $message, $data = array(), $preview = false, $test_send = false) |
|
96 | + { |
|
97 | + $data['preview'] = $preview; |
|
98 | + $data['test_send'] = $test_send; |
|
99 | + return $this->_message_repository->add($message, $data); |
|
100 | + } |
|
101 | + |
|
102 | + |
|
103 | + /** |
|
104 | + * Removes EE_Message from _queue that matches the given EE_Message if the pointer is on a matching EE_Message |
|
105 | + * |
|
106 | + * @param EE_Message $message The message to detach from the queue |
|
107 | + * @param bool $persist This flag indicates whether to attempt to delete the object from the db as well. |
|
108 | + * @return bool |
|
109 | + */ |
|
110 | + public function remove(EE_Message $message, $persist = false) |
|
111 | + { |
|
112 | + if ($persist && $this->_message_repository->current() !== $message) { |
|
113 | + //get pointer on right message |
|
114 | + if ($this->_message_repository->has($message)) { |
|
115 | + $this->_message_repository->rewind(); |
|
116 | + while ($this->_message_repository->valid()) { |
|
117 | + if ($this->_message_repository->current() === $message) { |
|
118 | + break; |
|
119 | + } |
|
120 | + $this->_message_repository->next(); |
|
121 | + } |
|
122 | + } else { |
|
123 | + return false; |
|
124 | + } |
|
125 | + } |
|
126 | + return $persist ? $this->_message_repository->delete() : $this->_message_repository->remove($message); |
|
127 | + } |
|
128 | + |
|
129 | + |
|
130 | + /** |
|
131 | + * Persists all queued EE_Message objects to the db. |
|
132 | + * |
|
133 | + * @param bool $do_hooks_only @see EE_Message_Repository::saveAll |
|
134 | + * @return array @see EE_Messages_Repository::saveAll() for return values. |
|
135 | + */ |
|
136 | + public function save($do_hooks_only = false) |
|
137 | + { |
|
138 | + return $this->_message_repository->saveAll($do_hooks_only); |
|
139 | + } |
|
140 | + |
|
141 | + |
|
142 | + /** |
|
143 | + * @return EE_Message_Repository |
|
144 | + */ |
|
145 | + public function get_message_repository() |
|
146 | + { |
|
147 | + return $this->_message_repository; |
|
148 | + } |
|
149 | + |
|
150 | + |
|
151 | + /** |
|
152 | + * This does the following things: |
|
153 | + * 1. Checks if there is a lock on generation (prevents race conditions). If there is a lock then exits (return |
|
154 | + * false). |
|
155 | + * 2. If no lock, sets lock, then retrieves a batch of non-generated EE_Message objects and adds to queue |
|
156 | + * 3. Returns bool. True = batch ready. False = no batch ready (or nothing available for generation). |
|
157 | + * Note: Callers should make sure they release the lock otherwise batch generation will be prevented from |
|
158 | + * continuing. The lock is on a transient that is set to expire after one hour as a fallback in case locks are not |
|
159 | + * removed. |
|
160 | + * |
|
161 | + * @return bool true if successfully retrieved batch, false no batch ready. |
|
162 | + */ |
|
163 | + public function get_batch_to_generate() |
|
164 | + { |
|
165 | + if ($this->is_locked(EE_Messages_Queue::action_generating)) { |
|
166 | + return false; |
|
167 | + } |
|
168 | + |
|
169 | + //lock batch generation to prevent race conditions. |
|
170 | + $this->lock_queue(EE_Messages_Queue::action_generating); |
|
171 | + |
|
172 | + $query_args = array( |
|
173 | + // key 0 = where conditions |
|
174 | + 0 => array('STS_ID' => EEM_Message::status_incomplete), |
|
175 | + 'order_by' => $this->_get_priority_orderby(), |
|
176 | + 'limit' => $this->_batch_count, |
|
177 | + ); |
|
178 | + $messages = EEM_Message::instance()->get_all($query_args); |
|
179 | + |
|
180 | + if ( ! $messages) { |
|
181 | + return false; //nothing to generate |
|
182 | + } |
|
183 | + |
|
184 | + foreach ($messages as $message) { |
|
185 | + if ($message instanceof EE_Message) { |
|
186 | + $data = $message->all_extra_meta_array(); |
|
187 | + $this->add($message, $data); |
|
188 | + } |
|
189 | + } |
|
190 | + return true; |
|
191 | + } |
|
192 | + |
|
193 | + |
|
194 | + /** |
|
195 | + * This does the following things: |
|
196 | + * 1. Checks if there is a lock on sending (prevents race conditions). If there is a lock then exits (return |
|
197 | + * false). |
|
198 | + * 2. Grabs the allowed number of messages to send for the rate_limit. If cannot send any more messages, then |
|
199 | + * return false. |
|
200 | + * 2. If no lock, sets lock, then retrieves a batch of EE_Message objects, adds to queue and triggers execution. |
|
201 | + * 3. On success or unsuccessful send, sets status appropriately. |
|
202 | + * 4. Saves messages via the queue |
|
203 | + * 5. Releases lock. |
|
204 | + * |
|
205 | + * @return bool true on success, false if something preventing sending (i.e. lock set). Note: true does not |
|
206 | + * necessarily mean that all messages were successfully sent. It just means that this method |
|
207 | + * successfully completed. On true, client may want to call $this->count_STS_in_queue( |
|
208 | + * EEM_Message::status_failed ) to see if any failed EE_Message objects. Each failed message object |
|
209 | + * will also have a saved error message on it to assist with notifying user. |
|
210 | + */ |
|
211 | + public function get_to_send_batch_and_send() |
|
212 | + { |
|
213 | + $rate_limit = $this->get_rate_limit(); |
|
214 | + if ($rate_limit < 1 || $this->is_locked(EE_Messages_Queue::action_sending)) { |
|
215 | + return false; |
|
216 | + } |
|
217 | + |
|
218 | + $this->lock_queue(EE_Messages_Queue::action_sending); |
|
219 | + |
|
220 | + $batch = $this->_batch_count < $rate_limit ? $this->_batch_count : $rate_limit; |
|
221 | + |
|
222 | + $query_args = array( |
|
223 | + // key 0 = where conditions |
|
224 | + 0 => array('STS_ID' => array('IN', EEM_Message::instance()->stati_indicating_to_send())), |
|
225 | + 'order_by' => $this->_get_priority_orderby(), |
|
226 | + 'limit' => $batch, |
|
227 | + ); |
|
228 | + |
|
229 | + $messages_to_send = EEM_Message::instance()->get_all($query_args); |
|
230 | + |
|
231 | + |
|
232 | + //any to send? |
|
233 | + if ( ! $messages_to_send) { |
|
234 | + $this->unlock_queue(EE_Messages_Queue::action_sending); |
|
235 | + return false; |
|
236 | + } |
|
237 | + |
|
238 | + $queue_count = 0; |
|
239 | + |
|
240 | + //add to queue. |
|
241 | + foreach ($messages_to_send as $message) { |
|
242 | + if ($message instanceof EE_Message) { |
|
243 | + $queue_count++; |
|
244 | + $this->add($message); |
|
245 | + } |
|
246 | + } |
|
247 | + |
|
248 | + //send messages (this also updates the rate limit) |
|
249 | + $this->execute(); |
|
250 | + |
|
251 | + //release lock |
|
252 | + $this->unlock_queue(EE_Messages_Queue::action_sending); |
|
253 | + //update rate limit |
|
254 | + $this->set_rate_limit($queue_count); |
|
255 | + return true; |
|
256 | + } |
|
257 | + |
|
258 | + |
|
259 | + /** |
|
260 | + * Locks the queue so that no other queues can call the "batch" methods. |
|
261 | + * |
|
262 | + * @param string $type The type of queue being locked. |
|
263 | + */ |
|
264 | + public function lock_queue($type = EE_Messages_Queue::action_generating) |
|
265 | + { |
|
266 | + update_option($this->_get_lock_key($type), $this->_get_lock_expiry($type)); |
|
267 | + } |
|
268 | + |
|
269 | + |
|
270 | + /** |
|
271 | + * Unlocks the queue so that batch methods can be used. |
|
272 | + * |
|
273 | + * @param string $type The type of queue being unlocked. |
|
274 | + */ |
|
275 | + public function unlock_queue($type = EE_Messages_Queue::action_generating) |
|
276 | + { |
|
277 | + delete_option($this->_get_lock_key($type)); |
|
278 | + } |
|
279 | + |
|
280 | + |
|
281 | + /** |
|
282 | + * Retrieve the key used for the lock transient. |
|
283 | + * |
|
284 | + * @param string $type The type of lock. |
|
285 | + * @return string |
|
286 | + */ |
|
287 | + protected function _get_lock_key($type = EE_Messages_Queue::action_generating) |
|
288 | + { |
|
289 | + return '_ee_lock_' . $type; |
|
290 | + } |
|
291 | + |
|
292 | + |
|
293 | + /** |
|
294 | + * Retrieve the expiry time for the lock transient. |
|
295 | + * |
|
296 | + * @param string $type The type of lock |
|
297 | + * @return int time to expiry in seconds. |
|
298 | + */ |
|
299 | + protected function _get_lock_expiry($type = EE_Messages_Queue::action_generating) |
|
300 | + { |
|
301 | + return time() + (int) apply_filters('FHEE__EE_Messages_Queue__lock_expiry', HOUR_IN_SECONDS, $type); |
|
302 | + } |
|
303 | + |
|
304 | + |
|
305 | + /** |
|
306 | + * Returns the key used for rate limit transient. |
|
307 | + * |
|
308 | + * @return string |
|
309 | + */ |
|
310 | + protected function _get_rate_limit_key() |
|
311 | + { |
|
312 | + return '_ee_rate_limit'; |
|
313 | + } |
|
314 | + |
|
315 | + |
|
316 | + /** |
|
317 | + * Returns the rate limit expiry time. |
|
318 | + * |
|
319 | + * @return int |
|
320 | + */ |
|
321 | + protected function _get_rate_limit_expiry() |
|
322 | + { |
|
323 | + return time() + (int) apply_filters('FHEE__EE_Messages_Queue__rate_limit_expiry', HOUR_IN_SECONDS); |
|
324 | + } |
|
325 | + |
|
326 | + |
|
327 | + /** |
|
328 | + * Returns the default rate limit for sending messages. |
|
329 | + * |
|
330 | + * @return int |
|
331 | + */ |
|
332 | + protected function _default_rate_limit() |
|
333 | + { |
|
334 | + return (int) apply_filters('FHEE__EE_Messages_Queue___rate_limit', 200); |
|
335 | + } |
|
336 | + |
|
337 | + |
|
338 | + /** |
|
339 | + * Return the orderby array for priority. |
|
340 | + * |
|
341 | + * @return array |
|
342 | + */ |
|
343 | + protected function _get_priority_orderby() |
|
344 | + { |
|
345 | + return array( |
|
346 | + 'MSG_priority' => 'ASC', |
|
347 | + 'MSG_modified' => 'DESC', |
|
348 | + ); |
|
349 | + } |
|
350 | + |
|
351 | + |
|
352 | + /** |
|
353 | + * Returns whether batch methods are "locked" or not. |
|
354 | + * |
|
355 | + * @param string $type The type of lock being checked for. |
|
356 | + * @return bool |
|
357 | + */ |
|
358 | + public function is_locked($type = EE_Messages_Queue::action_generating) |
|
359 | + { |
|
360 | + $lock = (int) get_option($this->_get_lock_key($type), 0); |
|
361 | + /** |
|
362 | + * This filters the default is_locked behaviour. |
|
363 | + */ |
|
364 | + $is_locked = filter_var( |
|
365 | + apply_filters( |
|
366 | + 'FHEE__EE_Messages_Queue__is_locked', |
|
367 | + $lock > time(), |
|
368 | + $this |
|
369 | + ), |
|
370 | + FILTER_VALIDATE_BOOLEAN |
|
371 | + ); |
|
372 | + |
|
373 | + /** |
|
374 | + * @see usage of this filter in EE_Messages_Queue::initiate_request_by_priority() method. |
|
375 | + * Also implemented here because messages processed on the same request should not have any locks applied. |
|
376 | + */ |
|
377 | + if ( |
|
378 | + apply_filters('FHEE__EE_Messages_Processor__initiate_request_by_priority__do_immediate_processing', false) |
|
379 | + || EE_Registry::instance()->NET_CFG->core->do_messages_on_same_request |
|
380 | + ) { |
|
381 | + $is_locked = false; |
|
382 | + } |
|
383 | + |
|
384 | + |
|
385 | + return $is_locked; |
|
386 | + } |
|
387 | + |
|
388 | + |
|
389 | + /** |
|
390 | + * Retrieves the rate limit that may be cached as a transient. |
|
391 | + * If the rate limit is not set, then this sets the default rate limit and expiry and returns it. |
|
392 | + * |
|
393 | + * @param bool $return_expiry If true then return the expiry time not the rate_limit. |
|
394 | + * @return int |
|
395 | + */ |
|
396 | + protected function get_rate_limit($return_expiry = false) |
|
397 | + { |
|
398 | + $stored_rate_info = get_option($this->_get_rate_limit_key(), array()); |
|
399 | + $rate_limit = isset($stored_rate_info[0]) |
|
400 | + ? (int) $stored_rate_info[0] |
|
401 | + : 0; |
|
402 | + $expiry = isset($stored_rate_info[1]) |
|
403 | + ? (int) $stored_rate_info[1] |
|
404 | + : 0; |
|
405 | + //set the default for tracking? |
|
406 | + if (empty($stored_rate_info) || time() > $expiry) { |
|
407 | + $expiry = $this->_get_rate_limit_expiry(); |
|
408 | + $rate_limit = $this->_default_rate_limit(); |
|
409 | + update_option($this->_get_rate_limit_key(), array($rate_limit, $expiry)); |
|
410 | + } |
|
411 | + return $return_expiry ? $expiry : $rate_limit; |
|
412 | + } |
|
413 | + |
|
414 | + |
|
415 | + /** |
|
416 | + * This updates existing rate limit with the new limit which is the old minus the batch. |
|
417 | + * |
|
418 | + * @param int $batch_completed This sets the new rate limit based on the given batch that was completed. |
|
419 | + */ |
|
420 | + protected function set_rate_limit($batch_completed) |
|
421 | + { |
|
422 | + //first get the most up to date rate limit (in case its expired and reset) |
|
423 | + $rate_limit = $this->get_rate_limit(); |
|
424 | + $expiry = $this->get_rate_limit(true); |
|
425 | + $new_limit = $rate_limit - $batch_completed; |
|
426 | + //updating the transient option directly to avoid resetting the expiry. |
|
427 | + |
|
428 | + update_option($this->_get_rate_limit_key(), array($new_limit, $expiry)); |
|
429 | + } |
|
430 | + |
|
431 | + |
|
432 | + /** |
|
433 | + * This method checks the queue for ANY EE_Message objects with a priority matching the given priority passed in. |
|
434 | + * If that exists, then we immediately initiate a non-blocking request to do the requested action type. |
|
435 | + * Note: Keep in mind that there is the possibility that the request will not execute if there is already another |
|
436 | + * request running on a queue for the given task. |
|
437 | + * |
|
438 | + * @param string $task This indicates what type of request is going to be initiated. |
|
439 | + * @param int $priority This indicates the priority that triggers initiating the request. |
|
440 | + */ |
|
441 | + public function initiate_request_by_priority($task = 'generate', $priority = EEM_Message::priority_high) |
|
442 | + { |
|
443 | + //determine what status is matched with the priority as part of the trigger conditions. |
|
444 | + $status = $task == 'generate' |
|
445 | + ? EEM_Message::status_incomplete |
|
446 | + : EEM_Message::instance()->stati_indicating_to_send(); |
|
447 | + // always make sure we save because either this will get executed immediately on a separate request |
|
448 | + // or remains in the queue for the regularly scheduled queue batch. |
|
449 | + $this->save(); |
|
450 | + /** |
|
451 | + * This filter/option allows users to override processing of messages on separate requests and instead have everything |
|
452 | + * happen on the same request. If this is utilized remember: |
|
453 | + * - message priorities don't matter |
|
454 | + * - existing unprocessed messages in the queue will not get processed unless manually triggered. |
|
455 | + * - things will be perceived to take longer to happen for end users (i.e. registrations) because of the additional |
|
456 | + * processing happening on the same request. |
|
457 | + * - any race condition protection (locks) are removed because they don't apply when things are processed on |
|
458 | + * the same request. |
|
459 | + */ |
|
460 | + if ( |
|
461 | + apply_filters('FHEE__EE_Messages_Processor__initiate_request_by_priority__do_immediate_processing', false) |
|
462 | + || EE_Registry::instance()->NET_CFG->core->do_messages_on_same_request |
|
463 | + ) { |
|
464 | + $messages_processor = EE_Registry::instance()->load_lib('Messages_Processor'); |
|
465 | + if ($messages_processor instanceof EE_Messages_Processor) { |
|
466 | + return $messages_processor->process_immediately_from_queue($this); |
|
467 | + } |
|
468 | + //if we get here then that means the messages processor couldn't be loaded so messages will just remain |
|
469 | + //queued for manual triggering by end user. |
|
470 | + } |
|
471 | + |
|
472 | + if ($this->_message_repository->count_by_priority_and_status($priority, $status)) { |
|
473 | + EE_Messages_Scheduler::initiate_scheduled_non_blocking_request($task); |
|
474 | + } |
|
475 | + } |
|
476 | + |
|
477 | + |
|
478 | + /** |
|
479 | + * Loops through the EE_Message objects in the _queue and calls the messenger send methods for each message. |
|
480 | + * |
|
481 | + * @param bool $save Used to indicate whether to save the message queue after sending |
|
482 | + * (default will save). |
|
483 | + * @param mixed $sending_messenger (optional) When the sending messenger is different than |
|
484 | + * what is on the EE_Message object in the queue. |
|
485 | + * For instance, showing the browser view of an email message, |
|
486 | + * or giving a pdf generated view of an html document. |
|
487 | + * This should be an instance of EE_messenger but if you call this |
|
488 | + * method |
|
489 | + * intending it to be a sending messenger but a valid one could not be |
|
490 | + * retrieved then send in an instance of EE_Error that contains the |
|
491 | + * related error message. |
|
492 | + * @param bool|int $by_priority When set, this indicates that only messages |
|
493 | + * matching the given priority should be executed. |
|
494 | + * @return int Number of messages sent. Note, 0 does not mean that no messages were processed. |
|
495 | + * Also, if the messenger is an request type messenger (or a preview), |
|
496 | + * its entirely possible that the messenger will exit before |
|
497 | + */ |
|
498 | + public function execute($save = true, $sending_messenger = null, $by_priority = false) |
|
499 | + { |
|
500 | + $messages_sent = 0; |
|
501 | + $this->_did_hook = array(); |
|
502 | + $this->_message_repository->rewind(); |
|
503 | + |
|
504 | + while ($this->_message_repository->valid()) { |
|
505 | + $error_messages = array(); |
|
506 | + /** @type EE_Message $message */ |
|
507 | + $message = $this->_message_repository->current(); |
|
508 | + //only process things that are queued for sending |
|
509 | + if (! in_array($message->STS_ID(), EEM_Message::instance()->stati_indicating_to_send())) { |
|
510 | + $this->_message_repository->next(); |
|
511 | + continue; |
|
512 | + } |
|
513 | + //if $by_priority is set and does not match then continue; |
|
514 | + if ($by_priority && $by_priority != $message->priority()) { |
|
515 | + $this->_message_repository->next(); |
|
516 | + continue; |
|
517 | + } |
|
518 | + //error checking |
|
519 | + if (! $message->valid_messenger()) { |
|
520 | + $error_messages[] = sprintf( |
|
521 | + __('The %s messenger is not active at time of sending.', 'event_espresso'), |
|
522 | + $message->messenger() |
|
523 | + ); |
|
524 | + } |
|
525 | + if (! $message->valid_message_type()) { |
|
526 | + $error_messages[] = sprintf( |
|
527 | + __('The %s message type is not active at the time of sending.', 'event_espresso'), |
|
528 | + $message->message_type() |
|
529 | + ); |
|
530 | + } |
|
531 | + // if there was supposed to be a sending messenger for this message, but it was invalid/inactive, |
|
532 | + // then it will instead be an EE_Error object, so let's check for that |
|
533 | + if ($sending_messenger instanceof EE_Error) { |
|
534 | + $error_messages[] = $sending_messenger->getMessage(); |
|
535 | + } |
|
536 | + // if there are no errors, then let's process the message |
|
537 | + if (empty($error_messages)) { |
|
538 | + if ($save) { |
|
539 | + $message->set_messenger_is_executing(); |
|
540 | + } |
|
541 | + if ($this->_process_message($message, $sending_messenger)) { |
|
542 | + $messages_sent++; |
|
543 | + } |
|
544 | + } |
|
545 | + $this->_set_error_message($message, $error_messages); |
|
546 | + //add modified time |
|
547 | + $message->set_modified(time()); |
|
548 | + //we save each message after its processed to make sure its status persists in case PHP times-out or runs |
|
549 | + //out of memory. @see https://events.codebasehq.com/projects/event-espresso/tickets/10281 |
|
550 | + if ($save) { |
|
551 | + $message->save(); |
|
552 | + } |
|
553 | + |
|
554 | + $this->_message_repository->next(); |
|
555 | + } |
|
556 | + if ($save) { |
|
557 | + $this->save(true); |
|
558 | + } |
|
559 | + return $messages_sent; |
|
560 | + } |
|
561 | + |
|
562 | + |
|
563 | + /** |
|
564 | + * _process_message |
|
565 | + * |
|
566 | + * @param EE_Message $message |
|
567 | + * @param mixed $sending_messenger (optional) |
|
568 | + * @return bool |
|
569 | + */ |
|
570 | + protected function _process_message(EE_Message $message, $sending_messenger = null) |
|
571 | + { |
|
572 | + // these *should* have been validated in the execute() method above |
|
573 | + $messenger = $message->messenger_object(); |
|
574 | + $message_type = $message->message_type_object(); |
|
575 | + //do actions for sending messenger if it differs from generating messenger and swap values. |
|
576 | + if ( |
|
577 | + $sending_messenger instanceof EE_messenger |
|
578 | + && $messenger instanceof EE_messenger |
|
579 | + && $sending_messenger->name != $messenger->name |
|
580 | + ) { |
|
581 | + $messenger->do_secondary_messenger_hooks($sending_messenger->name); |
|
582 | + $messenger = $sending_messenger; |
|
583 | + } |
|
584 | + // send using messenger, but double check objects |
|
585 | + if ($messenger instanceof EE_messenger && $message_type instanceof EE_message_type) { |
|
586 | + //set hook for message type (but only if not using another messenger to send). |
|
587 | + if ( ! isset($this->_did_hook[$message_type->name])) { |
|
588 | + $message_type->do_messenger_hooks($messenger); |
|
589 | + $this->_did_hook[$message_type->name] = 1; |
|
590 | + } |
|
591 | + //if preview then use preview method |
|
592 | + return $this->_message_repository->is_preview() |
|
593 | + ? $this->_do_preview($message, $messenger, $message_type, $this->_message_repository->is_test_send()) |
|
594 | + : $this->_do_send($message, $messenger, $message_type); |
|
595 | + } |
|
596 | + return false; |
|
597 | + } |
|
598 | + |
|
599 | + |
|
600 | + /** |
|
601 | + * The intention of this method is to count how many EE_Message objects |
|
602 | + * are in the queue with a given status. |
|
603 | + * Example usage: |
|
604 | + * After a caller calls the "EE_Message_Queue::execute()" method, the caller can check if there were any failed |
|
605 | + * sends by calling $queue->count_STS_in_queue( EEM_Message_Queue::status_failed ). |
|
606 | + * |
|
607 | + * @param array|string $status Stati to check for in queue |
|
608 | + * @return int Count of EE_Message's matching the given status. |
|
609 | + */ |
|
610 | + public function count_STS_in_queue($status) |
|
611 | + { |
|
612 | + $count = 0; |
|
613 | + $status = is_array($status) ? $status : array($status); |
|
614 | + $this->_message_repository->rewind(); |
|
615 | + foreach ($this->_message_repository as $message) { |
|
616 | + if (in_array($message->STS_ID(), $status)) { |
|
617 | + $count++; |
|
618 | + } |
|
619 | + } |
|
620 | + return $count; |
|
621 | + } |
|
622 | + |
|
623 | + |
|
624 | + /** |
|
625 | + * Executes the get_preview method on the provided messenger. |
|
626 | + * |
|
627 | + * @param EE_Message $message |
|
628 | + * @param EE_messenger $messenger |
|
629 | + * @param EE_message_type $message_type |
|
630 | + * @param $test_send |
|
631 | + * @return bool true means all went well, false means, not so much. |
|
632 | + */ |
|
633 | + protected function _do_preview( |
|
634 | + EE_Message $message, |
|
635 | + EE_messenger $messenger, |
|
636 | + EE_message_type $message_type, |
|
637 | + $test_send |
|
638 | + ) { |
|
639 | + if ($preview = $messenger->get_preview($message, $message_type, $test_send)) { |
|
640 | + if ( ! $test_send) { |
|
641 | + $message->set_content($preview); |
|
642 | + } |
|
643 | + $message->set_STS_ID(EEM_Message::status_sent); |
|
644 | + return true; |
|
645 | + } else { |
|
646 | + $message->set_STS_ID(EEM_Message::status_failed); |
|
647 | + return false; |
|
648 | + } |
|
649 | + } |
|
650 | + |
|
651 | + |
|
652 | + /** |
|
653 | + * Executes the send method on the provided messenger |
|
654 | + * EE_Messengers are expected to: |
|
655 | + * - return true if the send was successful. |
|
656 | + * - return false if the send was unsuccessful but can be tried again. |
|
657 | + * - throw an Exception if the send was unsuccessful and cannot be tried again. |
|
658 | + * |
|
659 | + * @param EE_Message $message |
|
660 | + * @param EE_messenger $messenger |
|
661 | + * @param EE_message_type $message_type |
|
662 | + * @return bool true means all went well, false means, not so much. |
|
663 | + */ |
|
664 | + protected function _do_send(EE_Message $message, EE_messenger $messenger, EE_message_type $message_type) |
|
665 | + { |
|
666 | + try { |
|
667 | + if ($messenger->send_message($message, $message_type)) { |
|
668 | + $message->set_STS_ID(EEM_Message::status_sent); |
|
669 | + return true; |
|
670 | + } else { |
|
671 | + $message->set_STS_ID(EEM_Message::status_retry); |
|
672 | + return false; |
|
673 | + } |
|
674 | + } catch (SendMessageException $e) { |
|
675 | + $message->set_STS_ID(EEM_Message::status_failed); |
|
676 | + $message->set_error_message($e->getMessage()); |
|
677 | + return false; |
|
678 | + } |
|
679 | + } |
|
680 | + |
|
681 | + |
|
682 | + /** |
|
683 | + * This sets any necessary error messages on the message object and its status to failed. |
|
684 | + * |
|
685 | + * @param EE_Message $message |
|
686 | + * @param array $error_messages the response from the messenger. |
|
687 | + */ |
|
688 | + protected function _set_error_message(EE_Message $message, $error_messages) |
|
689 | + { |
|
690 | + $error_messages = (array)$error_messages; |
|
691 | + if (in_array($message->STS_ID(), EEM_Message::instance()->stati_indicating_failed_sending())) { |
|
692 | + $notices = EE_Error::has_notices(); |
|
693 | + $error_messages[] = __( |
|
694 | + 'Messenger and Message Type were valid and active, but the messenger send method failed.', |
|
695 | + 'event_espresso' |
|
696 | + ); |
|
697 | + if ($notices === 1) { |
|
698 | + $notices = EE_Error::get_vanilla_notices(); |
|
699 | + $notices['errors'] = isset($notices['errors']) ? $notices['errors'] : array(); |
|
700 | + $error_messages[] = implode("\n", $notices['errors']); |
|
701 | + } |
|
702 | + } |
|
703 | + if (count($error_messages) > 0) { |
|
704 | + $msg = __('Message was not executed successfully.', 'event_espresso'); |
|
705 | + $msg = $msg . "\n" . implode("\n", $error_messages); |
|
706 | + $message->set_error_message($msg); |
|
707 | + } |
|
708 | + } |
|
709 | 709 | |
710 | 710 | } //end EE_Messages_Queue class |
@@ -1,7 +1,7 @@ discard block |
||
1 | 1 | <?php |
2 | 2 | use \EventEspresso\core\exceptions\SendMessageException; |
3 | 3 | |
4 | -if (! defined('EVENT_ESPRESSO_VERSION')) { |
|
4 | +if ( ! defined('EVENT_ESPRESSO_VERSION')) { |
|
5 | 5 | exit('No direct script access allowed'); |
6 | 6 | } |
7 | 7 | |
@@ -175,7 +175,7 @@ discard block |
||
175 | 175 | 'order_by' => $this->_get_priority_orderby(), |
176 | 176 | 'limit' => $this->_batch_count, |
177 | 177 | ); |
178 | - $messages = EEM_Message::instance()->get_all($query_args); |
|
178 | + $messages = EEM_Message::instance()->get_all($query_args); |
|
179 | 179 | |
180 | 180 | if ( ! $messages) { |
181 | 181 | return false; //nothing to generate |
@@ -286,7 +286,7 @@ discard block |
||
286 | 286 | */ |
287 | 287 | protected function _get_lock_key($type = EE_Messages_Queue::action_generating) |
288 | 288 | { |
289 | - return '_ee_lock_' . $type; |
|
289 | + return '_ee_lock_'.$type; |
|
290 | 290 | } |
291 | 291 | |
292 | 292 | |
@@ -506,7 +506,7 @@ discard block |
||
506 | 506 | /** @type EE_Message $message */ |
507 | 507 | $message = $this->_message_repository->current(); |
508 | 508 | //only process things that are queued for sending |
509 | - if (! in_array($message->STS_ID(), EEM_Message::instance()->stati_indicating_to_send())) { |
|
509 | + if ( ! in_array($message->STS_ID(), EEM_Message::instance()->stati_indicating_to_send())) { |
|
510 | 510 | $this->_message_repository->next(); |
511 | 511 | continue; |
512 | 512 | } |
@@ -516,13 +516,13 @@ discard block |
||
516 | 516 | continue; |
517 | 517 | } |
518 | 518 | //error checking |
519 | - if (! $message->valid_messenger()) { |
|
519 | + if ( ! $message->valid_messenger()) { |
|
520 | 520 | $error_messages[] = sprintf( |
521 | 521 | __('The %s messenger is not active at time of sending.', 'event_espresso'), |
522 | 522 | $message->messenger() |
523 | 523 | ); |
524 | 524 | } |
525 | - if (! $message->valid_message_type()) { |
|
525 | + if ( ! $message->valid_message_type()) { |
|
526 | 526 | $error_messages[] = sprintf( |
527 | 527 | __('The %s message type is not active at the time of sending.', 'event_espresso'), |
528 | 528 | $message->message_type() |
@@ -687,7 +687,7 @@ discard block |
||
687 | 687 | */ |
688 | 688 | protected function _set_error_message(EE_Message $message, $error_messages) |
689 | 689 | { |
690 | - $error_messages = (array)$error_messages; |
|
690 | + $error_messages = (array) $error_messages; |
|
691 | 691 | if (in_array($message->STS_ID(), EEM_Message::instance()->stati_indicating_failed_sending())) { |
692 | 692 | $notices = EE_Error::has_notices(); |
693 | 693 | $error_messages[] = __( |
@@ -702,7 +702,7 @@ discard block |
||
702 | 702 | } |
703 | 703 | if (count($error_messages) > 0) { |
704 | 704 | $msg = __('Message was not executed successfully.', 'event_espresso'); |
705 | - $msg = $msg . "\n" . implode("\n", $error_messages); |
|
705 | + $msg = $msg."\n".implode("\n", $error_messages); |
|
706 | 706 | $message->set_error_message($msg); |
707 | 707 | } |
708 | 708 | } |
@@ -101,7 +101,7 @@ |
||
101 | 101 | /** |
102 | 102 | * _get_table_filters |
103 | 103 | * |
104 | - * @return array |
|
104 | + * @return string[] |
|
105 | 105 | */ |
106 | 106 | protected function _get_table_filters() |
107 | 107 | { |
@@ -1,6 +1,6 @@ discard block |
||
1 | 1 | <?php |
2 | 2 | if (! defined('EVENT_ESPRESSO_VERSION')) { |
3 | - exit('NO direct script access allowed'); |
|
3 | + exit('NO direct script access allowed'); |
|
4 | 4 | } |
5 | 5 | |
6 | 6 | |
@@ -27,205 +27,205 @@ discard block |
||
27 | 27 | class Payment_Log_Admin_List_Table extends EE_Admin_List_Table |
28 | 28 | { |
29 | 29 | |
30 | - /** |
|
31 | - * @param \EE_Admin_Page $admin_page |
|
32 | - * @return Payment_Log_Admin_List_Table |
|
33 | - */ |
|
34 | - public function __construct($admin_page) |
|
35 | - { |
|
36 | - parent::__construct($admin_page); |
|
37 | - } |
|
38 | - |
|
39 | - |
|
40 | - |
|
41 | - /** |
|
42 | - * _setup_data |
|
43 | - * |
|
44 | - * @return void |
|
45 | - */ |
|
46 | - protected function _setup_data() |
|
47 | - { |
|
48 | - $this->_data = $this->_admin_page->get_payment_logs($this->_per_page, $this->_current_page); |
|
49 | - // if(isset($this->_req_data['status'] ) && $this->_req_data['status'] == 'trash'){ |
|
50 | - // $this->_data = $this->_admin_page->get_trashed_questions( $this->_per_page,$this->_current_page, FALSE ); |
|
51 | - // }else{ |
|
52 | - // $this->_data = $this->_admin_page->get_questions( $this->_per_page,$this->_current_page, FALSE ); |
|
53 | - // } |
|
54 | - $this->_all_data_count = $this->_admin_page->get_payment_logs($this->_per_page, $this->_current_page, true); |
|
55 | - add_action('AHEE__EE_Admin_List_Table__extra_tablenav__after_bottom_buttons', array($this, 'add_download_logs_checkbox')); |
|
56 | - } |
|
57 | - |
|
58 | - |
|
59 | - |
|
60 | - /** |
|
61 | - * add_download_logs_checkbox |
|
62 | - * adds a checkbox to the bottom of the list table, instead of at the top with the rest of the filters |
|
63 | - * |
|
64 | - * @return void |
|
65 | - */ |
|
66 | - public function add_download_logs_checkbox() |
|
67 | - { |
|
68 | - echo "<input type='submit' class='button-primary' id='download_results' name='download_results' value='" . __('Download Results', 'event_espresso') . "'>"; |
|
69 | - } |
|
70 | - |
|
71 | - |
|
72 | - |
|
73 | - /** |
|
74 | - * _set_properties |
|
75 | - * |
|
76 | - * @return void |
|
77 | - */ |
|
78 | - protected function _set_properties() |
|
79 | - { |
|
80 | - $this->_wp_list_args = array( |
|
81 | - 'singular' => __('payment log', 'event_espresso'), |
|
82 | - 'plural' => __('payment logs', 'event_espresso'), |
|
83 | - 'ajax' => true, //for now, |
|
84 | - 'screen' => $this->_admin_page->get_current_screen()->id, |
|
85 | - ); |
|
86 | - $this->_columns = array( |
|
87 | - 'cb' => '<input type="checkbox" />', |
|
88 | - 'id' => __('ID', 'event_espresso'), |
|
89 | - 'LOG_time' => __('Time', 'event_espresso'), |
|
90 | - 'PMD_ID' => __('Payment Method', 'event_espresso'), |
|
91 | - 'TXN_ID' => __('Transaction ID', 'event_espresso'), |
|
92 | - ); |
|
93 | - $this->_sortable_columns = array( |
|
94 | - 'LOG_time' => array('LOG_time' => true), |
|
95 | - ); |
|
96 | - $this->_hidden_columns = array(); |
|
97 | - } |
|
98 | - |
|
99 | - |
|
100 | - |
|
101 | - /** |
|
102 | - * _get_table_filters |
|
103 | - * |
|
104 | - * @return array |
|
105 | - */ |
|
106 | - protected function _get_table_filters() |
|
107 | - { |
|
108 | - $filters = array(); |
|
109 | - //todo we're currently using old functions here. We need to move things into the Events_Admin_Page() class as methods. |
|
110 | - $payment_methods = EEM_Payment_Method::instance()->get_all(); |
|
111 | - $payment_method_names = array(array('id' => 'all', 'text' => __("All", 'event_espresso')), array('id' => '0', 'text' => __("Unknown Payment Method", 'event_espresso'))); |
|
112 | - foreach ($payment_methods as $payment_method) { |
|
113 | - $payment_method_names[] = array('id' => $payment_method->ID(), 'text' => $payment_method->admin_name()); |
|
114 | - } |
|
115 | - $filters[] = EEH_Form_Fields::select_input('_payment_method', $payment_method_names, isset($this->_req_data['_payment_method']) ? $this->_req_data['_payment_method'] : 'all'); |
|
116 | - $start_date = isset($this->_req_data['payment-filter-start-date']) ? wp_strip_all_tags($this->_req_data['payment-filter-start-date']) : date('m/d/Y', strtotime('-6 months')); |
|
117 | - $end_date = isset($this->_req_data['payment-filter-end-date']) ? wp_strip_all_tags($this->_req_data['payment-filter-end-date']) : date('m/d/Y'); |
|
118 | - ob_start(); |
|
119 | - ?> |
|
30 | + /** |
|
31 | + * @param \EE_Admin_Page $admin_page |
|
32 | + * @return Payment_Log_Admin_List_Table |
|
33 | + */ |
|
34 | + public function __construct($admin_page) |
|
35 | + { |
|
36 | + parent::__construct($admin_page); |
|
37 | + } |
|
38 | + |
|
39 | + |
|
40 | + |
|
41 | + /** |
|
42 | + * _setup_data |
|
43 | + * |
|
44 | + * @return void |
|
45 | + */ |
|
46 | + protected function _setup_data() |
|
47 | + { |
|
48 | + $this->_data = $this->_admin_page->get_payment_logs($this->_per_page, $this->_current_page); |
|
49 | + // if(isset($this->_req_data['status'] ) && $this->_req_data['status'] == 'trash'){ |
|
50 | + // $this->_data = $this->_admin_page->get_trashed_questions( $this->_per_page,$this->_current_page, FALSE ); |
|
51 | + // }else{ |
|
52 | + // $this->_data = $this->_admin_page->get_questions( $this->_per_page,$this->_current_page, FALSE ); |
|
53 | + // } |
|
54 | + $this->_all_data_count = $this->_admin_page->get_payment_logs($this->_per_page, $this->_current_page, true); |
|
55 | + add_action('AHEE__EE_Admin_List_Table__extra_tablenav__after_bottom_buttons', array($this, 'add_download_logs_checkbox')); |
|
56 | + } |
|
57 | + |
|
58 | + |
|
59 | + |
|
60 | + /** |
|
61 | + * add_download_logs_checkbox |
|
62 | + * adds a checkbox to the bottom of the list table, instead of at the top with the rest of the filters |
|
63 | + * |
|
64 | + * @return void |
|
65 | + */ |
|
66 | + public function add_download_logs_checkbox() |
|
67 | + { |
|
68 | + echo "<input type='submit' class='button-primary' id='download_results' name='download_results' value='" . __('Download Results', 'event_espresso') . "'>"; |
|
69 | + } |
|
70 | + |
|
71 | + |
|
72 | + |
|
73 | + /** |
|
74 | + * _set_properties |
|
75 | + * |
|
76 | + * @return void |
|
77 | + */ |
|
78 | + protected function _set_properties() |
|
79 | + { |
|
80 | + $this->_wp_list_args = array( |
|
81 | + 'singular' => __('payment log', 'event_espresso'), |
|
82 | + 'plural' => __('payment logs', 'event_espresso'), |
|
83 | + 'ajax' => true, //for now, |
|
84 | + 'screen' => $this->_admin_page->get_current_screen()->id, |
|
85 | + ); |
|
86 | + $this->_columns = array( |
|
87 | + 'cb' => '<input type="checkbox" />', |
|
88 | + 'id' => __('ID', 'event_espresso'), |
|
89 | + 'LOG_time' => __('Time', 'event_espresso'), |
|
90 | + 'PMD_ID' => __('Payment Method', 'event_espresso'), |
|
91 | + 'TXN_ID' => __('Transaction ID', 'event_espresso'), |
|
92 | + ); |
|
93 | + $this->_sortable_columns = array( |
|
94 | + 'LOG_time' => array('LOG_time' => true), |
|
95 | + ); |
|
96 | + $this->_hidden_columns = array(); |
|
97 | + } |
|
98 | + |
|
99 | + |
|
100 | + |
|
101 | + /** |
|
102 | + * _get_table_filters |
|
103 | + * |
|
104 | + * @return array |
|
105 | + */ |
|
106 | + protected function _get_table_filters() |
|
107 | + { |
|
108 | + $filters = array(); |
|
109 | + //todo we're currently using old functions here. We need to move things into the Events_Admin_Page() class as methods. |
|
110 | + $payment_methods = EEM_Payment_Method::instance()->get_all(); |
|
111 | + $payment_method_names = array(array('id' => 'all', 'text' => __("All", 'event_espresso')), array('id' => '0', 'text' => __("Unknown Payment Method", 'event_espresso'))); |
|
112 | + foreach ($payment_methods as $payment_method) { |
|
113 | + $payment_method_names[] = array('id' => $payment_method->ID(), 'text' => $payment_method->admin_name()); |
|
114 | + } |
|
115 | + $filters[] = EEH_Form_Fields::select_input('_payment_method', $payment_method_names, isset($this->_req_data['_payment_method']) ? $this->_req_data['_payment_method'] : 'all'); |
|
116 | + $start_date = isset($this->_req_data['payment-filter-start-date']) ? wp_strip_all_tags($this->_req_data['payment-filter-start-date']) : date('m/d/Y', strtotime('-6 months')); |
|
117 | + $end_date = isset($this->_req_data['payment-filter-end-date']) ? wp_strip_all_tags($this->_req_data['payment-filter-end-date']) : date('m/d/Y'); |
|
118 | + ob_start(); |
|
119 | + ?> |
|
120 | 120 | <label for="txn-filter-start-date"><?php _e('Display Transactions from ', 'event_espresso'); ?></label> |
121 | 121 | <input id="payment-filter-start-date" class="datepicker" type="text" value="<?php echo $start_date; ?>" name="payment-filter-start-date" size="15"/> |
122 | 122 | <label for="txn-filter-end-date"><?php _e(' until ', 'event_espresso'); ?></label> |
123 | 123 | <input id="payment-filter-end-date" class="datepicker" type="text" value="<?php echo $end_date; ?>" name="payment-filter-end-date" size="15"/> |
124 | 124 | <?php |
125 | - $filters[] = ob_get_clean(); |
|
126 | - return $filters; |
|
127 | - } |
|
128 | - |
|
129 | - |
|
130 | - |
|
131 | - /** |
|
132 | - * _add_view_counts |
|
133 | - * |
|
134 | - * @return void |
|
135 | - */ |
|
136 | - protected function _add_view_counts() |
|
137 | - { |
|
138 | - $this->_views['all']['count'] = $this->_admin_page->get_payment_logs($this->_per_page, $this->_current_page, true); |
|
139 | - } |
|
140 | - |
|
141 | - |
|
142 | - |
|
143 | - /** |
|
144 | - * column_cb |
|
145 | - * |
|
146 | - * @param \EE_Change_Log $item |
|
147 | - * @return string |
|
148 | - */ |
|
149 | - public function column_cb($item) |
|
150 | - { |
|
151 | - return sprintf('<input type="checkbox" class="option_id" name="checkbox[%1$d]" value="%1$d" />', $item->ID()); |
|
152 | - } |
|
153 | - |
|
154 | - |
|
155 | - |
|
156 | - /** |
|
157 | - * column_id |
|
158 | - * |
|
159 | - * @param \EE_Change_Log $item |
|
160 | - * @return string |
|
161 | - */ |
|
162 | - public function column_id(EE_Change_Log $item) |
|
163 | - { |
|
164 | - $details_query_args = array( |
|
165 | - 'action' => 'payment_log_details', |
|
166 | - 'ID' => $item->ID(), |
|
167 | - ); |
|
168 | - $url = EE_Admin_Page::add_query_args_and_nonce($details_query_args, EE_PAYMENTS_ADMIN_URL); |
|
169 | - return "<a href='$url'>{$item->ID()}</a>"; |
|
170 | - } |
|
171 | - |
|
172 | - |
|
173 | - |
|
174 | - /** |
|
175 | - * column_LOG_time |
|
176 | - * |
|
177 | - * @param \EE_Change_Log $item |
|
178 | - * @return string |
|
179 | - */ |
|
180 | - public function column_LOG_time(EE_Change_Log $item) |
|
181 | - { |
|
182 | - return $item->get_datetime('LOG_time'); |
|
183 | - } |
|
184 | - |
|
185 | - |
|
186 | - |
|
187 | - /** |
|
188 | - * column_PMD_ID |
|
189 | - * |
|
190 | - * @param \EE_Change_Log $item |
|
191 | - * @return string |
|
192 | - */ |
|
193 | - public function column_PMD_ID(EE_Change_Log $item) |
|
194 | - { |
|
195 | - if ($item->object() instanceof EE_Payment_Method) { |
|
196 | - return $item->object()->admin_name(); |
|
197 | - } elseif ($item->object() instanceof EE_Payment && $item->object()->payment_method()) { |
|
198 | - return $item->object()->payment_method()->admin_name(); |
|
199 | - } else { |
|
200 | - return __("No longer exists", 'event_espresso'); |
|
201 | - } |
|
202 | - } |
|
203 | - |
|
204 | - |
|
205 | - |
|
206 | - /** |
|
207 | - * column_TXN_ID |
|
208 | - * |
|
209 | - * @param \EE_Change_Log $item |
|
210 | - * @return string |
|
211 | - */ |
|
212 | - public function column_TXN_ID(EE_Change_Log $item) |
|
213 | - { |
|
214 | - if ($item->object() instanceof EE_Payment) { |
|
215 | - if (EE_Registry::instance()->CAP->current_user_can('ee_read_transaction', 'espresso_transactions_view_transaction', $item->object()->TXN_ID())) { |
|
216 | - $view_txn_lnk_url = EE_Admin_Page::add_query_args_and_nonce(array('action' => 'view_transaction', 'TXN_ID' => $item->object()->TXN_ID()), TXN_ADMIN_URL); |
|
217 | - return '<a href="' |
|
218 | - . $view_txn_lnk_url |
|
219 | - . '" title="' |
|
220 | - . sprintf(esc_attr__('click to view transaction #%s', 'event_espresso'), $item->object()->TXN_ID()) |
|
221 | - . '">' |
|
222 | - . sprintf(__('view txn %s', 'event_espresso'), $item->object()->TXN_ID()) |
|
223 | - . '</a>'; |
|
224 | - } |
|
225 | - } else { |
|
226 | - return __("Unable to find transaction", 'event_espresso'); |
|
227 | - } |
|
228 | - } |
|
125 | + $filters[] = ob_get_clean(); |
|
126 | + return $filters; |
|
127 | + } |
|
128 | + |
|
129 | + |
|
130 | + |
|
131 | + /** |
|
132 | + * _add_view_counts |
|
133 | + * |
|
134 | + * @return void |
|
135 | + */ |
|
136 | + protected function _add_view_counts() |
|
137 | + { |
|
138 | + $this->_views['all']['count'] = $this->_admin_page->get_payment_logs($this->_per_page, $this->_current_page, true); |
|
139 | + } |
|
140 | + |
|
141 | + |
|
142 | + |
|
143 | + /** |
|
144 | + * column_cb |
|
145 | + * |
|
146 | + * @param \EE_Change_Log $item |
|
147 | + * @return string |
|
148 | + */ |
|
149 | + public function column_cb($item) |
|
150 | + { |
|
151 | + return sprintf('<input type="checkbox" class="option_id" name="checkbox[%1$d]" value="%1$d" />', $item->ID()); |
|
152 | + } |
|
153 | + |
|
154 | + |
|
155 | + |
|
156 | + /** |
|
157 | + * column_id |
|
158 | + * |
|
159 | + * @param \EE_Change_Log $item |
|
160 | + * @return string |
|
161 | + */ |
|
162 | + public function column_id(EE_Change_Log $item) |
|
163 | + { |
|
164 | + $details_query_args = array( |
|
165 | + 'action' => 'payment_log_details', |
|
166 | + 'ID' => $item->ID(), |
|
167 | + ); |
|
168 | + $url = EE_Admin_Page::add_query_args_and_nonce($details_query_args, EE_PAYMENTS_ADMIN_URL); |
|
169 | + return "<a href='$url'>{$item->ID()}</a>"; |
|
170 | + } |
|
171 | + |
|
172 | + |
|
173 | + |
|
174 | + /** |
|
175 | + * column_LOG_time |
|
176 | + * |
|
177 | + * @param \EE_Change_Log $item |
|
178 | + * @return string |
|
179 | + */ |
|
180 | + public function column_LOG_time(EE_Change_Log $item) |
|
181 | + { |
|
182 | + return $item->get_datetime('LOG_time'); |
|
183 | + } |
|
184 | + |
|
185 | + |
|
186 | + |
|
187 | + /** |
|
188 | + * column_PMD_ID |
|
189 | + * |
|
190 | + * @param \EE_Change_Log $item |
|
191 | + * @return string |
|
192 | + */ |
|
193 | + public function column_PMD_ID(EE_Change_Log $item) |
|
194 | + { |
|
195 | + if ($item->object() instanceof EE_Payment_Method) { |
|
196 | + return $item->object()->admin_name(); |
|
197 | + } elseif ($item->object() instanceof EE_Payment && $item->object()->payment_method()) { |
|
198 | + return $item->object()->payment_method()->admin_name(); |
|
199 | + } else { |
|
200 | + return __("No longer exists", 'event_espresso'); |
|
201 | + } |
|
202 | + } |
|
203 | + |
|
204 | + |
|
205 | + |
|
206 | + /** |
|
207 | + * column_TXN_ID |
|
208 | + * |
|
209 | + * @param \EE_Change_Log $item |
|
210 | + * @return string |
|
211 | + */ |
|
212 | + public function column_TXN_ID(EE_Change_Log $item) |
|
213 | + { |
|
214 | + if ($item->object() instanceof EE_Payment) { |
|
215 | + if (EE_Registry::instance()->CAP->current_user_can('ee_read_transaction', 'espresso_transactions_view_transaction', $item->object()->TXN_ID())) { |
|
216 | + $view_txn_lnk_url = EE_Admin_Page::add_query_args_and_nonce(array('action' => 'view_transaction', 'TXN_ID' => $item->object()->TXN_ID()), TXN_ADMIN_URL); |
|
217 | + return '<a href="' |
|
218 | + . $view_txn_lnk_url |
|
219 | + . '" title="' |
|
220 | + . sprintf(esc_attr__('click to view transaction #%s', 'event_espresso'), $item->object()->TXN_ID()) |
|
221 | + . '">' |
|
222 | + . sprintf(__('view txn %s', 'event_espresso'), $item->object()->TXN_ID()) |
|
223 | + . '</a>'; |
|
224 | + } |
|
225 | + } else { |
|
226 | + return __("Unable to find transaction", 'event_espresso'); |
|
227 | + } |
|
228 | + } |
|
229 | 229 | |
230 | 230 | |
231 | 231 |
@@ -1,5 +1,5 @@ discard block |
||
1 | 1 | <?php |
2 | -if (! defined('EVENT_ESPRESSO_VERSION')) { |
|
2 | +if ( ! defined('EVENT_ESPRESSO_VERSION')) { |
|
3 | 3 | exit('NO direct script access allowed'); |
4 | 4 | } |
5 | 5 | |
@@ -65,7 +65,7 @@ discard block |
||
65 | 65 | */ |
66 | 66 | public function add_download_logs_checkbox() |
67 | 67 | { |
68 | - echo "<input type='submit' class='button-primary' id='download_results' name='download_results' value='" . __('Download Results', 'event_espresso') . "'>"; |
|
68 | + echo "<input type='submit' class='button-primary' id='download_results' name='download_results' value='".__('Download Results', 'event_espresso')."'>"; |
|
69 | 69 | } |
70 | 70 | |
71 | 71 |
@@ -2,11 +2,9 @@ |
||
2 | 2 | namespace EventEspresso\core\libraries\rest_api; |
3 | 3 | |
4 | 4 | use DomainException; |
5 | -use EE_Capabilities; |
|
6 | 5 | use EE_Datetime_Field; |
7 | 6 | use EE_Error; |
8 | 7 | use EE_Infinite_Integer_Field; |
9 | -use EE_Maybe_Serialized_Simple_HTML_Field; |
|
10 | 8 | use EE_Model_Field_Base; |
11 | 9 | use EE_Serialized_Text_Field; |
12 | 10 | use EEM_Base; |
@@ -12,7 +12,7 @@ discard block |
||
12 | 12 | use EEM_Base; |
13 | 13 | |
14 | 14 | if (! defined('EVENT_ESPRESSO_VERSION')) { |
15 | - exit('No direct script access allowed'); |
|
15 | + exit('No direct script access allowed'); |
|
16 | 16 | } |
17 | 17 | |
18 | 18 | |
@@ -37,837 +37,837 @@ discard block |
||
37 | 37 | class ModelDataTranslator |
38 | 38 | { |
39 | 39 | |
40 | - /** |
|
41 | - * We used to use -1 for infinity in the rest api, but that's ambiguous for |
|
42 | - * fields that COULD contain -1; so we use null |
|
43 | - */ |
|
44 | - const EE_INF_IN_REST = null; |
|
45 | - |
|
46 | - |
|
47 | - |
|
48 | - /** |
|
49 | - * Prepares a possible array of input values from JSON for use by the models |
|
50 | - * |
|
51 | - * @param EE_Model_Field_Base $field_obj |
|
52 | - * @param mixed $original_value_maybe_array |
|
53 | - * @param string $requested_version |
|
54 | - * @param string $timezone_string treat values as being in this timezone |
|
55 | - * @return mixed |
|
56 | - * @throws RestException |
|
57 | - */ |
|
58 | - public static function prepareFieldValuesFromJson( |
|
59 | - $field_obj, |
|
60 | - $original_value_maybe_array, |
|
61 | - $requested_version, |
|
62 | - $timezone_string = 'UTC' |
|
63 | - ) { |
|
64 | - if (is_array($original_value_maybe_array) |
|
65 | - && ! $field_obj instanceof EE_Serialized_Text_Field |
|
66 | - ) { |
|
67 | - $new_value_maybe_array = array(); |
|
68 | - foreach ($original_value_maybe_array as $array_key => $array_item) { |
|
69 | - $new_value_maybe_array[$array_key] = ModelDataTranslator::prepareFieldValueFromJson( |
|
70 | - $field_obj, |
|
71 | - $array_item, |
|
72 | - $requested_version, |
|
73 | - $timezone_string |
|
74 | - ); |
|
75 | - } |
|
76 | - } else { |
|
77 | - $new_value_maybe_array = ModelDataTranslator::prepareFieldValueFromJson( |
|
78 | - $field_obj, |
|
79 | - $original_value_maybe_array, |
|
80 | - $requested_version, |
|
81 | - $timezone_string |
|
82 | - ); |
|
83 | - } |
|
84 | - return $new_value_maybe_array; |
|
85 | - } |
|
86 | - |
|
87 | - |
|
88 | - |
|
89 | - /** |
|
90 | - * Prepares an array of field values FOR use in JSON/REST API |
|
91 | - * |
|
92 | - * @param EE_Model_Field_Base $field_obj |
|
93 | - * @param mixed $original_value_maybe_array |
|
94 | - * @param string $request_version (eg 4.8.36) |
|
95 | - * @return array |
|
96 | - */ |
|
97 | - public static function prepareFieldValuesForJson($field_obj, $original_value_maybe_array, $request_version) |
|
98 | - { |
|
99 | - if (is_array($original_value_maybe_array)) { |
|
100 | - $new_value = array(); |
|
101 | - foreach ($original_value_maybe_array as $key => $value) { |
|
102 | - $new_value[$key] = ModelDataTranslator::prepareFieldValuesForJson($field_obj, $value, $request_version); |
|
103 | - } |
|
104 | - } else { |
|
105 | - $new_value = ModelDataTranslator::prepareFieldValueForJson( |
|
106 | - $field_obj, |
|
107 | - $original_value_maybe_array, |
|
108 | - $request_version |
|
109 | - ); |
|
110 | - } |
|
111 | - return $new_value; |
|
112 | - } |
|
113 | - |
|
114 | - |
|
115 | - /** |
|
116 | - * Prepares incoming data from the json or $_REQUEST parameters for the models' |
|
117 | - * "$query_params". |
|
118 | - * |
|
119 | - * @param EE_Model_Field_Base $field_obj |
|
120 | - * @param mixed $original_value |
|
121 | - * @param string $requested_version |
|
122 | - * @param string $timezone_string treat values as being in this timezone |
|
123 | - * @return mixed |
|
124 | - * @throws RestException |
|
125 | - * @throws DomainException |
|
126 | - * @throws EE_Error |
|
127 | - */ |
|
128 | - public static function prepareFieldValueFromJson( |
|
129 | - $field_obj, |
|
130 | - $original_value, |
|
131 | - $requested_version, |
|
132 | - $timezone_string = 'UTC' // UTC |
|
133 | - ) { |
|
134 | - //check if they accidentally submitted an error value. If so throw an exception |
|
135 | - if (is_array($original_value) |
|
136 | - && isset($original_value['error_code'], $original_value['error_message'])) { |
|
137 | - throw new RestException( |
|
138 | - 'rest_submitted_error_value', |
|
139 | - sprintf( |
|
140 | - esc_html__( |
|
141 | - 'You tried to submit a JSON error object as a value for %1$s. That\'s not allowed.', |
|
142 | - 'event_espresso' |
|
143 | - ), |
|
144 | - $field_obj->get_name() |
|
145 | - ), |
|
146 | - array( |
|
147 | - 'status' => 400, |
|
148 | - ) |
|
149 | - ); |
|
150 | - } |
|
151 | - //double-check for serialized PHP. We never accept serialized PHP. No way Jose. |
|
152 | - ModelDataTranslator::throwExceptionIfContainsSerializedData($original_value); |
|
153 | - $timezone_string = $timezone_string !== '' ? $timezone_string : get_option('timezone_string', ''); |
|
154 | - $new_value = null; |
|
155 | - //walk through the submitted data and double-check for serialized PHP. We never accept serialized PHP. No |
|
156 | - // way Jose. |
|
157 | - ModelDataTranslator::throwExceptionIfContainsSerializedData($original_value); |
|
158 | - if ($field_obj instanceof EE_Infinite_Integer_Field |
|
159 | - && in_array($original_value, array(null, ''), true) |
|
160 | - ) { |
|
161 | - $new_value = EE_INF; |
|
162 | - } elseif ($field_obj instanceof EE_Datetime_Field) { |
|
163 | - $new_value = rest_parse_date( |
|
164 | - self::getTimestampWithTimezoneOffset($original_value, $field_obj, $timezone_string) |
|
165 | - ); |
|
166 | - if ($new_value === false) { |
|
167 | - throw new RestException( |
|
168 | - 'invalid_format_for_timestamp', |
|
169 | - sprintf( |
|
170 | - esc_html__( |
|
171 | - 'Timestamps received on a request as the value for Date and Time fields must be in %1$s/%2$s format. The timestamp provided (%3$s) is not that format.', |
|
172 | - 'event_espresso' |
|
173 | - ), |
|
174 | - 'RFC3339', |
|
175 | - 'ISO8601', |
|
176 | - $original_value |
|
177 | - ), |
|
178 | - array( |
|
179 | - 'status' => 400 |
|
180 | - ) |
|
181 | - ); |
|
182 | - } |
|
183 | - } else { |
|
184 | - $new_value = $original_value; |
|
185 | - } |
|
186 | - return $new_value; |
|
187 | - } |
|
188 | - |
|
189 | - |
|
190 | - /** |
|
191 | - * This checks if the incoming timestamp has timezone information already on it and if it doesn't then adds timezone |
|
192 | - * information via details obtained from the host site. |
|
193 | - * |
|
194 | - * @param string $original_timestamp |
|
195 | - * @param EE_Datetime_Field $datetime_field |
|
196 | - * @param $timezone_string |
|
197 | - * @return string |
|
198 | - * @throws DomainException |
|
199 | - */ |
|
200 | - private static function getTimestampWithTimezoneOffset( |
|
201 | - $original_timestamp, |
|
202 | - EE_Datetime_Field $datetime_field, |
|
203 | - $timezone_string |
|
204 | - ) { |
|
205 | - //already have timezone information? |
|
206 | - if (preg_match('/Z|(\+|\-)(\d{2}:\d{2})/', $original_timestamp)) { |
|
207 | - //yes, we're ignoring the timezone. |
|
208 | - return $original_timestamp; |
|
209 | - } |
|
210 | - //need to append timezone |
|
211 | - list($offset_sign, $offset_secs) = self::parseTimezoneOffset( |
|
212 | - $datetime_field->get_timezone_offset( |
|
213 | - new \DateTimeZone($timezone_string), |
|
214 | - $original_timestamp |
|
215 | - ) |
|
216 | - ); |
|
217 | - $offset_string = |
|
218 | - str_pad( |
|
219 | - floor($offset_secs / HOUR_IN_SECONDS), |
|
220 | - 2, |
|
221 | - '0', |
|
222 | - STR_PAD_LEFT |
|
223 | - ) |
|
224 | - . ':' |
|
225 | - . str_pad( |
|
226 | - ($offset_secs % HOUR_IN_SECONDS) / MINUTE_IN_SECONDS, |
|
227 | - 2, |
|
228 | - '0', |
|
229 | - STR_PAD_LEFT |
|
230 | - ); |
|
231 | - return $original_timestamp . $offset_sign . $offset_string; |
|
232 | - } |
|
233 | - |
|
234 | - |
|
235 | - |
|
236 | - /** |
|
237 | - * Throws an exception if $data is a serialized PHP string (or somehow an actually PHP object, although I don't |
|
238 | - * think that can happen). If $data is an array, recurses into its keys and values |
|
239 | - * @param mixed $data |
|
240 | - * @throws RestException |
|
241 | - * @return void |
|
242 | - */ |
|
243 | - public static function throwExceptionIfContainsSerializedData($data) |
|
244 | - { |
|
245 | - if (is_array($data)) { |
|
246 | - foreach ($data as $key => $value) { |
|
247 | - ModelDataTranslator::throwExceptionIfContainsSerializedData($key); |
|
248 | - ModelDataTranslator::throwExceptionIfContainsSerializedData($value); |
|
249 | - } |
|
250 | - } else { |
|
251 | - if (is_serialized($data) || is_object($data)) { |
|
252 | - throw new RestException( |
|
253 | - 'serialized_data_submission_prohibited', |
|
254 | - esc_html__( |
|
255 | - // @codingStandardsIgnoreStart |
|
256 | - 'You tried to submit a string of serialized text. Serialized PHP is prohibited over the EE4 REST API.', |
|
257 | - // @codingStandardsIgnoreEnd |
|
258 | - 'event_espresso' |
|
259 | - ) |
|
260 | - ); |
|
261 | - } |
|
262 | - } |
|
263 | - } |
|
264 | - |
|
265 | - |
|
266 | - |
|
267 | - /** |
|
268 | - * determines what's going on with them timezone strings |
|
269 | - * |
|
270 | - * @param int $timezone_offset |
|
271 | - * @return array |
|
272 | - */ |
|
273 | - private static function parseTimezoneOffset($timezone_offset) |
|
274 | - { |
|
275 | - $first_char = substr((string)$timezone_offset, 0, 1); |
|
276 | - if ($first_char === '+' || $first_char === '-') { |
|
277 | - $offset_sign = $first_char; |
|
278 | - $offset_secs = substr((string)$timezone_offset, 1); |
|
279 | - } else { |
|
280 | - $offset_sign = '+'; |
|
281 | - $offset_secs = $timezone_offset; |
|
282 | - } |
|
283 | - return array($offset_sign, $offset_secs); |
|
284 | - } |
|
285 | - |
|
286 | - |
|
287 | - |
|
288 | - /** |
|
289 | - * Prepares a field's value for display in the API |
|
290 | - * |
|
291 | - * @param EE_Model_Field_Base $field_obj |
|
292 | - * @param mixed $original_value |
|
293 | - * @param string $requested_version |
|
294 | - * @return mixed |
|
295 | - */ |
|
296 | - public static function prepareFieldValueForJson($field_obj, $original_value, $requested_version) |
|
297 | - { |
|
298 | - if ($original_value === EE_INF) { |
|
299 | - $new_value = ModelDataTranslator::EE_INF_IN_REST; |
|
300 | - } elseif ($field_obj instanceof EE_Datetime_Field) { |
|
301 | - if (is_string($original_value)) { |
|
302 | - //did they submit a string of a unix timestamp? |
|
303 | - if (is_numeric($original_value)) { |
|
304 | - $datetime_obj = new \DateTime(); |
|
305 | - $datetime_obj->setTimestamp((int)$original_value); |
|
306 | - } else { |
|
307 | - //first, check if its a MySQL timestamp in GMT |
|
308 | - $datetime_obj = \DateTime::createFromFormat('Y-m-d H:i:s', $original_value); |
|
309 | - } |
|
310 | - if (! $datetime_obj instanceof \DateTime) { |
|
311 | - //so it's not a unix timestamp or a MySQL timestamp. Maybe its in the field's date/time format? |
|
312 | - $datetime_obj = $field_obj->prepare_for_set($original_value); |
|
313 | - } |
|
314 | - $original_value = $datetime_obj; |
|
315 | - } |
|
316 | - if ($original_value instanceof \DateTime) { |
|
317 | - $new_value = $original_value->format('Y-m-d H:i:s'); |
|
318 | - } elseif (is_int($original_value) || is_float($original_value)) { |
|
319 | - $new_value = date('Y-m-d H:i:s', $original_value); |
|
320 | - } elseif($original_value === null || $original_value === '') { |
|
321 | - $new_value = null; |
|
322 | - } else { |
|
323 | - //so it's not a datetime object, unix timestamp (as string or int), |
|
324 | - //MySQL timestamp, or even a string in the field object's format. So no idea what it is |
|
325 | - throw new \EE_Error( |
|
326 | - sprintf( |
|
327 | - esc_html__( |
|
328 | - // @codingStandardsIgnoreStart |
|
329 | - 'The value "%1$s" for the field "%2$s" on model "%3$s" could not be understood. It should be a PHP DateTime, unix timestamp, MySQL date, or string in the format "%4$s".', |
|
330 | - // @codingStandardsIgnoreEnd |
|
331 | - 'event_espressso' |
|
332 | - ), |
|
333 | - $original_value, |
|
334 | - $field_obj->get_name(), |
|
335 | - $field_obj->get_model_name(), |
|
336 | - $field_obj->get_time_format() . ' ' . $field_obj->get_time_format() |
|
337 | - ) |
|
338 | - ); |
|
339 | - } |
|
340 | - $new_value = mysql_to_rfc3339($new_value); |
|
341 | - } else { |
|
342 | - $new_value = $original_value; |
|
343 | - } |
|
344 | - //are we about to send an object? just don't. We have no good way to represent it in JSON. |
|
345 | - // can't just check using is_object() because that missed PHP incomplete objects |
|
346 | - if (! ModelDataTranslator::isRepresentableInJson($new_value)) { |
|
347 | - $new_value = array( |
|
348 | - 'error_code' => 'php_object_not_return', |
|
349 | - 'error_message' => esc_html__('The value of this field in the database is a PHP object, which can\'t be represented in JSON.', 'event_espresso') |
|
350 | - ); |
|
351 | - } |
|
352 | - return apply_filters( |
|
353 | - 'FHEE__EventEspresso\core\libraries\rest_api\Model_Data_Translator__prepare_field_for_rest_api', |
|
354 | - $new_value, |
|
355 | - $field_obj, |
|
356 | - $original_value, |
|
357 | - $requested_version |
|
358 | - ); |
|
359 | - } |
|
360 | - |
|
361 | - |
|
362 | - |
|
363 | - /** |
|
364 | - * Prepares condition-query-parameters (like what's in where and having) from |
|
365 | - * the format expected in the API to use in the models |
|
366 | - * |
|
367 | - * @param array $inputted_query_params_of_this_type |
|
368 | - * @param EEM_Base $model |
|
369 | - * @param string $requested_version |
|
370 | - * @param boolean $writing whether this data will be written to the DB, or if we're just building a query. |
|
371 | - * If we're writing to the DB, we don't expect any operators, or any logic query parameters, |
|
372 | - * and we also won't accept serialized data unless the current user has unfiltered_html. |
|
373 | - * @return array |
|
374 | - * @throws DomainException |
|
375 | - * @throws RestException |
|
376 | - * @throws EE_Error |
|
377 | - */ |
|
378 | - public static function prepareConditionsQueryParamsForModels( |
|
379 | - $inputted_query_params_of_this_type, |
|
380 | - EEM_Base $model, |
|
381 | - $requested_version, |
|
382 | - $writing = false |
|
383 | - ) { |
|
384 | - $query_param_for_models = array(); |
|
385 | - $valid_operators = $model->valid_operators(); |
|
386 | - foreach ($inputted_query_params_of_this_type as $query_param_key => $query_param_value) { |
|
387 | - $is_gmt_datetime_field = false; |
|
388 | - $query_param_sans_stars = ModelDataTranslator::removeStarsAndAnythingAfterFromConditionQueryParamKey( |
|
389 | - $query_param_key |
|
390 | - ); |
|
391 | - $field = ModelDataTranslator::deduceFieldFromQueryParam( |
|
392 | - $query_param_sans_stars, |
|
393 | - $model |
|
394 | - ); |
|
395 | - //double-check is it a *_gmt field? |
|
396 | - if (! $field instanceof EE_Model_Field_Base |
|
397 | - && ModelDataTranslator::isGmtDateFieldName($query_param_sans_stars) |
|
398 | - ) { |
|
399 | - //yep, take off '_gmt', and find the field |
|
400 | - $query_param_key = ModelDataTranslator::removeGmtFromFieldName($query_param_sans_stars); |
|
401 | - $field = ModelDataTranslator::deduceFieldFromQueryParam( |
|
402 | - $query_param_key, |
|
403 | - $model |
|
404 | - ); |
|
405 | - $timezone = 'UTC'; |
|
406 | - $is_gmt_datetime_field = true; |
|
407 | - } elseif ($field instanceof EE_Datetime_Field) { |
|
408 | - //so it's not a GMT field. Set the timezone on the model to the default |
|
409 | - $timezone = \EEH_DTT_Helper::get_valid_timezone_string(); |
|
410 | - } else { |
|
411 | - //just keep using what's already set for the timezone |
|
412 | - $timezone = $model->get_timezone(); |
|
413 | - } |
|
414 | - if ($field instanceof EE_Model_Field_Base) { |
|
415 | - if (! $writing && is_array($query_param_value)) { |
|
416 | - if (! \EEH_Array::is_array_numerically_and_sequentially_indexed($query_param_value)) { |
|
417 | - if (defined('EE_REST_API_DEBUG_MODE') && EE_REST_API_DEBUG_MODE) { |
|
418 | - throw new RestException( |
|
419 | - 'numerically_indexed_array_of_values_only', |
|
420 | - sprintf( |
|
421 | - esc_html__( |
|
422 | - 'The array provided for the parameter "%1$s" should be numerically indexed.', |
|
423 | - 'event_espresso' |
|
424 | - ), |
|
425 | - $query_param_key |
|
426 | - ), |
|
427 | - array( |
|
428 | - 'status' => 400, |
|
429 | - ) |
|
430 | - ); |
|
431 | - } |
|
432 | - } |
|
433 | - //did they specify an operator? |
|
434 | - if (isset($query_param_value[0]) |
|
435 | - && isset($valid_operators[$query_param_value[0]]) |
|
436 | - ) { |
|
437 | - $op = $query_param_value[0]; |
|
438 | - $translated_value = array($op); |
|
439 | - if (array_key_exists($op, $model->valid_in_style_operators()) |
|
440 | - && isset($query_param_value[1]) |
|
441 | - && ! isset($query_param_value[2]) |
|
442 | - ) { |
|
443 | - $translated_value[] = ModelDataTranslator::prepareFieldValuesFromJson( |
|
444 | - $field, |
|
445 | - $query_param_value[1], |
|
446 | - $requested_version, |
|
447 | - $timezone |
|
448 | - ); |
|
449 | - } elseif (array_key_exists($op, $model->valid_between_style_operators()) |
|
450 | - && isset($query_param_value[1], $query_param_value[2]) |
|
451 | - && !isset($query_param_value[3]) |
|
452 | - ) { |
|
453 | - $translated_value[] = ModelDataTranslator::prepareFieldValuesFromJson( |
|
454 | - $field, |
|
455 | - $query_param_value[1], |
|
456 | - $requested_version, |
|
457 | - $timezone |
|
458 | - ); |
|
459 | - $translated_value[] = ModelDataTranslator::prepareFieldValuesFromJson( |
|
460 | - $field, |
|
461 | - $query_param_value[2], |
|
462 | - $requested_version, |
|
463 | - $timezone |
|
464 | - ); |
|
465 | - } elseif (array_key_exists($op, $model->valid_like_style_operators()) |
|
466 | - && isset($query_param_value[1]) |
|
467 | - && ! isset($query_param_value[2]) |
|
468 | - ) { |
|
469 | - //we want to leave this value mostly-as-is (eg don't force it to be a float |
|
470 | - //or a boolean or an enum value. Leave it as-is with wildcards etc) |
|
471 | - //but do verify it at least doesn't have any serialized data |
|
472 | - ModelDataTranslator::throwExceptionIfContainsSerializedData($query_param_value[1]); |
|
473 | - $translated_value[] = $query_param_value[1]; |
|
474 | - } elseif (array_key_exists($op, $model->valid_null_style_operators()) |
|
475 | - && !isset($query_param_value[1])) { |
|
476 | - //no arguments should have been provided, so don't look for any |
|
477 | - } elseif (isset($query_param_value[1]) |
|
478 | - && !isset($query_param_value[2]) |
|
479 | - && ! array_key_exists( |
|
480 | - $op, |
|
481 | - array_merge( |
|
482 | - $model->valid_in_style_operators(), |
|
483 | - $model->valid_null_style_operators(), |
|
484 | - $model->valid_like_style_operators(), |
|
485 | - $model->valid_between_style_operators() |
|
486 | - ) |
|
487 | - ) |
|
488 | - ) { |
|
489 | - //it's a valid operator, but none of the exceptions. Treat it normally. |
|
490 | - $translated_value[] = ModelDataTranslator::prepareFieldValuesFromJson( |
|
491 | - $field, |
|
492 | - $query_param_value[1], |
|
493 | - $requested_version, |
|
494 | - $timezone |
|
495 | - ); |
|
496 | - } else { |
|
497 | - //so they provided a valid operator, but wrong number of arguments |
|
498 | - if (defined('EE_REST_API_DEBUG_MODE') && EE_REST_API_DEBUG_MODE) { |
|
499 | - throw new RestException( |
|
500 | - 'wrong_number_of_arguments', |
|
501 | - sprintf( |
|
502 | - esc_html__( |
|
503 | - 'The operator you provided, "%1$s" had the wrong number of arguments', |
|
504 | - 'event_espresso' |
|
505 | - ), |
|
506 | - $op |
|
507 | - ), |
|
508 | - array( |
|
509 | - 'status' => 400, |
|
510 | - ) |
|
511 | - ); |
|
512 | - } |
|
513 | - $translated_value = null; |
|
514 | - } |
|
515 | - } else { |
|
516 | - //so they didn't provide a valid operator |
|
517 | - if (defined('EE_REST_API_DEBUG_MODE') && EE_REST_API_DEBUG_MODE) { |
|
518 | - throw new RestException( |
|
519 | - 'invalid_operator', |
|
520 | - sprintf( |
|
521 | - esc_html__( |
|
522 | - 'You provided an invalid parameter, with key "%1$s" and value "%2$s"', |
|
523 | - 'event_espresso' |
|
524 | - ), |
|
525 | - $query_param_key, |
|
526 | - $query_param_value |
|
527 | - ), |
|
528 | - array( |
|
529 | - 'status' => 400, |
|
530 | - ) |
|
531 | - ); |
|
532 | - } |
|
533 | - //if we aren't in debug mode, then just try our best to fulfill the user's request |
|
534 | - $translated_value = null; |
|
535 | - } |
|
536 | - } else { |
|
537 | - $translated_value = ModelDataTranslator::prepareFieldValueFromJson( |
|
538 | - $field, |
|
539 | - $query_param_value, |
|
540 | - $requested_version, |
|
541 | - $timezone |
|
542 | - ); |
|
543 | - } |
|
544 | - if ( |
|
545 | - (isset($query_param_for_models[$query_param_key]) && $is_gmt_datetime_field) |
|
546 | - || |
|
547 | - $translated_value === null |
|
548 | - ) { |
|
549 | - //they have already provided a non-gmt field, ignore the gmt one. That's what WP core |
|
550 | - //currently does (they might change it though). See https://core.trac.wordpress.org/ticket/39954 |
|
551 | - //OR we couldn't create a translated value from their input |
|
552 | - continue; |
|
553 | - } |
|
554 | - $query_param_for_models[$query_param_key] = $translated_value; |
|
555 | - } else { |
|
556 | - //so this param doesn't correspond to a field eh? |
|
557 | - if ($writing) { |
|
558 | - //always tell API clients about invalid parameters when they're creating data. Otherwise, |
|
559 | - //they are probably going to create invalid data |
|
560 | - throw new RestException( |
|
561 | - 'invalid_field', |
|
562 | - sprintf( |
|
563 | - esc_html__('You have provided an invalid parameter: "%1$s"', 'event_espresso'), |
|
564 | - $query_param_key |
|
565 | - ) |
|
566 | - ); |
|
567 | - } else { |
|
568 | - //so it's not for a field, is it a logic query param key? |
|
569 | - if (in_array( |
|
570 | - $query_param_sans_stars, |
|
571 | - $model->logic_query_param_keys() |
|
572 | - )) { |
|
573 | - $query_param_for_models[$query_param_key] = ModelDataTranslator::prepareConditionsQueryParamsForModels( |
|
574 | - $query_param_value, |
|
575 | - $model, |
|
576 | - $requested_version |
|
577 | - ); |
|
578 | - } elseif (defined('EE_REST_API_DEBUG_MODE') && EE_REST_API_DEBUG_MODE) { |
|
579 | - //only tell API clients they got it wrong if we're in debug mode |
|
580 | - //otherwise try our best ot fulfill their request by ignoring this invalid data |
|
581 | - throw new RestException( |
|
582 | - 'invalid_parameter', |
|
583 | - sprintf( |
|
584 | - esc_html__( |
|
585 | - 'You provided an invalid parameter, with key "%1$s"', |
|
586 | - 'event_espresso' |
|
587 | - ), |
|
588 | - $query_param_sans_stars |
|
589 | - ), |
|
590 | - array( |
|
591 | - 'status' => 400, |
|
592 | - ) |
|
593 | - ); |
|
594 | - } |
|
595 | - } |
|
596 | - } |
|
597 | - } |
|
598 | - return $query_param_for_models; |
|
599 | - } |
|
600 | - |
|
601 | - |
|
602 | - |
|
603 | - /** |
|
604 | - * Mostly checks if the last 4 characters are "_gmt", indicating its a |
|
605 | - * gmt date field name |
|
606 | - * |
|
607 | - * @param string $field_name |
|
608 | - * @return boolean |
|
609 | - */ |
|
610 | - public static function isGmtDateFieldName($field_name) |
|
611 | - { |
|
612 | - return substr( |
|
613 | - ModelDataTranslator::removeStarsAndAnythingAfterFromConditionQueryParamKey($field_name), |
|
614 | - -4, |
|
615 | - 4 |
|
616 | - ) === '_gmt'; |
|
617 | - } |
|
618 | - |
|
619 | - |
|
620 | - |
|
621 | - /** |
|
622 | - * Removes the last "_gmt" part of a field name (and if there is no "_gmt" at the end, leave it alone) |
|
623 | - * |
|
624 | - * @param string $field_name |
|
625 | - * @return string |
|
626 | - */ |
|
627 | - public static function removeGmtFromFieldName($field_name) |
|
628 | - { |
|
629 | - if (! ModelDataTranslator::isGmtDateFieldName($field_name)) { |
|
630 | - return $field_name; |
|
631 | - } |
|
632 | - $query_param_sans_stars = ModelDataTranslator::removeStarsAndAnythingAfterFromConditionQueryParamKey( |
|
633 | - $field_name |
|
634 | - ); |
|
635 | - $query_param_sans_gmt_and_sans_stars = substr( |
|
636 | - $query_param_sans_stars, |
|
637 | - 0, |
|
638 | - strrpos( |
|
639 | - $field_name, |
|
640 | - '_gmt' |
|
641 | - ) |
|
642 | - ); |
|
643 | - return str_replace($query_param_sans_stars, $query_param_sans_gmt_and_sans_stars, $field_name); |
|
644 | - } |
|
645 | - |
|
646 | - |
|
647 | - |
|
648 | - /** |
|
649 | - * Takes a field name from the REST API and prepares it for the model querying |
|
650 | - * |
|
651 | - * @param string $field_name |
|
652 | - * @return string |
|
653 | - */ |
|
654 | - public static function prepareFieldNameFromJson($field_name) |
|
655 | - { |
|
656 | - if (ModelDataTranslator::isGmtDateFieldName($field_name)) { |
|
657 | - return ModelDataTranslator::removeGmtFromFieldName($field_name); |
|
658 | - } |
|
659 | - return $field_name; |
|
660 | - } |
|
661 | - |
|
662 | - |
|
663 | - |
|
664 | - /** |
|
665 | - * Takes array of field names from REST API and prepares for models |
|
666 | - * |
|
667 | - * @param array $field_names |
|
668 | - * @return array of field names (possibly include model prefixes) |
|
669 | - */ |
|
670 | - public static function prepareFieldNamesFromJson(array $field_names) |
|
671 | - { |
|
672 | - $new_array = array(); |
|
673 | - foreach ($field_names as $key => $field_name) { |
|
674 | - $new_array[$key] = ModelDataTranslator::prepareFieldNameFromJson($field_name); |
|
675 | - } |
|
676 | - return $new_array; |
|
677 | - } |
|
678 | - |
|
679 | - |
|
680 | - |
|
681 | - /** |
|
682 | - * Takes array where array keys are field names (possibly with model path prefixes) |
|
683 | - * from the REST API and prepares them for model querying |
|
684 | - * |
|
685 | - * @param array $field_names_as_keys |
|
686 | - * @return array |
|
687 | - */ |
|
688 | - public static function prepareFieldNamesInArrayKeysFromJson(array $field_names_as_keys) |
|
689 | - { |
|
690 | - $new_array = array(); |
|
691 | - foreach ($field_names_as_keys as $field_name => $value) { |
|
692 | - $new_array[ModelDataTranslator::prepareFieldNameFromJson($field_name)] = $value; |
|
693 | - } |
|
694 | - return $new_array; |
|
695 | - } |
|
696 | - |
|
697 | - |
|
698 | - |
|
699 | - /** |
|
700 | - * Prepares an array of model query params for use in the REST API |
|
701 | - * |
|
702 | - * @param array $model_query_params |
|
703 | - * @param EEM_Base $model |
|
704 | - * @param string $requested_version eg "4.8.36". If null is provided, defaults to the latest release of the EE4 |
|
705 | - * REST API |
|
706 | - * @return array which can be passed into the EE4 REST API when querying a model resource |
|
707 | - * @throws EE_Error |
|
708 | - */ |
|
709 | - public static function prepareQueryParamsForRestApi( |
|
710 | - array $model_query_params, |
|
711 | - EEM_Base $model, |
|
712 | - $requested_version = null |
|
713 | - ) { |
|
714 | - if ($requested_version === null) { |
|
715 | - $requested_version = \EED_Core_Rest_Api::latest_rest_api_version(); |
|
716 | - } |
|
717 | - $rest_query_params = $model_query_params; |
|
718 | - if (isset($model_query_params[0])) { |
|
719 | - $rest_query_params['where'] = ModelDataTranslator::prepareConditionsQueryParamsForRestApi( |
|
720 | - $model_query_params[0], |
|
721 | - $model, |
|
722 | - $requested_version |
|
723 | - ); |
|
724 | - unset($rest_query_params[0]); |
|
725 | - } |
|
726 | - if (isset($model_query_params['having'])) { |
|
727 | - $rest_query_params['having'] = ModelDataTranslator::prepareConditionsQueryParamsForRestApi( |
|
728 | - $model_query_params['having'], |
|
729 | - $model, |
|
730 | - $requested_version |
|
731 | - ); |
|
732 | - } |
|
733 | - return apply_filters( |
|
734 | - 'FHEE__EventEspresso\core\libraries\rest_api\Model_Data_Translator__prepare_query_params_for_rest_api', |
|
735 | - $rest_query_params, |
|
736 | - $model_query_params, |
|
737 | - $model, |
|
738 | - $requested_version |
|
739 | - ); |
|
740 | - } |
|
741 | - |
|
742 | - |
|
743 | - |
|
744 | - /** |
|
745 | - * Prepares all the sub-conditions query parameters (eg having or where conditions) for use in the rest api |
|
746 | - * |
|
747 | - * @param array $inputted_query_params_of_this_type eg like the "where" or "having" conditions query params |
|
748 | - * passed into EEM_Base::get_all() |
|
749 | - * @param EEM_Base $model |
|
750 | - * @param string $requested_version eg "4.8.36" |
|
751 | - * @return array ready for use in the rest api query params |
|
752 | - * @throws EE_Error |
|
753 | - * @throws ObjectDetectedException if somehow a PHP object were in the query params' values, |
|
754 | - * (which would be really unusual) |
|
755 | - */ |
|
756 | - public static function prepareConditionsQueryParamsForRestApi( |
|
757 | - $inputted_query_params_of_this_type, |
|
758 | - EEM_Base $model, |
|
759 | - $requested_version |
|
760 | - ) { |
|
761 | - $query_param_for_models = array(); |
|
762 | - foreach ($inputted_query_params_of_this_type as $query_param_key => $query_param_value) { |
|
763 | - $field = ModelDataTranslator::deduceFieldFromQueryParam( |
|
764 | - ModelDataTranslator::removeStarsAndAnythingAfterFromConditionQueryParamKey($query_param_key), |
|
765 | - $model |
|
766 | - ); |
|
767 | - if ($field instanceof EE_Model_Field_Base) { |
|
768 | - //did they specify an operator? |
|
769 | - if (is_array($query_param_value)) { |
|
770 | - $op = $query_param_value[0]; |
|
771 | - $translated_value = array($op); |
|
772 | - if (isset($query_param_value[1])) { |
|
773 | - $value = $query_param_value[1]; |
|
774 | - $translated_value[1] = ModelDataTranslator::prepareFieldValuesForJson( |
|
775 | - $field, |
|
776 | - $value, |
|
777 | - $requested_version |
|
778 | - ); |
|
779 | - } |
|
780 | - } else { |
|
781 | - $translated_value = ModelDataTranslator::prepareFieldValueForJson( |
|
782 | - $field, |
|
783 | - $query_param_value, |
|
784 | - $requested_version |
|
785 | - ); |
|
786 | - } |
|
787 | - $query_param_for_models[$query_param_key] = $translated_value; |
|
788 | - } else { |
|
789 | - //so it's not for a field, assume it's a logic query param key |
|
790 | - $query_param_for_models[$query_param_key] = ModelDataTranslator::prepareConditionsQueryParamsForRestApi( |
|
791 | - $query_param_value, |
|
792 | - $model, |
|
793 | - $requested_version |
|
794 | - ); |
|
795 | - } |
|
796 | - } |
|
797 | - return $query_param_for_models; |
|
798 | - } |
|
799 | - |
|
800 | - |
|
801 | - |
|
802 | - /** |
|
803 | - * @param $condition_query_param_key |
|
804 | - * @return string |
|
805 | - */ |
|
806 | - public static function removeStarsAndAnythingAfterFromConditionQueryParamKey($condition_query_param_key) |
|
807 | - { |
|
808 | - $pos_of_star = strpos($condition_query_param_key, '*'); |
|
809 | - if ($pos_of_star === false) { |
|
810 | - return $condition_query_param_key; |
|
811 | - } else { |
|
812 | - $condition_query_param_sans_star = substr($condition_query_param_key, 0, $pos_of_star); |
|
813 | - return $condition_query_param_sans_star; |
|
814 | - } |
|
815 | - } |
|
816 | - |
|
817 | - |
|
818 | - |
|
819 | - /** |
|
820 | - * Takes the input parameter and finds the model field that it indicates. |
|
821 | - * |
|
822 | - * @param string $query_param_name like Registration.Transaction.TXN_ID, Event.Datetime.start_time, or REG_ID |
|
823 | - * @param EEM_Base $model |
|
824 | - * @return EE_Model_Field_Base |
|
825 | - * @throws EE_Error |
|
826 | - */ |
|
827 | - public static function deduceFieldFromQueryParam($query_param_name, EEM_Base $model) |
|
828 | - { |
|
829 | - //ok, now proceed with deducing which part is the model's name, and which is the field's name |
|
830 | - //which will help us find the database table and column |
|
831 | - $query_param_parts = explode('.', $query_param_name); |
|
832 | - if (empty($query_param_parts)) { |
|
833 | - throw new EE_Error( |
|
834 | - sprintf( |
|
835 | - __( |
|
836 | - '_extract_column_name is empty when trying to extract column and table name from %s', |
|
837 | - 'event_espresso' |
|
838 | - ), |
|
839 | - $query_param_name |
|
840 | - ) |
|
841 | - ); |
|
842 | - } |
|
843 | - $number_of_parts = count($query_param_parts); |
|
844 | - $last_query_param_part = $query_param_parts[count($query_param_parts) - 1]; |
|
845 | - if ($number_of_parts === 1) { |
|
846 | - $field_name = $last_query_param_part; |
|
847 | - } else {// $number_of_parts >= 2 |
|
848 | - //the last part is the column name, and there are only 2parts. therefore... |
|
849 | - $field_name = $last_query_param_part; |
|
850 | - $model = \EE_Registry::instance()->load_model($query_param_parts[$number_of_parts - 2]); |
|
851 | - } |
|
852 | - try { |
|
853 | - return $model->field_settings_for($field_name, false); |
|
854 | - } catch (EE_Error $e) { |
|
855 | - return null; |
|
856 | - } |
|
857 | - } |
|
858 | - |
|
859 | - |
|
860 | - |
|
861 | - /** |
|
862 | - * Returns true if $data can be easily represented in JSON. |
|
863 | - * Basically, objects and resources can't be represented in JSON easily. |
|
864 | - * @param mixed $data |
|
865 | - * @return bool |
|
866 | - */ |
|
867 | - protected static function isRepresentableInJson($data) |
|
868 | - { |
|
869 | - return is_scalar($data) |
|
870 | - || is_array($data) |
|
871 | - || is_null($data); |
|
872 | - } |
|
40 | + /** |
|
41 | + * We used to use -1 for infinity in the rest api, but that's ambiguous for |
|
42 | + * fields that COULD contain -1; so we use null |
|
43 | + */ |
|
44 | + const EE_INF_IN_REST = null; |
|
45 | + |
|
46 | + |
|
47 | + |
|
48 | + /** |
|
49 | + * Prepares a possible array of input values from JSON for use by the models |
|
50 | + * |
|
51 | + * @param EE_Model_Field_Base $field_obj |
|
52 | + * @param mixed $original_value_maybe_array |
|
53 | + * @param string $requested_version |
|
54 | + * @param string $timezone_string treat values as being in this timezone |
|
55 | + * @return mixed |
|
56 | + * @throws RestException |
|
57 | + */ |
|
58 | + public static function prepareFieldValuesFromJson( |
|
59 | + $field_obj, |
|
60 | + $original_value_maybe_array, |
|
61 | + $requested_version, |
|
62 | + $timezone_string = 'UTC' |
|
63 | + ) { |
|
64 | + if (is_array($original_value_maybe_array) |
|
65 | + && ! $field_obj instanceof EE_Serialized_Text_Field |
|
66 | + ) { |
|
67 | + $new_value_maybe_array = array(); |
|
68 | + foreach ($original_value_maybe_array as $array_key => $array_item) { |
|
69 | + $new_value_maybe_array[$array_key] = ModelDataTranslator::prepareFieldValueFromJson( |
|
70 | + $field_obj, |
|
71 | + $array_item, |
|
72 | + $requested_version, |
|
73 | + $timezone_string |
|
74 | + ); |
|
75 | + } |
|
76 | + } else { |
|
77 | + $new_value_maybe_array = ModelDataTranslator::prepareFieldValueFromJson( |
|
78 | + $field_obj, |
|
79 | + $original_value_maybe_array, |
|
80 | + $requested_version, |
|
81 | + $timezone_string |
|
82 | + ); |
|
83 | + } |
|
84 | + return $new_value_maybe_array; |
|
85 | + } |
|
86 | + |
|
87 | + |
|
88 | + |
|
89 | + /** |
|
90 | + * Prepares an array of field values FOR use in JSON/REST API |
|
91 | + * |
|
92 | + * @param EE_Model_Field_Base $field_obj |
|
93 | + * @param mixed $original_value_maybe_array |
|
94 | + * @param string $request_version (eg 4.8.36) |
|
95 | + * @return array |
|
96 | + */ |
|
97 | + public static function prepareFieldValuesForJson($field_obj, $original_value_maybe_array, $request_version) |
|
98 | + { |
|
99 | + if (is_array($original_value_maybe_array)) { |
|
100 | + $new_value = array(); |
|
101 | + foreach ($original_value_maybe_array as $key => $value) { |
|
102 | + $new_value[$key] = ModelDataTranslator::prepareFieldValuesForJson($field_obj, $value, $request_version); |
|
103 | + } |
|
104 | + } else { |
|
105 | + $new_value = ModelDataTranslator::prepareFieldValueForJson( |
|
106 | + $field_obj, |
|
107 | + $original_value_maybe_array, |
|
108 | + $request_version |
|
109 | + ); |
|
110 | + } |
|
111 | + return $new_value; |
|
112 | + } |
|
113 | + |
|
114 | + |
|
115 | + /** |
|
116 | + * Prepares incoming data from the json or $_REQUEST parameters for the models' |
|
117 | + * "$query_params". |
|
118 | + * |
|
119 | + * @param EE_Model_Field_Base $field_obj |
|
120 | + * @param mixed $original_value |
|
121 | + * @param string $requested_version |
|
122 | + * @param string $timezone_string treat values as being in this timezone |
|
123 | + * @return mixed |
|
124 | + * @throws RestException |
|
125 | + * @throws DomainException |
|
126 | + * @throws EE_Error |
|
127 | + */ |
|
128 | + public static function prepareFieldValueFromJson( |
|
129 | + $field_obj, |
|
130 | + $original_value, |
|
131 | + $requested_version, |
|
132 | + $timezone_string = 'UTC' // UTC |
|
133 | + ) { |
|
134 | + //check if they accidentally submitted an error value. If so throw an exception |
|
135 | + if (is_array($original_value) |
|
136 | + && isset($original_value['error_code'], $original_value['error_message'])) { |
|
137 | + throw new RestException( |
|
138 | + 'rest_submitted_error_value', |
|
139 | + sprintf( |
|
140 | + esc_html__( |
|
141 | + 'You tried to submit a JSON error object as a value for %1$s. That\'s not allowed.', |
|
142 | + 'event_espresso' |
|
143 | + ), |
|
144 | + $field_obj->get_name() |
|
145 | + ), |
|
146 | + array( |
|
147 | + 'status' => 400, |
|
148 | + ) |
|
149 | + ); |
|
150 | + } |
|
151 | + //double-check for serialized PHP. We never accept serialized PHP. No way Jose. |
|
152 | + ModelDataTranslator::throwExceptionIfContainsSerializedData($original_value); |
|
153 | + $timezone_string = $timezone_string !== '' ? $timezone_string : get_option('timezone_string', ''); |
|
154 | + $new_value = null; |
|
155 | + //walk through the submitted data and double-check for serialized PHP. We never accept serialized PHP. No |
|
156 | + // way Jose. |
|
157 | + ModelDataTranslator::throwExceptionIfContainsSerializedData($original_value); |
|
158 | + if ($field_obj instanceof EE_Infinite_Integer_Field |
|
159 | + && in_array($original_value, array(null, ''), true) |
|
160 | + ) { |
|
161 | + $new_value = EE_INF; |
|
162 | + } elseif ($field_obj instanceof EE_Datetime_Field) { |
|
163 | + $new_value = rest_parse_date( |
|
164 | + self::getTimestampWithTimezoneOffset($original_value, $field_obj, $timezone_string) |
|
165 | + ); |
|
166 | + if ($new_value === false) { |
|
167 | + throw new RestException( |
|
168 | + 'invalid_format_for_timestamp', |
|
169 | + sprintf( |
|
170 | + esc_html__( |
|
171 | + 'Timestamps received on a request as the value for Date and Time fields must be in %1$s/%2$s format. The timestamp provided (%3$s) is not that format.', |
|
172 | + 'event_espresso' |
|
173 | + ), |
|
174 | + 'RFC3339', |
|
175 | + 'ISO8601', |
|
176 | + $original_value |
|
177 | + ), |
|
178 | + array( |
|
179 | + 'status' => 400 |
|
180 | + ) |
|
181 | + ); |
|
182 | + } |
|
183 | + } else { |
|
184 | + $new_value = $original_value; |
|
185 | + } |
|
186 | + return $new_value; |
|
187 | + } |
|
188 | + |
|
189 | + |
|
190 | + /** |
|
191 | + * This checks if the incoming timestamp has timezone information already on it and if it doesn't then adds timezone |
|
192 | + * information via details obtained from the host site. |
|
193 | + * |
|
194 | + * @param string $original_timestamp |
|
195 | + * @param EE_Datetime_Field $datetime_field |
|
196 | + * @param $timezone_string |
|
197 | + * @return string |
|
198 | + * @throws DomainException |
|
199 | + */ |
|
200 | + private static function getTimestampWithTimezoneOffset( |
|
201 | + $original_timestamp, |
|
202 | + EE_Datetime_Field $datetime_field, |
|
203 | + $timezone_string |
|
204 | + ) { |
|
205 | + //already have timezone information? |
|
206 | + if (preg_match('/Z|(\+|\-)(\d{2}:\d{2})/', $original_timestamp)) { |
|
207 | + //yes, we're ignoring the timezone. |
|
208 | + return $original_timestamp; |
|
209 | + } |
|
210 | + //need to append timezone |
|
211 | + list($offset_sign, $offset_secs) = self::parseTimezoneOffset( |
|
212 | + $datetime_field->get_timezone_offset( |
|
213 | + new \DateTimeZone($timezone_string), |
|
214 | + $original_timestamp |
|
215 | + ) |
|
216 | + ); |
|
217 | + $offset_string = |
|
218 | + str_pad( |
|
219 | + floor($offset_secs / HOUR_IN_SECONDS), |
|
220 | + 2, |
|
221 | + '0', |
|
222 | + STR_PAD_LEFT |
|
223 | + ) |
|
224 | + . ':' |
|
225 | + . str_pad( |
|
226 | + ($offset_secs % HOUR_IN_SECONDS) / MINUTE_IN_SECONDS, |
|
227 | + 2, |
|
228 | + '0', |
|
229 | + STR_PAD_LEFT |
|
230 | + ); |
|
231 | + return $original_timestamp . $offset_sign . $offset_string; |
|
232 | + } |
|
233 | + |
|
234 | + |
|
235 | + |
|
236 | + /** |
|
237 | + * Throws an exception if $data is a serialized PHP string (or somehow an actually PHP object, although I don't |
|
238 | + * think that can happen). If $data is an array, recurses into its keys and values |
|
239 | + * @param mixed $data |
|
240 | + * @throws RestException |
|
241 | + * @return void |
|
242 | + */ |
|
243 | + public static function throwExceptionIfContainsSerializedData($data) |
|
244 | + { |
|
245 | + if (is_array($data)) { |
|
246 | + foreach ($data as $key => $value) { |
|
247 | + ModelDataTranslator::throwExceptionIfContainsSerializedData($key); |
|
248 | + ModelDataTranslator::throwExceptionIfContainsSerializedData($value); |
|
249 | + } |
|
250 | + } else { |
|
251 | + if (is_serialized($data) || is_object($data)) { |
|
252 | + throw new RestException( |
|
253 | + 'serialized_data_submission_prohibited', |
|
254 | + esc_html__( |
|
255 | + // @codingStandardsIgnoreStart |
|
256 | + 'You tried to submit a string of serialized text. Serialized PHP is prohibited over the EE4 REST API.', |
|
257 | + // @codingStandardsIgnoreEnd |
|
258 | + 'event_espresso' |
|
259 | + ) |
|
260 | + ); |
|
261 | + } |
|
262 | + } |
|
263 | + } |
|
264 | + |
|
265 | + |
|
266 | + |
|
267 | + /** |
|
268 | + * determines what's going on with them timezone strings |
|
269 | + * |
|
270 | + * @param int $timezone_offset |
|
271 | + * @return array |
|
272 | + */ |
|
273 | + private static function parseTimezoneOffset($timezone_offset) |
|
274 | + { |
|
275 | + $first_char = substr((string)$timezone_offset, 0, 1); |
|
276 | + if ($first_char === '+' || $first_char === '-') { |
|
277 | + $offset_sign = $first_char; |
|
278 | + $offset_secs = substr((string)$timezone_offset, 1); |
|
279 | + } else { |
|
280 | + $offset_sign = '+'; |
|
281 | + $offset_secs = $timezone_offset; |
|
282 | + } |
|
283 | + return array($offset_sign, $offset_secs); |
|
284 | + } |
|
285 | + |
|
286 | + |
|
287 | + |
|
288 | + /** |
|
289 | + * Prepares a field's value for display in the API |
|
290 | + * |
|
291 | + * @param EE_Model_Field_Base $field_obj |
|
292 | + * @param mixed $original_value |
|
293 | + * @param string $requested_version |
|
294 | + * @return mixed |
|
295 | + */ |
|
296 | + public static function prepareFieldValueForJson($field_obj, $original_value, $requested_version) |
|
297 | + { |
|
298 | + if ($original_value === EE_INF) { |
|
299 | + $new_value = ModelDataTranslator::EE_INF_IN_REST; |
|
300 | + } elseif ($field_obj instanceof EE_Datetime_Field) { |
|
301 | + if (is_string($original_value)) { |
|
302 | + //did they submit a string of a unix timestamp? |
|
303 | + if (is_numeric($original_value)) { |
|
304 | + $datetime_obj = new \DateTime(); |
|
305 | + $datetime_obj->setTimestamp((int)$original_value); |
|
306 | + } else { |
|
307 | + //first, check if its a MySQL timestamp in GMT |
|
308 | + $datetime_obj = \DateTime::createFromFormat('Y-m-d H:i:s', $original_value); |
|
309 | + } |
|
310 | + if (! $datetime_obj instanceof \DateTime) { |
|
311 | + //so it's not a unix timestamp or a MySQL timestamp. Maybe its in the field's date/time format? |
|
312 | + $datetime_obj = $field_obj->prepare_for_set($original_value); |
|
313 | + } |
|
314 | + $original_value = $datetime_obj; |
|
315 | + } |
|
316 | + if ($original_value instanceof \DateTime) { |
|
317 | + $new_value = $original_value->format('Y-m-d H:i:s'); |
|
318 | + } elseif (is_int($original_value) || is_float($original_value)) { |
|
319 | + $new_value = date('Y-m-d H:i:s', $original_value); |
|
320 | + } elseif($original_value === null || $original_value === '') { |
|
321 | + $new_value = null; |
|
322 | + } else { |
|
323 | + //so it's not a datetime object, unix timestamp (as string or int), |
|
324 | + //MySQL timestamp, or even a string in the field object's format. So no idea what it is |
|
325 | + throw new \EE_Error( |
|
326 | + sprintf( |
|
327 | + esc_html__( |
|
328 | + // @codingStandardsIgnoreStart |
|
329 | + 'The value "%1$s" for the field "%2$s" on model "%3$s" could not be understood. It should be a PHP DateTime, unix timestamp, MySQL date, or string in the format "%4$s".', |
|
330 | + // @codingStandardsIgnoreEnd |
|
331 | + 'event_espressso' |
|
332 | + ), |
|
333 | + $original_value, |
|
334 | + $field_obj->get_name(), |
|
335 | + $field_obj->get_model_name(), |
|
336 | + $field_obj->get_time_format() . ' ' . $field_obj->get_time_format() |
|
337 | + ) |
|
338 | + ); |
|
339 | + } |
|
340 | + $new_value = mysql_to_rfc3339($new_value); |
|
341 | + } else { |
|
342 | + $new_value = $original_value; |
|
343 | + } |
|
344 | + //are we about to send an object? just don't. We have no good way to represent it in JSON. |
|
345 | + // can't just check using is_object() because that missed PHP incomplete objects |
|
346 | + if (! ModelDataTranslator::isRepresentableInJson($new_value)) { |
|
347 | + $new_value = array( |
|
348 | + 'error_code' => 'php_object_not_return', |
|
349 | + 'error_message' => esc_html__('The value of this field in the database is a PHP object, which can\'t be represented in JSON.', 'event_espresso') |
|
350 | + ); |
|
351 | + } |
|
352 | + return apply_filters( |
|
353 | + 'FHEE__EventEspresso\core\libraries\rest_api\Model_Data_Translator__prepare_field_for_rest_api', |
|
354 | + $new_value, |
|
355 | + $field_obj, |
|
356 | + $original_value, |
|
357 | + $requested_version |
|
358 | + ); |
|
359 | + } |
|
360 | + |
|
361 | + |
|
362 | + |
|
363 | + /** |
|
364 | + * Prepares condition-query-parameters (like what's in where and having) from |
|
365 | + * the format expected in the API to use in the models |
|
366 | + * |
|
367 | + * @param array $inputted_query_params_of_this_type |
|
368 | + * @param EEM_Base $model |
|
369 | + * @param string $requested_version |
|
370 | + * @param boolean $writing whether this data will be written to the DB, or if we're just building a query. |
|
371 | + * If we're writing to the DB, we don't expect any operators, or any logic query parameters, |
|
372 | + * and we also won't accept serialized data unless the current user has unfiltered_html. |
|
373 | + * @return array |
|
374 | + * @throws DomainException |
|
375 | + * @throws RestException |
|
376 | + * @throws EE_Error |
|
377 | + */ |
|
378 | + public static function prepareConditionsQueryParamsForModels( |
|
379 | + $inputted_query_params_of_this_type, |
|
380 | + EEM_Base $model, |
|
381 | + $requested_version, |
|
382 | + $writing = false |
|
383 | + ) { |
|
384 | + $query_param_for_models = array(); |
|
385 | + $valid_operators = $model->valid_operators(); |
|
386 | + foreach ($inputted_query_params_of_this_type as $query_param_key => $query_param_value) { |
|
387 | + $is_gmt_datetime_field = false; |
|
388 | + $query_param_sans_stars = ModelDataTranslator::removeStarsAndAnythingAfterFromConditionQueryParamKey( |
|
389 | + $query_param_key |
|
390 | + ); |
|
391 | + $field = ModelDataTranslator::deduceFieldFromQueryParam( |
|
392 | + $query_param_sans_stars, |
|
393 | + $model |
|
394 | + ); |
|
395 | + //double-check is it a *_gmt field? |
|
396 | + if (! $field instanceof EE_Model_Field_Base |
|
397 | + && ModelDataTranslator::isGmtDateFieldName($query_param_sans_stars) |
|
398 | + ) { |
|
399 | + //yep, take off '_gmt', and find the field |
|
400 | + $query_param_key = ModelDataTranslator::removeGmtFromFieldName($query_param_sans_stars); |
|
401 | + $field = ModelDataTranslator::deduceFieldFromQueryParam( |
|
402 | + $query_param_key, |
|
403 | + $model |
|
404 | + ); |
|
405 | + $timezone = 'UTC'; |
|
406 | + $is_gmt_datetime_field = true; |
|
407 | + } elseif ($field instanceof EE_Datetime_Field) { |
|
408 | + //so it's not a GMT field. Set the timezone on the model to the default |
|
409 | + $timezone = \EEH_DTT_Helper::get_valid_timezone_string(); |
|
410 | + } else { |
|
411 | + //just keep using what's already set for the timezone |
|
412 | + $timezone = $model->get_timezone(); |
|
413 | + } |
|
414 | + if ($field instanceof EE_Model_Field_Base) { |
|
415 | + if (! $writing && is_array($query_param_value)) { |
|
416 | + if (! \EEH_Array::is_array_numerically_and_sequentially_indexed($query_param_value)) { |
|
417 | + if (defined('EE_REST_API_DEBUG_MODE') && EE_REST_API_DEBUG_MODE) { |
|
418 | + throw new RestException( |
|
419 | + 'numerically_indexed_array_of_values_only', |
|
420 | + sprintf( |
|
421 | + esc_html__( |
|
422 | + 'The array provided for the parameter "%1$s" should be numerically indexed.', |
|
423 | + 'event_espresso' |
|
424 | + ), |
|
425 | + $query_param_key |
|
426 | + ), |
|
427 | + array( |
|
428 | + 'status' => 400, |
|
429 | + ) |
|
430 | + ); |
|
431 | + } |
|
432 | + } |
|
433 | + //did they specify an operator? |
|
434 | + if (isset($query_param_value[0]) |
|
435 | + && isset($valid_operators[$query_param_value[0]]) |
|
436 | + ) { |
|
437 | + $op = $query_param_value[0]; |
|
438 | + $translated_value = array($op); |
|
439 | + if (array_key_exists($op, $model->valid_in_style_operators()) |
|
440 | + && isset($query_param_value[1]) |
|
441 | + && ! isset($query_param_value[2]) |
|
442 | + ) { |
|
443 | + $translated_value[] = ModelDataTranslator::prepareFieldValuesFromJson( |
|
444 | + $field, |
|
445 | + $query_param_value[1], |
|
446 | + $requested_version, |
|
447 | + $timezone |
|
448 | + ); |
|
449 | + } elseif (array_key_exists($op, $model->valid_between_style_operators()) |
|
450 | + && isset($query_param_value[1], $query_param_value[2]) |
|
451 | + && !isset($query_param_value[3]) |
|
452 | + ) { |
|
453 | + $translated_value[] = ModelDataTranslator::prepareFieldValuesFromJson( |
|
454 | + $field, |
|
455 | + $query_param_value[1], |
|
456 | + $requested_version, |
|
457 | + $timezone |
|
458 | + ); |
|
459 | + $translated_value[] = ModelDataTranslator::prepareFieldValuesFromJson( |
|
460 | + $field, |
|
461 | + $query_param_value[2], |
|
462 | + $requested_version, |
|
463 | + $timezone |
|
464 | + ); |
|
465 | + } elseif (array_key_exists($op, $model->valid_like_style_operators()) |
|
466 | + && isset($query_param_value[1]) |
|
467 | + && ! isset($query_param_value[2]) |
|
468 | + ) { |
|
469 | + //we want to leave this value mostly-as-is (eg don't force it to be a float |
|
470 | + //or a boolean or an enum value. Leave it as-is with wildcards etc) |
|
471 | + //but do verify it at least doesn't have any serialized data |
|
472 | + ModelDataTranslator::throwExceptionIfContainsSerializedData($query_param_value[1]); |
|
473 | + $translated_value[] = $query_param_value[1]; |
|
474 | + } elseif (array_key_exists($op, $model->valid_null_style_operators()) |
|
475 | + && !isset($query_param_value[1])) { |
|
476 | + //no arguments should have been provided, so don't look for any |
|
477 | + } elseif (isset($query_param_value[1]) |
|
478 | + && !isset($query_param_value[2]) |
|
479 | + && ! array_key_exists( |
|
480 | + $op, |
|
481 | + array_merge( |
|
482 | + $model->valid_in_style_operators(), |
|
483 | + $model->valid_null_style_operators(), |
|
484 | + $model->valid_like_style_operators(), |
|
485 | + $model->valid_between_style_operators() |
|
486 | + ) |
|
487 | + ) |
|
488 | + ) { |
|
489 | + //it's a valid operator, but none of the exceptions. Treat it normally. |
|
490 | + $translated_value[] = ModelDataTranslator::prepareFieldValuesFromJson( |
|
491 | + $field, |
|
492 | + $query_param_value[1], |
|
493 | + $requested_version, |
|
494 | + $timezone |
|
495 | + ); |
|
496 | + } else { |
|
497 | + //so they provided a valid operator, but wrong number of arguments |
|
498 | + if (defined('EE_REST_API_DEBUG_MODE') && EE_REST_API_DEBUG_MODE) { |
|
499 | + throw new RestException( |
|
500 | + 'wrong_number_of_arguments', |
|
501 | + sprintf( |
|
502 | + esc_html__( |
|
503 | + 'The operator you provided, "%1$s" had the wrong number of arguments', |
|
504 | + 'event_espresso' |
|
505 | + ), |
|
506 | + $op |
|
507 | + ), |
|
508 | + array( |
|
509 | + 'status' => 400, |
|
510 | + ) |
|
511 | + ); |
|
512 | + } |
|
513 | + $translated_value = null; |
|
514 | + } |
|
515 | + } else { |
|
516 | + //so they didn't provide a valid operator |
|
517 | + if (defined('EE_REST_API_DEBUG_MODE') && EE_REST_API_DEBUG_MODE) { |
|
518 | + throw new RestException( |
|
519 | + 'invalid_operator', |
|
520 | + sprintf( |
|
521 | + esc_html__( |
|
522 | + 'You provided an invalid parameter, with key "%1$s" and value "%2$s"', |
|
523 | + 'event_espresso' |
|
524 | + ), |
|
525 | + $query_param_key, |
|
526 | + $query_param_value |
|
527 | + ), |
|
528 | + array( |
|
529 | + 'status' => 400, |
|
530 | + ) |
|
531 | + ); |
|
532 | + } |
|
533 | + //if we aren't in debug mode, then just try our best to fulfill the user's request |
|
534 | + $translated_value = null; |
|
535 | + } |
|
536 | + } else { |
|
537 | + $translated_value = ModelDataTranslator::prepareFieldValueFromJson( |
|
538 | + $field, |
|
539 | + $query_param_value, |
|
540 | + $requested_version, |
|
541 | + $timezone |
|
542 | + ); |
|
543 | + } |
|
544 | + if ( |
|
545 | + (isset($query_param_for_models[$query_param_key]) && $is_gmt_datetime_field) |
|
546 | + || |
|
547 | + $translated_value === null |
|
548 | + ) { |
|
549 | + //they have already provided a non-gmt field, ignore the gmt one. That's what WP core |
|
550 | + //currently does (they might change it though). See https://core.trac.wordpress.org/ticket/39954 |
|
551 | + //OR we couldn't create a translated value from their input |
|
552 | + continue; |
|
553 | + } |
|
554 | + $query_param_for_models[$query_param_key] = $translated_value; |
|
555 | + } else { |
|
556 | + //so this param doesn't correspond to a field eh? |
|
557 | + if ($writing) { |
|
558 | + //always tell API clients about invalid parameters when they're creating data. Otherwise, |
|
559 | + //they are probably going to create invalid data |
|
560 | + throw new RestException( |
|
561 | + 'invalid_field', |
|
562 | + sprintf( |
|
563 | + esc_html__('You have provided an invalid parameter: "%1$s"', 'event_espresso'), |
|
564 | + $query_param_key |
|
565 | + ) |
|
566 | + ); |
|
567 | + } else { |
|
568 | + //so it's not for a field, is it a logic query param key? |
|
569 | + if (in_array( |
|
570 | + $query_param_sans_stars, |
|
571 | + $model->logic_query_param_keys() |
|
572 | + )) { |
|
573 | + $query_param_for_models[$query_param_key] = ModelDataTranslator::prepareConditionsQueryParamsForModels( |
|
574 | + $query_param_value, |
|
575 | + $model, |
|
576 | + $requested_version |
|
577 | + ); |
|
578 | + } elseif (defined('EE_REST_API_DEBUG_MODE') && EE_REST_API_DEBUG_MODE) { |
|
579 | + //only tell API clients they got it wrong if we're in debug mode |
|
580 | + //otherwise try our best ot fulfill their request by ignoring this invalid data |
|
581 | + throw new RestException( |
|
582 | + 'invalid_parameter', |
|
583 | + sprintf( |
|
584 | + esc_html__( |
|
585 | + 'You provided an invalid parameter, with key "%1$s"', |
|
586 | + 'event_espresso' |
|
587 | + ), |
|
588 | + $query_param_sans_stars |
|
589 | + ), |
|
590 | + array( |
|
591 | + 'status' => 400, |
|
592 | + ) |
|
593 | + ); |
|
594 | + } |
|
595 | + } |
|
596 | + } |
|
597 | + } |
|
598 | + return $query_param_for_models; |
|
599 | + } |
|
600 | + |
|
601 | + |
|
602 | + |
|
603 | + /** |
|
604 | + * Mostly checks if the last 4 characters are "_gmt", indicating its a |
|
605 | + * gmt date field name |
|
606 | + * |
|
607 | + * @param string $field_name |
|
608 | + * @return boolean |
|
609 | + */ |
|
610 | + public static function isGmtDateFieldName($field_name) |
|
611 | + { |
|
612 | + return substr( |
|
613 | + ModelDataTranslator::removeStarsAndAnythingAfterFromConditionQueryParamKey($field_name), |
|
614 | + -4, |
|
615 | + 4 |
|
616 | + ) === '_gmt'; |
|
617 | + } |
|
618 | + |
|
619 | + |
|
620 | + |
|
621 | + /** |
|
622 | + * Removes the last "_gmt" part of a field name (and if there is no "_gmt" at the end, leave it alone) |
|
623 | + * |
|
624 | + * @param string $field_name |
|
625 | + * @return string |
|
626 | + */ |
|
627 | + public static function removeGmtFromFieldName($field_name) |
|
628 | + { |
|
629 | + if (! ModelDataTranslator::isGmtDateFieldName($field_name)) { |
|
630 | + return $field_name; |
|
631 | + } |
|
632 | + $query_param_sans_stars = ModelDataTranslator::removeStarsAndAnythingAfterFromConditionQueryParamKey( |
|
633 | + $field_name |
|
634 | + ); |
|
635 | + $query_param_sans_gmt_and_sans_stars = substr( |
|
636 | + $query_param_sans_stars, |
|
637 | + 0, |
|
638 | + strrpos( |
|
639 | + $field_name, |
|
640 | + '_gmt' |
|
641 | + ) |
|
642 | + ); |
|
643 | + return str_replace($query_param_sans_stars, $query_param_sans_gmt_and_sans_stars, $field_name); |
|
644 | + } |
|
645 | + |
|
646 | + |
|
647 | + |
|
648 | + /** |
|
649 | + * Takes a field name from the REST API and prepares it for the model querying |
|
650 | + * |
|
651 | + * @param string $field_name |
|
652 | + * @return string |
|
653 | + */ |
|
654 | + public static function prepareFieldNameFromJson($field_name) |
|
655 | + { |
|
656 | + if (ModelDataTranslator::isGmtDateFieldName($field_name)) { |
|
657 | + return ModelDataTranslator::removeGmtFromFieldName($field_name); |
|
658 | + } |
|
659 | + return $field_name; |
|
660 | + } |
|
661 | + |
|
662 | + |
|
663 | + |
|
664 | + /** |
|
665 | + * Takes array of field names from REST API and prepares for models |
|
666 | + * |
|
667 | + * @param array $field_names |
|
668 | + * @return array of field names (possibly include model prefixes) |
|
669 | + */ |
|
670 | + public static function prepareFieldNamesFromJson(array $field_names) |
|
671 | + { |
|
672 | + $new_array = array(); |
|
673 | + foreach ($field_names as $key => $field_name) { |
|
674 | + $new_array[$key] = ModelDataTranslator::prepareFieldNameFromJson($field_name); |
|
675 | + } |
|
676 | + return $new_array; |
|
677 | + } |
|
678 | + |
|
679 | + |
|
680 | + |
|
681 | + /** |
|
682 | + * Takes array where array keys are field names (possibly with model path prefixes) |
|
683 | + * from the REST API and prepares them for model querying |
|
684 | + * |
|
685 | + * @param array $field_names_as_keys |
|
686 | + * @return array |
|
687 | + */ |
|
688 | + public static function prepareFieldNamesInArrayKeysFromJson(array $field_names_as_keys) |
|
689 | + { |
|
690 | + $new_array = array(); |
|
691 | + foreach ($field_names_as_keys as $field_name => $value) { |
|
692 | + $new_array[ModelDataTranslator::prepareFieldNameFromJson($field_name)] = $value; |
|
693 | + } |
|
694 | + return $new_array; |
|
695 | + } |
|
696 | + |
|
697 | + |
|
698 | + |
|
699 | + /** |
|
700 | + * Prepares an array of model query params for use in the REST API |
|
701 | + * |
|
702 | + * @param array $model_query_params |
|
703 | + * @param EEM_Base $model |
|
704 | + * @param string $requested_version eg "4.8.36". If null is provided, defaults to the latest release of the EE4 |
|
705 | + * REST API |
|
706 | + * @return array which can be passed into the EE4 REST API when querying a model resource |
|
707 | + * @throws EE_Error |
|
708 | + */ |
|
709 | + public static function prepareQueryParamsForRestApi( |
|
710 | + array $model_query_params, |
|
711 | + EEM_Base $model, |
|
712 | + $requested_version = null |
|
713 | + ) { |
|
714 | + if ($requested_version === null) { |
|
715 | + $requested_version = \EED_Core_Rest_Api::latest_rest_api_version(); |
|
716 | + } |
|
717 | + $rest_query_params = $model_query_params; |
|
718 | + if (isset($model_query_params[0])) { |
|
719 | + $rest_query_params['where'] = ModelDataTranslator::prepareConditionsQueryParamsForRestApi( |
|
720 | + $model_query_params[0], |
|
721 | + $model, |
|
722 | + $requested_version |
|
723 | + ); |
|
724 | + unset($rest_query_params[0]); |
|
725 | + } |
|
726 | + if (isset($model_query_params['having'])) { |
|
727 | + $rest_query_params['having'] = ModelDataTranslator::prepareConditionsQueryParamsForRestApi( |
|
728 | + $model_query_params['having'], |
|
729 | + $model, |
|
730 | + $requested_version |
|
731 | + ); |
|
732 | + } |
|
733 | + return apply_filters( |
|
734 | + 'FHEE__EventEspresso\core\libraries\rest_api\Model_Data_Translator__prepare_query_params_for_rest_api', |
|
735 | + $rest_query_params, |
|
736 | + $model_query_params, |
|
737 | + $model, |
|
738 | + $requested_version |
|
739 | + ); |
|
740 | + } |
|
741 | + |
|
742 | + |
|
743 | + |
|
744 | + /** |
|
745 | + * Prepares all the sub-conditions query parameters (eg having or where conditions) for use in the rest api |
|
746 | + * |
|
747 | + * @param array $inputted_query_params_of_this_type eg like the "where" or "having" conditions query params |
|
748 | + * passed into EEM_Base::get_all() |
|
749 | + * @param EEM_Base $model |
|
750 | + * @param string $requested_version eg "4.8.36" |
|
751 | + * @return array ready for use in the rest api query params |
|
752 | + * @throws EE_Error |
|
753 | + * @throws ObjectDetectedException if somehow a PHP object were in the query params' values, |
|
754 | + * (which would be really unusual) |
|
755 | + */ |
|
756 | + public static function prepareConditionsQueryParamsForRestApi( |
|
757 | + $inputted_query_params_of_this_type, |
|
758 | + EEM_Base $model, |
|
759 | + $requested_version |
|
760 | + ) { |
|
761 | + $query_param_for_models = array(); |
|
762 | + foreach ($inputted_query_params_of_this_type as $query_param_key => $query_param_value) { |
|
763 | + $field = ModelDataTranslator::deduceFieldFromQueryParam( |
|
764 | + ModelDataTranslator::removeStarsAndAnythingAfterFromConditionQueryParamKey($query_param_key), |
|
765 | + $model |
|
766 | + ); |
|
767 | + if ($field instanceof EE_Model_Field_Base) { |
|
768 | + //did they specify an operator? |
|
769 | + if (is_array($query_param_value)) { |
|
770 | + $op = $query_param_value[0]; |
|
771 | + $translated_value = array($op); |
|
772 | + if (isset($query_param_value[1])) { |
|
773 | + $value = $query_param_value[1]; |
|
774 | + $translated_value[1] = ModelDataTranslator::prepareFieldValuesForJson( |
|
775 | + $field, |
|
776 | + $value, |
|
777 | + $requested_version |
|
778 | + ); |
|
779 | + } |
|
780 | + } else { |
|
781 | + $translated_value = ModelDataTranslator::prepareFieldValueForJson( |
|
782 | + $field, |
|
783 | + $query_param_value, |
|
784 | + $requested_version |
|
785 | + ); |
|
786 | + } |
|
787 | + $query_param_for_models[$query_param_key] = $translated_value; |
|
788 | + } else { |
|
789 | + //so it's not for a field, assume it's a logic query param key |
|
790 | + $query_param_for_models[$query_param_key] = ModelDataTranslator::prepareConditionsQueryParamsForRestApi( |
|
791 | + $query_param_value, |
|
792 | + $model, |
|
793 | + $requested_version |
|
794 | + ); |
|
795 | + } |
|
796 | + } |
|
797 | + return $query_param_for_models; |
|
798 | + } |
|
799 | + |
|
800 | + |
|
801 | + |
|
802 | + /** |
|
803 | + * @param $condition_query_param_key |
|
804 | + * @return string |
|
805 | + */ |
|
806 | + public static function removeStarsAndAnythingAfterFromConditionQueryParamKey($condition_query_param_key) |
|
807 | + { |
|
808 | + $pos_of_star = strpos($condition_query_param_key, '*'); |
|
809 | + if ($pos_of_star === false) { |
|
810 | + return $condition_query_param_key; |
|
811 | + } else { |
|
812 | + $condition_query_param_sans_star = substr($condition_query_param_key, 0, $pos_of_star); |
|
813 | + return $condition_query_param_sans_star; |
|
814 | + } |
|
815 | + } |
|
816 | + |
|
817 | + |
|
818 | + |
|
819 | + /** |
|
820 | + * Takes the input parameter and finds the model field that it indicates. |
|
821 | + * |
|
822 | + * @param string $query_param_name like Registration.Transaction.TXN_ID, Event.Datetime.start_time, or REG_ID |
|
823 | + * @param EEM_Base $model |
|
824 | + * @return EE_Model_Field_Base |
|
825 | + * @throws EE_Error |
|
826 | + */ |
|
827 | + public static function deduceFieldFromQueryParam($query_param_name, EEM_Base $model) |
|
828 | + { |
|
829 | + //ok, now proceed with deducing which part is the model's name, and which is the field's name |
|
830 | + //which will help us find the database table and column |
|
831 | + $query_param_parts = explode('.', $query_param_name); |
|
832 | + if (empty($query_param_parts)) { |
|
833 | + throw new EE_Error( |
|
834 | + sprintf( |
|
835 | + __( |
|
836 | + '_extract_column_name is empty when trying to extract column and table name from %s', |
|
837 | + 'event_espresso' |
|
838 | + ), |
|
839 | + $query_param_name |
|
840 | + ) |
|
841 | + ); |
|
842 | + } |
|
843 | + $number_of_parts = count($query_param_parts); |
|
844 | + $last_query_param_part = $query_param_parts[count($query_param_parts) - 1]; |
|
845 | + if ($number_of_parts === 1) { |
|
846 | + $field_name = $last_query_param_part; |
|
847 | + } else {// $number_of_parts >= 2 |
|
848 | + //the last part is the column name, and there are only 2parts. therefore... |
|
849 | + $field_name = $last_query_param_part; |
|
850 | + $model = \EE_Registry::instance()->load_model($query_param_parts[$number_of_parts - 2]); |
|
851 | + } |
|
852 | + try { |
|
853 | + return $model->field_settings_for($field_name, false); |
|
854 | + } catch (EE_Error $e) { |
|
855 | + return null; |
|
856 | + } |
|
857 | + } |
|
858 | + |
|
859 | + |
|
860 | + |
|
861 | + /** |
|
862 | + * Returns true if $data can be easily represented in JSON. |
|
863 | + * Basically, objects and resources can't be represented in JSON easily. |
|
864 | + * @param mixed $data |
|
865 | + * @return bool |
|
866 | + */ |
|
867 | + protected static function isRepresentableInJson($data) |
|
868 | + { |
|
869 | + return is_scalar($data) |
|
870 | + || is_array($data) |
|
871 | + || is_null($data); |
|
872 | + } |
|
873 | 873 | } |
@@ -11,7 +11,7 @@ discard block |
||
11 | 11 | use EE_Serialized_Text_Field; |
12 | 12 | use EEM_Base; |
13 | 13 | |
14 | -if (! defined('EVENT_ESPRESSO_VERSION')) { |
|
14 | +if ( ! defined('EVENT_ESPRESSO_VERSION')) { |
|
15 | 15 | exit('No direct script access allowed'); |
16 | 16 | } |
17 | 17 | |
@@ -228,7 +228,7 @@ discard block |
||
228 | 228 | '0', |
229 | 229 | STR_PAD_LEFT |
230 | 230 | ); |
231 | - return $original_timestamp . $offset_sign . $offset_string; |
|
231 | + return $original_timestamp.$offset_sign.$offset_string; |
|
232 | 232 | } |
233 | 233 | |
234 | 234 | |
@@ -272,10 +272,10 @@ discard block |
||
272 | 272 | */ |
273 | 273 | private static function parseTimezoneOffset($timezone_offset) |
274 | 274 | { |
275 | - $first_char = substr((string)$timezone_offset, 0, 1); |
|
275 | + $first_char = substr((string) $timezone_offset, 0, 1); |
|
276 | 276 | if ($first_char === '+' || $first_char === '-') { |
277 | 277 | $offset_sign = $first_char; |
278 | - $offset_secs = substr((string)$timezone_offset, 1); |
|
278 | + $offset_secs = substr((string) $timezone_offset, 1); |
|
279 | 279 | } else { |
280 | 280 | $offset_sign = '+'; |
281 | 281 | $offset_secs = $timezone_offset; |
@@ -302,12 +302,12 @@ discard block |
||
302 | 302 | //did they submit a string of a unix timestamp? |
303 | 303 | if (is_numeric($original_value)) { |
304 | 304 | $datetime_obj = new \DateTime(); |
305 | - $datetime_obj->setTimestamp((int)$original_value); |
|
305 | + $datetime_obj->setTimestamp((int) $original_value); |
|
306 | 306 | } else { |
307 | 307 | //first, check if its a MySQL timestamp in GMT |
308 | 308 | $datetime_obj = \DateTime::createFromFormat('Y-m-d H:i:s', $original_value); |
309 | 309 | } |
310 | - if (! $datetime_obj instanceof \DateTime) { |
|
310 | + if ( ! $datetime_obj instanceof \DateTime) { |
|
311 | 311 | //so it's not a unix timestamp or a MySQL timestamp. Maybe its in the field's date/time format? |
312 | 312 | $datetime_obj = $field_obj->prepare_for_set($original_value); |
313 | 313 | } |
@@ -317,7 +317,7 @@ discard block |
||
317 | 317 | $new_value = $original_value->format('Y-m-d H:i:s'); |
318 | 318 | } elseif (is_int($original_value) || is_float($original_value)) { |
319 | 319 | $new_value = date('Y-m-d H:i:s', $original_value); |
320 | - } elseif($original_value === null || $original_value === '') { |
|
320 | + } elseif ($original_value === null || $original_value === '') { |
|
321 | 321 | $new_value = null; |
322 | 322 | } else { |
323 | 323 | //so it's not a datetime object, unix timestamp (as string or int), |
@@ -333,7 +333,7 @@ discard block |
||
333 | 333 | $original_value, |
334 | 334 | $field_obj->get_name(), |
335 | 335 | $field_obj->get_model_name(), |
336 | - $field_obj->get_time_format() . ' ' . $field_obj->get_time_format() |
|
336 | + $field_obj->get_time_format().' '.$field_obj->get_time_format() |
|
337 | 337 | ) |
338 | 338 | ); |
339 | 339 | } |
@@ -343,7 +343,7 @@ discard block |
||
343 | 343 | } |
344 | 344 | //are we about to send an object? just don't. We have no good way to represent it in JSON. |
345 | 345 | // can't just check using is_object() because that missed PHP incomplete objects |
346 | - if (! ModelDataTranslator::isRepresentableInJson($new_value)) { |
|
346 | + if ( ! ModelDataTranslator::isRepresentableInJson($new_value)) { |
|
347 | 347 | $new_value = array( |
348 | 348 | 'error_code' => 'php_object_not_return', |
349 | 349 | 'error_message' => esc_html__('The value of this field in the database is a PHP object, which can\'t be represented in JSON.', 'event_espresso') |
@@ -393,7 +393,7 @@ discard block |
||
393 | 393 | $model |
394 | 394 | ); |
395 | 395 | //double-check is it a *_gmt field? |
396 | - if (! $field instanceof EE_Model_Field_Base |
|
396 | + if ( ! $field instanceof EE_Model_Field_Base |
|
397 | 397 | && ModelDataTranslator::isGmtDateFieldName($query_param_sans_stars) |
398 | 398 | ) { |
399 | 399 | //yep, take off '_gmt', and find the field |
@@ -412,8 +412,8 @@ discard block |
||
412 | 412 | $timezone = $model->get_timezone(); |
413 | 413 | } |
414 | 414 | if ($field instanceof EE_Model_Field_Base) { |
415 | - if (! $writing && is_array($query_param_value)) { |
|
416 | - if (! \EEH_Array::is_array_numerically_and_sequentially_indexed($query_param_value)) { |
|
415 | + if ( ! $writing && is_array($query_param_value)) { |
|
416 | + if ( ! \EEH_Array::is_array_numerically_and_sequentially_indexed($query_param_value)) { |
|
417 | 417 | if (defined('EE_REST_API_DEBUG_MODE') && EE_REST_API_DEBUG_MODE) { |
418 | 418 | throw new RestException( |
419 | 419 | 'numerically_indexed_array_of_values_only', |
@@ -448,7 +448,7 @@ discard block |
||
448 | 448 | ); |
449 | 449 | } elseif (array_key_exists($op, $model->valid_between_style_operators()) |
450 | 450 | && isset($query_param_value[1], $query_param_value[2]) |
451 | - && !isset($query_param_value[3]) |
|
451 | + && ! isset($query_param_value[3]) |
|
452 | 452 | ) { |
453 | 453 | $translated_value[] = ModelDataTranslator::prepareFieldValuesFromJson( |
454 | 454 | $field, |
@@ -472,10 +472,10 @@ discard block |
||
472 | 472 | ModelDataTranslator::throwExceptionIfContainsSerializedData($query_param_value[1]); |
473 | 473 | $translated_value[] = $query_param_value[1]; |
474 | 474 | } elseif (array_key_exists($op, $model->valid_null_style_operators()) |
475 | - && !isset($query_param_value[1])) { |
|
475 | + && ! isset($query_param_value[1])) { |
|
476 | 476 | //no arguments should have been provided, so don't look for any |
477 | 477 | } elseif (isset($query_param_value[1]) |
478 | - && !isset($query_param_value[2]) |
|
478 | + && ! isset($query_param_value[2]) |
|
479 | 479 | && ! array_key_exists( |
480 | 480 | $op, |
481 | 481 | array_merge( |
@@ -626,7 +626,7 @@ discard block |
||
626 | 626 | */ |
627 | 627 | public static function removeGmtFromFieldName($field_name) |
628 | 628 | { |
629 | - if (! ModelDataTranslator::isGmtDateFieldName($field_name)) { |
|
629 | + if ( ! ModelDataTranslator::isGmtDateFieldName($field_name)) { |
|
630 | 630 | return $field_name; |
631 | 631 | } |
632 | 632 | $query_param_sans_stars = ModelDataTranslator::removeStarsAndAnythingAfterFromConditionQueryParamKey( |
@@ -21,1015 +21,1015 @@ |
||
21 | 21 | { |
22 | 22 | |
23 | 23 | |
24 | - /** |
|
25 | - * return the timezone set for the WP install |
|
26 | - * |
|
27 | - * @return string valid timezone string for PHP DateTimeZone() class |
|
28 | - * @throws InvalidArgumentException |
|
29 | - * @throws InvalidDataTypeException |
|
30 | - * @throws InvalidInterfaceException |
|
31 | - */ |
|
32 | - public static function get_timezone() |
|
33 | - { |
|
34 | - return EEH_DTT_Helper::get_valid_timezone_string(); |
|
35 | - } |
|
24 | + /** |
|
25 | + * return the timezone set for the WP install |
|
26 | + * |
|
27 | + * @return string valid timezone string for PHP DateTimeZone() class |
|
28 | + * @throws InvalidArgumentException |
|
29 | + * @throws InvalidDataTypeException |
|
30 | + * @throws InvalidInterfaceException |
|
31 | + */ |
|
32 | + public static function get_timezone() |
|
33 | + { |
|
34 | + return EEH_DTT_Helper::get_valid_timezone_string(); |
|
35 | + } |
|
36 | 36 | |
37 | 37 | |
38 | - /** |
|
39 | - * get_valid_timezone_string |
|
40 | - * ensures that a valid timezone string is returned |
|
41 | - * |
|
42 | - * @param string $timezone_string |
|
43 | - * @return string |
|
44 | - * @throws InvalidArgumentException |
|
45 | - * @throws InvalidDataTypeException |
|
46 | - * @throws InvalidInterfaceException |
|
47 | - */ |
|
48 | - public static function get_valid_timezone_string($timezone_string = '') |
|
49 | - { |
|
50 | - return self::getHelperAdapter()->getValidTimezoneString($timezone_string); |
|
51 | - } |
|
38 | + /** |
|
39 | + * get_valid_timezone_string |
|
40 | + * ensures that a valid timezone string is returned |
|
41 | + * |
|
42 | + * @param string $timezone_string |
|
43 | + * @return string |
|
44 | + * @throws InvalidArgumentException |
|
45 | + * @throws InvalidDataTypeException |
|
46 | + * @throws InvalidInterfaceException |
|
47 | + */ |
|
48 | + public static function get_valid_timezone_string($timezone_string = '') |
|
49 | + { |
|
50 | + return self::getHelperAdapter()->getValidTimezoneString($timezone_string); |
|
51 | + } |
|
52 | 52 | |
53 | 53 | |
54 | - /** |
|
55 | - * This only purpose for this static method is to validate that the incoming timezone is a valid php timezone. |
|
56 | - * |
|
57 | - * @static |
|
58 | - * @param string $timezone_string Timezone string to check |
|
59 | - * @param bool $throw_error |
|
60 | - * @return bool |
|
61 | - * @throws InvalidArgumentException |
|
62 | - * @throws InvalidDataTypeException |
|
63 | - * @throws InvalidInterfaceException |
|
64 | - */ |
|
65 | - public static function validate_timezone($timezone_string, $throw_error = true) |
|
66 | - { |
|
67 | - return self::getHelperAdapter()->validateTimezone($timezone_string, $throw_error); |
|
68 | - } |
|
54 | + /** |
|
55 | + * This only purpose for this static method is to validate that the incoming timezone is a valid php timezone. |
|
56 | + * |
|
57 | + * @static |
|
58 | + * @param string $timezone_string Timezone string to check |
|
59 | + * @param bool $throw_error |
|
60 | + * @return bool |
|
61 | + * @throws InvalidArgumentException |
|
62 | + * @throws InvalidDataTypeException |
|
63 | + * @throws InvalidInterfaceException |
|
64 | + */ |
|
65 | + public static function validate_timezone($timezone_string, $throw_error = true) |
|
66 | + { |
|
67 | + return self::getHelperAdapter()->validateTimezone($timezone_string, $throw_error); |
|
68 | + } |
|
69 | 69 | |
70 | 70 | |
71 | - /** |
|
72 | - * This returns a string that can represent the provided gmt offset in format that can be passed into |
|
73 | - * DateTimeZone. This is NOT a string that can be passed as a value on the WordPress timezone_string option. |
|
74 | - * |
|
75 | - * @param float|string $gmt_offset |
|
76 | - * @return string |
|
77 | - * @throws InvalidArgumentException |
|
78 | - * @throws InvalidDataTypeException |
|
79 | - * @throws InvalidInterfaceException |
|
80 | - */ |
|
81 | - public static function get_timezone_string_from_gmt_offset($gmt_offset = '') |
|
82 | - { |
|
83 | - return self::getHelperAdapter()->getTimezoneStringFromGmtOffset($gmt_offset); |
|
84 | - } |
|
71 | + /** |
|
72 | + * This returns a string that can represent the provided gmt offset in format that can be passed into |
|
73 | + * DateTimeZone. This is NOT a string that can be passed as a value on the WordPress timezone_string option. |
|
74 | + * |
|
75 | + * @param float|string $gmt_offset |
|
76 | + * @return string |
|
77 | + * @throws InvalidArgumentException |
|
78 | + * @throws InvalidDataTypeException |
|
79 | + * @throws InvalidInterfaceException |
|
80 | + */ |
|
81 | + public static function get_timezone_string_from_gmt_offset($gmt_offset = '') |
|
82 | + { |
|
83 | + return self::getHelperAdapter()->getTimezoneStringFromGmtOffset($gmt_offset); |
|
84 | + } |
|
85 | 85 | |
86 | 86 | |
87 | - /** |
|
88 | - * Gets the site's GMT offset based on either the timezone string |
|
89 | - * (in which case teh gmt offset will vary depending on the location's |
|
90 | - * observance of daylight savings time) or the gmt_offset wp option |
|
91 | - * |
|
92 | - * @return int seconds offset |
|
93 | - * @throws InvalidArgumentException |
|
94 | - * @throws InvalidDataTypeException |
|
95 | - * @throws InvalidInterfaceException |
|
96 | - */ |
|
97 | - public static function get_site_timezone_gmt_offset() |
|
98 | - { |
|
99 | - return self::getHelperAdapter()->getSiteTimezoneGmtOffset(); |
|
100 | - } |
|
87 | + /** |
|
88 | + * Gets the site's GMT offset based on either the timezone string |
|
89 | + * (in which case teh gmt offset will vary depending on the location's |
|
90 | + * observance of daylight savings time) or the gmt_offset wp option |
|
91 | + * |
|
92 | + * @return int seconds offset |
|
93 | + * @throws InvalidArgumentException |
|
94 | + * @throws InvalidDataTypeException |
|
95 | + * @throws InvalidInterfaceException |
|
96 | + */ |
|
97 | + public static function get_site_timezone_gmt_offset() |
|
98 | + { |
|
99 | + return self::getHelperAdapter()->getSiteTimezoneGmtOffset(); |
|
100 | + } |
|
101 | 101 | |
102 | 102 | |
103 | - /** |
|
104 | - * Depending on PHP version, |
|
105 | - * there might not be valid current timezone strings to match these gmt_offsets in its timezone tables. |
|
106 | - * To get around that, for these fringe timezones we bump them to a known valid offset. |
|
107 | - * This method should ONLY be called after first verifying an timezone_string cannot be retrieved for the offset. |
|
108 | - * |
|
109 | - * @deprecated 4.9.54.rc Developers this was always meant to only be an internally used method. This will be |
|
110 | - * removed in a future version of EE. |
|
111 | - * @param int $gmt_offset |
|
112 | - * @return int |
|
113 | - * @throws InvalidArgumentException |
|
114 | - * @throws InvalidDataTypeException |
|
115 | - * @throws InvalidInterfaceException |
|
116 | - */ |
|
117 | - public static function adjust_invalid_gmt_offsets($gmt_offset = 0) |
|
118 | - { |
|
119 | - return self::getHelperAdapter()->adjustInvalidGmtOffsets($gmt_offset); |
|
120 | - } |
|
103 | + /** |
|
104 | + * Depending on PHP version, |
|
105 | + * there might not be valid current timezone strings to match these gmt_offsets in its timezone tables. |
|
106 | + * To get around that, for these fringe timezones we bump them to a known valid offset. |
|
107 | + * This method should ONLY be called after first verifying an timezone_string cannot be retrieved for the offset. |
|
108 | + * |
|
109 | + * @deprecated 4.9.54.rc Developers this was always meant to only be an internally used method. This will be |
|
110 | + * removed in a future version of EE. |
|
111 | + * @param int $gmt_offset |
|
112 | + * @return int |
|
113 | + * @throws InvalidArgumentException |
|
114 | + * @throws InvalidDataTypeException |
|
115 | + * @throws InvalidInterfaceException |
|
116 | + */ |
|
117 | + public static function adjust_invalid_gmt_offsets($gmt_offset = 0) |
|
118 | + { |
|
119 | + return self::getHelperAdapter()->adjustInvalidGmtOffsets($gmt_offset); |
|
120 | + } |
|
121 | 121 | |
122 | 122 | |
123 | - /** |
|
124 | - * get_timezone_string_from_abbreviations_list |
|
125 | - * |
|
126 | - * @deprecated 4.9.54.rc Developers, this was never intended to be public. This is a soft deprecation for now. |
|
127 | - * If you are using this, you'll want to work out an alternate way of getting the value. |
|
128 | - * @param int $gmt_offset |
|
129 | - * @param bool $coerce If true, we attempt to coerce with our adjustment table @see self::adjust_invalid_gmt_offset. |
|
130 | - * @return string |
|
131 | - * @throws EE_Error |
|
132 | - * @throws InvalidArgumentException |
|
133 | - * @throws InvalidDataTypeException |
|
134 | - * @throws InvalidInterfaceException |
|
135 | - */ |
|
136 | - public static function get_timezone_string_from_abbreviations_list($gmt_offset = 0, $coerce = true) |
|
137 | - { |
|
138 | - $gmt_offset = (int) $gmt_offset; |
|
139 | - /** @var array[] $abbreviations */ |
|
140 | - $abbreviations = DateTimeZone::listAbbreviations(); |
|
141 | - foreach ($abbreviations as $abbreviation) { |
|
142 | - foreach ($abbreviation as $timezone) { |
|
143 | - if ((int) $timezone['offset'] === $gmt_offset && (bool) $timezone['dst'] === false) { |
|
144 | - try { |
|
145 | - $offset = self::get_timezone_offset(new DateTimeZone($timezone['timezone_id'])); |
|
146 | - if ($offset !== $gmt_offset) { |
|
147 | - continue; |
|
148 | - } |
|
149 | - return $timezone['timezone_id']; |
|
150 | - } catch (Exception $e) { |
|
151 | - continue; |
|
152 | - } |
|
153 | - } |
|
154 | - } |
|
155 | - } |
|
156 | - //if $coerce is true, let's see if we can get a timezone string after the offset is adjusted |
|
157 | - if ($coerce === true) { |
|
158 | - $timezone_string = self::get_timezone_string_from_abbreviations_list( |
|
159 | - self::adjust_invalid_gmt_offsets($gmt_offset), |
|
160 | - false |
|
161 | - ); |
|
162 | - if ($timezone_string) { |
|
163 | - return $timezone_string; |
|
164 | - } |
|
165 | - } |
|
166 | - throw new EE_Error( |
|
167 | - sprintf( |
|
168 | - esc_html__( |
|
169 | - 'The provided GMT offset (%1$s), is invalid, please check with %2$sthis list%3$s for what valid timezones can be used', |
|
170 | - 'event_espresso' |
|
171 | - ), |
|
172 | - $gmt_offset / HOUR_IN_SECONDS, |
|
173 | - '<a href="http://www.php.net/manual/en/timezones.php">', |
|
174 | - '</a>' |
|
175 | - ) |
|
176 | - ); |
|
177 | - } |
|
123 | + /** |
|
124 | + * get_timezone_string_from_abbreviations_list |
|
125 | + * |
|
126 | + * @deprecated 4.9.54.rc Developers, this was never intended to be public. This is a soft deprecation for now. |
|
127 | + * If you are using this, you'll want to work out an alternate way of getting the value. |
|
128 | + * @param int $gmt_offset |
|
129 | + * @param bool $coerce If true, we attempt to coerce with our adjustment table @see self::adjust_invalid_gmt_offset. |
|
130 | + * @return string |
|
131 | + * @throws EE_Error |
|
132 | + * @throws InvalidArgumentException |
|
133 | + * @throws InvalidDataTypeException |
|
134 | + * @throws InvalidInterfaceException |
|
135 | + */ |
|
136 | + public static function get_timezone_string_from_abbreviations_list($gmt_offset = 0, $coerce = true) |
|
137 | + { |
|
138 | + $gmt_offset = (int) $gmt_offset; |
|
139 | + /** @var array[] $abbreviations */ |
|
140 | + $abbreviations = DateTimeZone::listAbbreviations(); |
|
141 | + foreach ($abbreviations as $abbreviation) { |
|
142 | + foreach ($abbreviation as $timezone) { |
|
143 | + if ((int) $timezone['offset'] === $gmt_offset && (bool) $timezone['dst'] === false) { |
|
144 | + try { |
|
145 | + $offset = self::get_timezone_offset(new DateTimeZone($timezone['timezone_id'])); |
|
146 | + if ($offset !== $gmt_offset) { |
|
147 | + continue; |
|
148 | + } |
|
149 | + return $timezone['timezone_id']; |
|
150 | + } catch (Exception $e) { |
|
151 | + continue; |
|
152 | + } |
|
153 | + } |
|
154 | + } |
|
155 | + } |
|
156 | + //if $coerce is true, let's see if we can get a timezone string after the offset is adjusted |
|
157 | + if ($coerce === true) { |
|
158 | + $timezone_string = self::get_timezone_string_from_abbreviations_list( |
|
159 | + self::adjust_invalid_gmt_offsets($gmt_offset), |
|
160 | + false |
|
161 | + ); |
|
162 | + if ($timezone_string) { |
|
163 | + return $timezone_string; |
|
164 | + } |
|
165 | + } |
|
166 | + throw new EE_Error( |
|
167 | + sprintf( |
|
168 | + esc_html__( |
|
169 | + 'The provided GMT offset (%1$s), is invalid, please check with %2$sthis list%3$s for what valid timezones can be used', |
|
170 | + 'event_espresso' |
|
171 | + ), |
|
172 | + $gmt_offset / HOUR_IN_SECONDS, |
|
173 | + '<a href="http://www.php.net/manual/en/timezones.php">', |
|
174 | + '</a>' |
|
175 | + ) |
|
176 | + ); |
|
177 | + } |
|
178 | 178 | |
179 | 179 | |
180 | - /** |
|
181 | - * Get Timezone Transitions |
|
182 | - * |
|
183 | - * @param DateTimeZone $date_time_zone |
|
184 | - * @param int|null $time |
|
185 | - * @param bool $first_only |
|
186 | - * @return array |
|
187 | - * @throws InvalidArgumentException |
|
188 | - * @throws InvalidDataTypeException |
|
189 | - * @throws InvalidInterfaceException |
|
190 | - */ |
|
191 | - public static function get_timezone_transitions(DateTimeZone $date_time_zone, $time = null, $first_only = true) |
|
192 | - { |
|
193 | - return self::getHelperAdapter()->getTimezoneTransitions($date_time_zone, $time, $first_only); |
|
194 | - } |
|
180 | + /** |
|
181 | + * Get Timezone Transitions |
|
182 | + * |
|
183 | + * @param DateTimeZone $date_time_zone |
|
184 | + * @param int|null $time |
|
185 | + * @param bool $first_only |
|
186 | + * @return array |
|
187 | + * @throws InvalidArgumentException |
|
188 | + * @throws InvalidDataTypeException |
|
189 | + * @throws InvalidInterfaceException |
|
190 | + */ |
|
191 | + public static function get_timezone_transitions(DateTimeZone $date_time_zone, $time = null, $first_only = true) |
|
192 | + { |
|
193 | + return self::getHelperAdapter()->getTimezoneTransitions($date_time_zone, $time, $first_only); |
|
194 | + } |
|
195 | 195 | |
196 | 196 | |
197 | - /** |
|
198 | - * Get Timezone Offset for given timezone object. |
|
199 | - * |
|
200 | - * @param DateTimeZone $date_time_zone |
|
201 | - * @param null $time |
|
202 | - * @return mixed |
|
203 | - * @throws InvalidArgumentException |
|
204 | - * @throws InvalidDataTypeException |
|
205 | - * @throws InvalidInterfaceException |
|
206 | - */ |
|
207 | - public static function get_timezone_offset(DateTimeZone $date_time_zone, $time = null) |
|
208 | - { |
|
209 | - return self::getHelperAdapter()->getTimezoneOffset($date_time_zone, $time); |
|
210 | - } |
|
197 | + /** |
|
198 | + * Get Timezone Offset for given timezone object. |
|
199 | + * |
|
200 | + * @param DateTimeZone $date_time_zone |
|
201 | + * @param null $time |
|
202 | + * @return mixed |
|
203 | + * @throws InvalidArgumentException |
|
204 | + * @throws InvalidDataTypeException |
|
205 | + * @throws InvalidInterfaceException |
|
206 | + */ |
|
207 | + public static function get_timezone_offset(DateTimeZone $date_time_zone, $time = null) |
|
208 | + { |
|
209 | + return self::getHelperAdapter()->getTimezoneOffset($date_time_zone, $time); |
|
210 | + } |
|
211 | 211 | |
212 | 212 | |
213 | - /** |
|
214 | - * Prints a select input for the given timezone string. |
|
215 | - * @param string $timezone_string |
|
216 | - * @deprecatd 4.9.54.rc Soft deprecation. Consider using \EEH_DTT_Helper::wp_timezone_choice instead. |
|
217 | - * @throws InvalidArgumentException |
|
218 | - * @throws InvalidDataTypeException |
|
219 | - * @throws InvalidInterfaceException |
|
220 | - */ |
|
221 | - public static function timezone_select_input($timezone_string = '') |
|
222 | - { |
|
223 | - self::getHelperAdapter()->timezoneSelectInput($timezone_string); |
|
224 | - } |
|
213 | + /** |
|
214 | + * Prints a select input for the given timezone string. |
|
215 | + * @param string $timezone_string |
|
216 | + * @deprecatd 4.9.54.rc Soft deprecation. Consider using \EEH_DTT_Helper::wp_timezone_choice instead. |
|
217 | + * @throws InvalidArgumentException |
|
218 | + * @throws InvalidDataTypeException |
|
219 | + * @throws InvalidInterfaceException |
|
220 | + */ |
|
221 | + public static function timezone_select_input($timezone_string = '') |
|
222 | + { |
|
223 | + self::getHelperAdapter()->timezoneSelectInput($timezone_string); |
|
224 | + } |
|
225 | 225 | |
226 | 226 | |
227 | - /** |
|
228 | - * This method will take an incoming unix timestamp and add the offset to it for the given timezone_string. |
|
229 | - * If no unix timestamp is given then time() is used. If no timezone is given then the set timezone string for |
|
230 | - * the site is used. |
|
231 | - * This is used typically when using a Unix timestamp any core WP functions that expect their specially |
|
232 | - * computed timestamp (i.e. date_i18n() ) |
|
233 | - * |
|
234 | - * @param int $unix_timestamp if 0, then time() will be used. |
|
235 | - * @param string $timezone_string timezone_string. If empty, then the current set timezone for the |
|
236 | - * site will be used. |
|
237 | - * @return int $unix_timestamp with the offset applied for the given timezone. |
|
238 | - * @throws InvalidArgumentException |
|
239 | - * @throws InvalidDataTypeException |
|
240 | - * @throws InvalidInterfaceException |
|
241 | - */ |
|
242 | - public static function get_timestamp_with_offset($unix_timestamp = 0, $timezone_string = '') |
|
243 | - { |
|
244 | - return self::getHelperAdapter()->getTimestampWithOffset($unix_timestamp, $timezone_string); |
|
245 | - } |
|
227 | + /** |
|
228 | + * This method will take an incoming unix timestamp and add the offset to it for the given timezone_string. |
|
229 | + * If no unix timestamp is given then time() is used. If no timezone is given then the set timezone string for |
|
230 | + * the site is used. |
|
231 | + * This is used typically when using a Unix timestamp any core WP functions that expect their specially |
|
232 | + * computed timestamp (i.e. date_i18n() ) |
|
233 | + * |
|
234 | + * @param int $unix_timestamp if 0, then time() will be used. |
|
235 | + * @param string $timezone_string timezone_string. If empty, then the current set timezone for the |
|
236 | + * site will be used. |
|
237 | + * @return int $unix_timestamp with the offset applied for the given timezone. |
|
238 | + * @throws InvalidArgumentException |
|
239 | + * @throws InvalidDataTypeException |
|
240 | + * @throws InvalidInterfaceException |
|
241 | + */ |
|
242 | + public static function get_timestamp_with_offset($unix_timestamp = 0, $timezone_string = '') |
|
243 | + { |
|
244 | + return self::getHelperAdapter()->getTimestampWithOffset($unix_timestamp, $timezone_string); |
|
245 | + } |
|
246 | 246 | |
247 | 247 | |
248 | - /** |
|
249 | - * _set_date_time_field |
|
250 | - * modifies EE_Base_Class EE_Datetime_Field objects |
|
251 | - * |
|
252 | - * @param EE_Base_Class $obj EE_Base_Class object |
|
253 | - * @param DateTime $DateTime PHP DateTime object |
|
254 | - * @param string $datetime_field_name the datetime fieldname to be manipulated |
|
255 | - * @return EE_Base_Class |
|
256 | - * @throws EE_Error |
|
257 | - */ |
|
258 | - protected static function _set_date_time_field(EE_Base_Class $obj, DateTime $DateTime, $datetime_field_name) |
|
259 | - { |
|
260 | - // grab current datetime format |
|
261 | - $current_format = $obj->get_format(); |
|
262 | - // set new full timestamp format |
|
263 | - $obj->set_date_format(EE_Datetime_Field::mysql_date_format); |
|
264 | - $obj->set_time_format(EE_Datetime_Field::mysql_time_format); |
|
265 | - // set the new date value using a full timestamp format so that no data is lost |
|
266 | - $obj->set($datetime_field_name, $DateTime->format(EE_Datetime_Field::mysql_timestamp_format)); |
|
267 | - // reset datetime formats |
|
268 | - $obj->set_date_format($current_format[0]); |
|
269 | - $obj->set_time_format($current_format[1]); |
|
270 | - return $obj; |
|
271 | - } |
|
248 | + /** |
|
249 | + * _set_date_time_field |
|
250 | + * modifies EE_Base_Class EE_Datetime_Field objects |
|
251 | + * |
|
252 | + * @param EE_Base_Class $obj EE_Base_Class object |
|
253 | + * @param DateTime $DateTime PHP DateTime object |
|
254 | + * @param string $datetime_field_name the datetime fieldname to be manipulated |
|
255 | + * @return EE_Base_Class |
|
256 | + * @throws EE_Error |
|
257 | + */ |
|
258 | + protected static function _set_date_time_field(EE_Base_Class $obj, DateTime $DateTime, $datetime_field_name) |
|
259 | + { |
|
260 | + // grab current datetime format |
|
261 | + $current_format = $obj->get_format(); |
|
262 | + // set new full timestamp format |
|
263 | + $obj->set_date_format(EE_Datetime_Field::mysql_date_format); |
|
264 | + $obj->set_time_format(EE_Datetime_Field::mysql_time_format); |
|
265 | + // set the new date value using a full timestamp format so that no data is lost |
|
266 | + $obj->set($datetime_field_name, $DateTime->format(EE_Datetime_Field::mysql_timestamp_format)); |
|
267 | + // reset datetime formats |
|
268 | + $obj->set_date_format($current_format[0]); |
|
269 | + $obj->set_time_format($current_format[1]); |
|
270 | + return $obj; |
|
271 | + } |
|
272 | 272 | |
273 | 273 | |
274 | - /** |
|
275 | - * date_time_add |
|
276 | - * helper for doing simple datetime calculations on a given datetime from EE_Base_Class |
|
277 | - * and modifying it IN the EE_Base_Class so you don't have to do anything else. |
|
278 | - * |
|
279 | - * @param EE_Base_Class $obj EE_Base_Class object |
|
280 | - * @param string $datetime_field_name name of the EE_Datetime_Filed datatype db column to be manipulated |
|
281 | - * @param string $period what you are adding. The options are (years, months, days, hours, |
|
282 | - * minutes, seconds) defaults to years |
|
283 | - * @param integer $value what you want to increment the time by |
|
284 | - * @return EE_Base_Class return the EE_Base_Class object so right away you can do something with it |
|
285 | - * (chaining) |
|
286 | - * @throws EE_Error |
|
287 | - * @throws Exception |
|
288 | - */ |
|
289 | - public static function date_time_add(EE_Base_Class $obj, $datetime_field_name, $period = 'years', $value = 1) |
|
290 | - { |
|
291 | - //get the raw UTC date. |
|
292 | - $DateTime = $obj->get_DateTime_object($datetime_field_name); |
|
293 | - $DateTime = EEH_DTT_Helper::calc_date($DateTime, $period, $value); |
|
294 | - return EEH_DTT_Helper::_set_date_time_field($obj, $DateTime, $datetime_field_name); |
|
295 | - } |
|
274 | + /** |
|
275 | + * date_time_add |
|
276 | + * helper for doing simple datetime calculations on a given datetime from EE_Base_Class |
|
277 | + * and modifying it IN the EE_Base_Class so you don't have to do anything else. |
|
278 | + * |
|
279 | + * @param EE_Base_Class $obj EE_Base_Class object |
|
280 | + * @param string $datetime_field_name name of the EE_Datetime_Filed datatype db column to be manipulated |
|
281 | + * @param string $period what you are adding. The options are (years, months, days, hours, |
|
282 | + * minutes, seconds) defaults to years |
|
283 | + * @param integer $value what you want to increment the time by |
|
284 | + * @return EE_Base_Class return the EE_Base_Class object so right away you can do something with it |
|
285 | + * (chaining) |
|
286 | + * @throws EE_Error |
|
287 | + * @throws Exception |
|
288 | + */ |
|
289 | + public static function date_time_add(EE_Base_Class $obj, $datetime_field_name, $period = 'years', $value = 1) |
|
290 | + { |
|
291 | + //get the raw UTC date. |
|
292 | + $DateTime = $obj->get_DateTime_object($datetime_field_name); |
|
293 | + $DateTime = EEH_DTT_Helper::calc_date($DateTime, $period, $value); |
|
294 | + return EEH_DTT_Helper::_set_date_time_field($obj, $DateTime, $datetime_field_name); |
|
295 | + } |
|
296 | 296 | |
297 | 297 | |
298 | - /** |
|
299 | - * date_time_subtract |
|
300 | - * same as date_time_add except subtracting value instead of adding. |
|
301 | - * |
|
302 | - * @param EE_Base_Class $obj |
|
303 | - * @param string $datetime_field_name name of the EE_Datetime_Filed datatype db column to be manipulated |
|
304 | - * @param string $period |
|
305 | - * @param int $value |
|
306 | - * @return EE_Base_Class |
|
307 | - * @throws EE_Error |
|
308 | - * @throws Exception |
|
309 | - */ |
|
310 | - public static function date_time_subtract(EE_Base_Class $obj, $datetime_field_name, $period = 'years', $value = 1) |
|
311 | - { |
|
312 | - //get the raw UTC date |
|
313 | - $DateTime = $obj->get_DateTime_object($datetime_field_name); |
|
314 | - $DateTime = EEH_DTT_Helper::calc_date($DateTime, $period, $value, '-'); |
|
315 | - return EEH_DTT_Helper::_set_date_time_field($obj, $DateTime, $datetime_field_name); |
|
316 | - } |
|
298 | + /** |
|
299 | + * date_time_subtract |
|
300 | + * same as date_time_add except subtracting value instead of adding. |
|
301 | + * |
|
302 | + * @param EE_Base_Class $obj |
|
303 | + * @param string $datetime_field_name name of the EE_Datetime_Filed datatype db column to be manipulated |
|
304 | + * @param string $period |
|
305 | + * @param int $value |
|
306 | + * @return EE_Base_Class |
|
307 | + * @throws EE_Error |
|
308 | + * @throws Exception |
|
309 | + */ |
|
310 | + public static function date_time_subtract(EE_Base_Class $obj, $datetime_field_name, $period = 'years', $value = 1) |
|
311 | + { |
|
312 | + //get the raw UTC date |
|
313 | + $DateTime = $obj->get_DateTime_object($datetime_field_name); |
|
314 | + $DateTime = EEH_DTT_Helper::calc_date($DateTime, $period, $value, '-'); |
|
315 | + return EEH_DTT_Helper::_set_date_time_field($obj, $DateTime, $datetime_field_name); |
|
316 | + } |
|
317 | 317 | |
318 | 318 | |
319 | - /** |
|
320 | - * Simply takes an incoming DateTime object and does calculations on it based on the incoming parameters |
|
321 | - * |
|
322 | - * @param DateTime $DateTime DateTime object |
|
323 | - * @param string $period a value to indicate what interval is being used in the calculation. The options are |
|
324 | - * 'years', 'months', 'days', 'hours', 'minutes', 'seconds'. Defaults to years. |
|
325 | - * @param int|string $value What you want to increment the date by |
|
326 | - * @param string $operand What operand you wish to use for the calculation |
|
327 | - * @return DateTime return whatever type came in. |
|
328 | - * @throws Exception |
|
329 | - * @throws EE_Error |
|
330 | - */ |
|
331 | - protected static function _modify_datetime_object(DateTime $DateTime, $period = 'years', $value = 1, $operand = '+') |
|
332 | - { |
|
333 | - if (! $DateTime instanceof DateTime) { |
|
334 | - throw new EE_Error( |
|
335 | - sprintf( |
|
336 | - esc_html__('Expected a PHP DateTime object, but instead received %1$s', 'event_espresso'), |
|
337 | - print_r($DateTime, true) |
|
338 | - ) |
|
339 | - ); |
|
340 | - } |
|
341 | - switch ($period) { |
|
342 | - case 'years' : |
|
343 | - $value = 'P' . $value . 'Y'; |
|
344 | - break; |
|
345 | - case 'months' : |
|
346 | - $value = 'P' . $value . 'M'; |
|
347 | - break; |
|
348 | - case 'weeks' : |
|
349 | - $value = 'P' . $value . 'W'; |
|
350 | - break; |
|
351 | - case 'days' : |
|
352 | - $value = 'P' . $value . 'D'; |
|
353 | - break; |
|
354 | - case 'hours' : |
|
355 | - $value = 'PT' . $value . 'H'; |
|
356 | - break; |
|
357 | - case 'minutes' : |
|
358 | - $value = 'PT' . $value . 'M'; |
|
359 | - break; |
|
360 | - case 'seconds' : |
|
361 | - $value = 'PT' . $value . 'S'; |
|
362 | - break; |
|
363 | - } |
|
364 | - switch ($operand) { |
|
365 | - case '+': |
|
366 | - $DateTime->add(new DateInterval($value)); |
|
367 | - break; |
|
368 | - case '-': |
|
369 | - $DateTime->sub(new DateInterval($value)); |
|
370 | - break; |
|
371 | - } |
|
372 | - return $DateTime; |
|
373 | - } |
|
319 | + /** |
|
320 | + * Simply takes an incoming DateTime object and does calculations on it based on the incoming parameters |
|
321 | + * |
|
322 | + * @param DateTime $DateTime DateTime object |
|
323 | + * @param string $period a value to indicate what interval is being used in the calculation. The options are |
|
324 | + * 'years', 'months', 'days', 'hours', 'minutes', 'seconds'. Defaults to years. |
|
325 | + * @param int|string $value What you want to increment the date by |
|
326 | + * @param string $operand What operand you wish to use for the calculation |
|
327 | + * @return DateTime return whatever type came in. |
|
328 | + * @throws Exception |
|
329 | + * @throws EE_Error |
|
330 | + */ |
|
331 | + protected static function _modify_datetime_object(DateTime $DateTime, $period = 'years', $value = 1, $operand = '+') |
|
332 | + { |
|
333 | + if (! $DateTime instanceof DateTime) { |
|
334 | + throw new EE_Error( |
|
335 | + sprintf( |
|
336 | + esc_html__('Expected a PHP DateTime object, but instead received %1$s', 'event_espresso'), |
|
337 | + print_r($DateTime, true) |
|
338 | + ) |
|
339 | + ); |
|
340 | + } |
|
341 | + switch ($period) { |
|
342 | + case 'years' : |
|
343 | + $value = 'P' . $value . 'Y'; |
|
344 | + break; |
|
345 | + case 'months' : |
|
346 | + $value = 'P' . $value . 'M'; |
|
347 | + break; |
|
348 | + case 'weeks' : |
|
349 | + $value = 'P' . $value . 'W'; |
|
350 | + break; |
|
351 | + case 'days' : |
|
352 | + $value = 'P' . $value . 'D'; |
|
353 | + break; |
|
354 | + case 'hours' : |
|
355 | + $value = 'PT' . $value . 'H'; |
|
356 | + break; |
|
357 | + case 'minutes' : |
|
358 | + $value = 'PT' . $value . 'M'; |
|
359 | + break; |
|
360 | + case 'seconds' : |
|
361 | + $value = 'PT' . $value . 'S'; |
|
362 | + break; |
|
363 | + } |
|
364 | + switch ($operand) { |
|
365 | + case '+': |
|
366 | + $DateTime->add(new DateInterval($value)); |
|
367 | + break; |
|
368 | + case '-': |
|
369 | + $DateTime->sub(new DateInterval($value)); |
|
370 | + break; |
|
371 | + } |
|
372 | + return $DateTime; |
|
373 | + } |
|
374 | 374 | |
375 | 375 | |
376 | - /** |
|
377 | - * Simply takes an incoming Unix timestamp and does calculations on it based on the incoming parameters |
|
378 | - * |
|
379 | - * @param int $timestamp Unix timestamp |
|
380 | - * @param string $period a value to indicate what interval is being used in the calculation. The options are |
|
381 | - * 'years', 'months', 'days', 'hours', 'minutes', 'seconds'. Defaults to years. |
|
382 | - * @param integer $value What you want to increment the date by |
|
383 | - * @param string $operand What operand you wish to use for the calculation |
|
384 | - * @return int |
|
385 | - * @throws EE_Error |
|
386 | - */ |
|
387 | - protected static function _modify_timestamp($timestamp, $period = 'years', $value = 1, $operand = '+') |
|
388 | - { |
|
389 | - if (! preg_match(EE_Datetime_Field::unix_timestamp_regex, $timestamp)) { |
|
390 | - throw new EE_Error( |
|
391 | - sprintf( |
|
392 | - esc_html__('Expected a Unix timestamp, but instead received %1$s', 'event_espresso'), |
|
393 | - print_r($timestamp, true) |
|
394 | - ) |
|
395 | - ); |
|
396 | - } |
|
397 | - switch ($period) { |
|
398 | - case 'years' : |
|
399 | - $value = YEAR_IN_SECONDS * $value; |
|
400 | - break; |
|
401 | - case 'months' : |
|
402 | - $value = YEAR_IN_SECONDS / 12 * $value; |
|
403 | - break; |
|
404 | - case 'weeks' : |
|
405 | - $value = WEEK_IN_SECONDS * $value; |
|
406 | - break; |
|
407 | - case 'days' : |
|
408 | - $value = DAY_IN_SECONDS * $value; |
|
409 | - break; |
|
410 | - case 'hours' : |
|
411 | - $value = HOUR_IN_SECONDS * $value; |
|
412 | - break; |
|
413 | - case 'minutes' : |
|
414 | - $value = MINUTE_IN_SECONDS * $value; |
|
415 | - break; |
|
416 | - } |
|
417 | - switch ($operand) { |
|
418 | - case '+': |
|
419 | - $timestamp += $value; |
|
420 | - break; |
|
421 | - case '-': |
|
422 | - $timestamp -= $value; |
|
423 | - break; |
|
424 | - } |
|
425 | - return $timestamp; |
|
426 | - } |
|
376 | + /** |
|
377 | + * Simply takes an incoming Unix timestamp and does calculations on it based on the incoming parameters |
|
378 | + * |
|
379 | + * @param int $timestamp Unix timestamp |
|
380 | + * @param string $period a value to indicate what interval is being used in the calculation. The options are |
|
381 | + * 'years', 'months', 'days', 'hours', 'minutes', 'seconds'. Defaults to years. |
|
382 | + * @param integer $value What you want to increment the date by |
|
383 | + * @param string $operand What operand you wish to use for the calculation |
|
384 | + * @return int |
|
385 | + * @throws EE_Error |
|
386 | + */ |
|
387 | + protected static function _modify_timestamp($timestamp, $period = 'years', $value = 1, $operand = '+') |
|
388 | + { |
|
389 | + if (! preg_match(EE_Datetime_Field::unix_timestamp_regex, $timestamp)) { |
|
390 | + throw new EE_Error( |
|
391 | + sprintf( |
|
392 | + esc_html__('Expected a Unix timestamp, but instead received %1$s', 'event_espresso'), |
|
393 | + print_r($timestamp, true) |
|
394 | + ) |
|
395 | + ); |
|
396 | + } |
|
397 | + switch ($period) { |
|
398 | + case 'years' : |
|
399 | + $value = YEAR_IN_SECONDS * $value; |
|
400 | + break; |
|
401 | + case 'months' : |
|
402 | + $value = YEAR_IN_SECONDS / 12 * $value; |
|
403 | + break; |
|
404 | + case 'weeks' : |
|
405 | + $value = WEEK_IN_SECONDS * $value; |
|
406 | + break; |
|
407 | + case 'days' : |
|
408 | + $value = DAY_IN_SECONDS * $value; |
|
409 | + break; |
|
410 | + case 'hours' : |
|
411 | + $value = HOUR_IN_SECONDS * $value; |
|
412 | + break; |
|
413 | + case 'minutes' : |
|
414 | + $value = MINUTE_IN_SECONDS * $value; |
|
415 | + break; |
|
416 | + } |
|
417 | + switch ($operand) { |
|
418 | + case '+': |
|
419 | + $timestamp += $value; |
|
420 | + break; |
|
421 | + case '-': |
|
422 | + $timestamp -= $value; |
|
423 | + break; |
|
424 | + } |
|
425 | + return $timestamp; |
|
426 | + } |
|
427 | 427 | |
428 | 428 | |
429 | - /** |
|
430 | - * Simply takes an incoming UTC timestamp or DateTime object and does calculations on it based on the incoming |
|
431 | - * parameters and returns the new timestamp or DateTime. |
|
432 | - * |
|
433 | - * @param int | DateTime $DateTime_or_timestamp DateTime object or Unix timestamp |
|
434 | - * @param string $period a value to indicate what interval is being used in the |
|
435 | - * calculation. The options are 'years', 'months', 'days', 'hours', |
|
436 | - * 'minutes', 'seconds'. Defaults to years. |
|
437 | - * @param integer $value What you want to increment the date by |
|
438 | - * @param string $operand What operand you wish to use for the calculation |
|
439 | - * @return mixed string|DateTime return whatever type came in. |
|
440 | - * @throws Exception |
|
441 | - * @throws EE_Error |
|
442 | - */ |
|
443 | - public static function calc_date($DateTime_or_timestamp, $period = 'years', $value = 1, $operand = '+') |
|
444 | - { |
|
445 | - if ($DateTime_or_timestamp instanceof DateTime) { |
|
446 | - return EEH_DTT_Helper::_modify_datetime_object( |
|
447 | - $DateTime_or_timestamp, |
|
448 | - $period, |
|
449 | - $value, |
|
450 | - $operand |
|
451 | - ); |
|
452 | - } |
|
453 | - if (preg_match(EE_Datetime_Field::unix_timestamp_regex, $DateTime_or_timestamp)) { |
|
454 | - return EEH_DTT_Helper::_modify_timestamp( |
|
455 | - $DateTime_or_timestamp, |
|
456 | - $period, |
|
457 | - $value, |
|
458 | - $operand |
|
459 | - ); |
|
460 | - } |
|
461 | - //error |
|
462 | - return $DateTime_or_timestamp; |
|
463 | - } |
|
429 | + /** |
|
430 | + * Simply takes an incoming UTC timestamp or DateTime object and does calculations on it based on the incoming |
|
431 | + * parameters and returns the new timestamp or DateTime. |
|
432 | + * |
|
433 | + * @param int | DateTime $DateTime_or_timestamp DateTime object or Unix timestamp |
|
434 | + * @param string $period a value to indicate what interval is being used in the |
|
435 | + * calculation. The options are 'years', 'months', 'days', 'hours', |
|
436 | + * 'minutes', 'seconds'. Defaults to years. |
|
437 | + * @param integer $value What you want to increment the date by |
|
438 | + * @param string $operand What operand you wish to use for the calculation |
|
439 | + * @return mixed string|DateTime return whatever type came in. |
|
440 | + * @throws Exception |
|
441 | + * @throws EE_Error |
|
442 | + */ |
|
443 | + public static function calc_date($DateTime_or_timestamp, $period = 'years', $value = 1, $operand = '+') |
|
444 | + { |
|
445 | + if ($DateTime_or_timestamp instanceof DateTime) { |
|
446 | + return EEH_DTT_Helper::_modify_datetime_object( |
|
447 | + $DateTime_or_timestamp, |
|
448 | + $period, |
|
449 | + $value, |
|
450 | + $operand |
|
451 | + ); |
|
452 | + } |
|
453 | + if (preg_match(EE_Datetime_Field::unix_timestamp_regex, $DateTime_or_timestamp)) { |
|
454 | + return EEH_DTT_Helper::_modify_timestamp( |
|
455 | + $DateTime_or_timestamp, |
|
456 | + $period, |
|
457 | + $value, |
|
458 | + $operand |
|
459 | + ); |
|
460 | + } |
|
461 | + //error |
|
462 | + return $DateTime_or_timestamp; |
|
463 | + } |
|
464 | 464 | |
465 | 465 | |
466 | - /** |
|
467 | - * The purpose of this helper method is to receive an incoming format string in php date/time format |
|
468 | - * and spit out the js and moment.js equivalent formats. |
|
469 | - * Note, if no format string is given, then it is assumed the user wants what is set for WP. |
|
470 | - * Note, js date and time formats are those used by the jquery-ui datepicker and the jquery-ui date- |
|
471 | - * time picker. |
|
472 | - * |
|
473 | - * @see http://stackoverflow.com/posts/16725290/ for the code inspiration. |
|
474 | - * @param string $date_format_string |
|
475 | - * @param string $time_format_string |
|
476 | - * @return array |
|
477 | - * array( |
|
478 | - * 'js' => array ( |
|
479 | - * 'date' => //date format |
|
480 | - * 'time' => //time format |
|
481 | - * ), |
|
482 | - * 'moment' => //date and time format. |
|
483 | - * ) |
|
484 | - */ |
|
485 | - public static function convert_php_to_js_and_moment_date_formats( |
|
486 | - $date_format_string = null, |
|
487 | - $time_format_string = null |
|
488 | - ) { |
|
489 | - if ($date_format_string === null) { |
|
490 | - $date_format_string = (string) get_option('date_format'); |
|
491 | - } |
|
492 | - if ($time_format_string === null) { |
|
493 | - $time_format_string = (string) get_option('time_format'); |
|
494 | - } |
|
495 | - $date_format = self::_php_to_js_moment_converter($date_format_string); |
|
496 | - $time_format = self::_php_to_js_moment_converter($time_format_string); |
|
497 | - return array( |
|
498 | - 'js' => array( |
|
499 | - 'date' => $date_format['js'], |
|
500 | - 'time' => $time_format['js'], |
|
501 | - ), |
|
502 | - 'moment' => $date_format['moment'] . ' ' . $time_format['moment'], |
|
503 | - ); |
|
504 | - } |
|
466 | + /** |
|
467 | + * The purpose of this helper method is to receive an incoming format string in php date/time format |
|
468 | + * and spit out the js and moment.js equivalent formats. |
|
469 | + * Note, if no format string is given, then it is assumed the user wants what is set for WP. |
|
470 | + * Note, js date and time formats are those used by the jquery-ui datepicker and the jquery-ui date- |
|
471 | + * time picker. |
|
472 | + * |
|
473 | + * @see http://stackoverflow.com/posts/16725290/ for the code inspiration. |
|
474 | + * @param string $date_format_string |
|
475 | + * @param string $time_format_string |
|
476 | + * @return array |
|
477 | + * array( |
|
478 | + * 'js' => array ( |
|
479 | + * 'date' => //date format |
|
480 | + * 'time' => //time format |
|
481 | + * ), |
|
482 | + * 'moment' => //date and time format. |
|
483 | + * ) |
|
484 | + */ |
|
485 | + public static function convert_php_to_js_and_moment_date_formats( |
|
486 | + $date_format_string = null, |
|
487 | + $time_format_string = null |
|
488 | + ) { |
|
489 | + if ($date_format_string === null) { |
|
490 | + $date_format_string = (string) get_option('date_format'); |
|
491 | + } |
|
492 | + if ($time_format_string === null) { |
|
493 | + $time_format_string = (string) get_option('time_format'); |
|
494 | + } |
|
495 | + $date_format = self::_php_to_js_moment_converter($date_format_string); |
|
496 | + $time_format = self::_php_to_js_moment_converter($time_format_string); |
|
497 | + return array( |
|
498 | + 'js' => array( |
|
499 | + 'date' => $date_format['js'], |
|
500 | + 'time' => $time_format['js'], |
|
501 | + ), |
|
502 | + 'moment' => $date_format['moment'] . ' ' . $time_format['moment'], |
|
503 | + ); |
|
504 | + } |
|
505 | 505 | |
506 | 506 | |
507 | - /** |
|
508 | - * This converts incoming format string into js and moment variations. |
|
509 | - * |
|
510 | - * @param string $format_string incoming php format string |
|
511 | - * @return array js and moment formats. |
|
512 | - */ |
|
513 | - protected static function _php_to_js_moment_converter($format_string) |
|
514 | - { |
|
515 | - /** |
|
516 | - * This is a map of symbols for formats. |
|
517 | - * The index is the php symbol, the equivalent values are in the array. |
|
518 | - * |
|
519 | - * @var array |
|
520 | - */ |
|
521 | - $symbols_map = array( |
|
522 | - // Day |
|
523 | - //01 |
|
524 | - 'd' => array( |
|
525 | - 'js' => 'dd', |
|
526 | - 'moment' => 'DD', |
|
527 | - ), |
|
528 | - //Mon |
|
529 | - 'D' => array( |
|
530 | - 'js' => 'D', |
|
531 | - 'moment' => 'ddd', |
|
532 | - ), |
|
533 | - //1,2,...31 |
|
534 | - 'j' => array( |
|
535 | - 'js' => 'd', |
|
536 | - 'moment' => 'D', |
|
537 | - ), |
|
538 | - //Monday |
|
539 | - 'l' => array( |
|
540 | - 'js' => 'DD', |
|
541 | - 'moment' => 'dddd', |
|
542 | - ), |
|
543 | - //ISO numeric representation of the day of the week (1-6) |
|
544 | - 'N' => array( |
|
545 | - 'js' => '', |
|
546 | - 'moment' => 'E', |
|
547 | - ), |
|
548 | - //st,nd.rd |
|
549 | - 'S' => array( |
|
550 | - 'js' => '', |
|
551 | - 'moment' => 'o', |
|
552 | - ), |
|
553 | - //numeric representation of day of week (0-6) |
|
554 | - 'w' => array( |
|
555 | - 'js' => '', |
|
556 | - 'moment' => 'd', |
|
557 | - ), |
|
558 | - //day of year starting from 0 (0-365) |
|
559 | - 'z' => array( |
|
560 | - 'js' => 'o', |
|
561 | - 'moment' => 'DDD' //note moment does not start with 0 so will need to modify by subtracting 1 |
|
562 | - ), |
|
563 | - // Week |
|
564 | - //ISO-8601 week number of year (weeks starting on monday) |
|
565 | - 'W' => array( |
|
566 | - 'js' => '', |
|
567 | - 'moment' => 'w', |
|
568 | - ), |
|
569 | - // Month |
|
570 | - // January...December |
|
571 | - 'F' => array( |
|
572 | - 'js' => 'MM', |
|
573 | - 'moment' => 'MMMM', |
|
574 | - ), |
|
575 | - //01...12 |
|
576 | - 'm' => array( |
|
577 | - 'js' => 'mm', |
|
578 | - 'moment' => 'MM', |
|
579 | - ), |
|
580 | - //Jan...Dec |
|
581 | - 'M' => array( |
|
582 | - 'js' => 'M', |
|
583 | - 'moment' => 'MMM', |
|
584 | - ), |
|
585 | - //1-12 |
|
586 | - 'n' => array( |
|
587 | - 'js' => 'm', |
|
588 | - 'moment' => 'M', |
|
589 | - ), |
|
590 | - //number of days in given month |
|
591 | - 't' => array( |
|
592 | - 'js' => '', |
|
593 | - 'moment' => '', |
|
594 | - ), |
|
595 | - // Year |
|
596 | - //whether leap year or not 1/0 |
|
597 | - 'L' => array( |
|
598 | - 'js' => '', |
|
599 | - 'moment' => '', |
|
600 | - ), |
|
601 | - //ISO-8601 year number |
|
602 | - 'o' => array( |
|
603 | - 'js' => '', |
|
604 | - 'moment' => 'GGGG', |
|
605 | - ), |
|
606 | - //1999...2003 |
|
607 | - 'Y' => array( |
|
608 | - 'js' => 'yy', |
|
609 | - 'moment' => 'YYYY', |
|
610 | - ), |
|
611 | - //99...03 |
|
612 | - 'y' => array( |
|
613 | - 'js' => 'y', |
|
614 | - 'moment' => 'YY', |
|
615 | - ), |
|
616 | - // Time |
|
617 | - // am/pm |
|
618 | - 'a' => array( |
|
619 | - 'js' => 'tt', |
|
620 | - 'moment' => 'a', |
|
621 | - ), |
|
622 | - // AM/PM |
|
623 | - 'A' => array( |
|
624 | - 'js' => 'TT', |
|
625 | - 'moment' => 'A', |
|
626 | - ), |
|
627 | - // Swatch Internet Time?!? |
|
628 | - 'B' => array( |
|
629 | - 'js' => '', |
|
630 | - 'moment' => '', |
|
631 | - ), |
|
632 | - //1...12 |
|
633 | - 'g' => array( |
|
634 | - 'js' => 'h', |
|
635 | - 'moment' => 'h', |
|
636 | - ), |
|
637 | - //0...23 |
|
638 | - 'G' => array( |
|
639 | - 'js' => 'H', |
|
640 | - 'moment' => 'H', |
|
641 | - ), |
|
642 | - //01...12 |
|
643 | - 'h' => array( |
|
644 | - 'js' => 'hh', |
|
645 | - 'moment' => 'hh', |
|
646 | - ), |
|
647 | - //00...23 |
|
648 | - 'H' => array( |
|
649 | - 'js' => 'HH', |
|
650 | - 'moment' => 'HH', |
|
651 | - ), |
|
652 | - //00..59 |
|
653 | - 'i' => array( |
|
654 | - 'js' => 'mm', |
|
655 | - 'moment' => 'mm', |
|
656 | - ), |
|
657 | - //seconds... 00...59 |
|
658 | - 's' => array( |
|
659 | - 'js' => 'ss', |
|
660 | - 'moment' => 'ss', |
|
661 | - ), |
|
662 | - //microseconds |
|
663 | - 'u' => array( |
|
664 | - 'js' => '', |
|
665 | - 'moment' => '', |
|
666 | - ), |
|
667 | - ); |
|
668 | - $jquery_ui_format = ''; |
|
669 | - $moment_format = ''; |
|
670 | - $escaping = false; |
|
671 | - $format_string_length = strlen($format_string); |
|
672 | - for ($i = 0; $i < $format_string_length; $i++) { |
|
673 | - $char = $format_string[ $i ]; |
|
674 | - if ($char === '\\') { // PHP date format escaping character |
|
675 | - $i++; |
|
676 | - if ($escaping) { |
|
677 | - $jquery_ui_format .= $format_string[ $i ]; |
|
678 | - $moment_format .= $format_string[ $i ]; |
|
679 | - } else { |
|
680 | - $jquery_ui_format .= '\'' . $format_string[ $i ]; |
|
681 | - $moment_format .= $format_string[ $i ]; |
|
682 | - } |
|
683 | - $escaping = true; |
|
684 | - } else { |
|
685 | - if ($escaping) { |
|
686 | - $jquery_ui_format .= "'"; |
|
687 | - $moment_format .= "'"; |
|
688 | - $escaping = false; |
|
689 | - } |
|
690 | - if (isset($symbols_map[ $char ])) { |
|
691 | - $jquery_ui_format .= $symbols_map[ $char ]['js']; |
|
692 | - $moment_format .= $symbols_map[ $char ]['moment']; |
|
693 | - } else { |
|
694 | - $jquery_ui_format .= $char; |
|
695 | - $moment_format .= $char; |
|
696 | - } |
|
697 | - } |
|
698 | - } |
|
699 | - return array('js' => $jquery_ui_format, 'moment' => $moment_format); |
|
700 | - } |
|
507 | + /** |
|
508 | + * This converts incoming format string into js and moment variations. |
|
509 | + * |
|
510 | + * @param string $format_string incoming php format string |
|
511 | + * @return array js and moment formats. |
|
512 | + */ |
|
513 | + protected static function _php_to_js_moment_converter($format_string) |
|
514 | + { |
|
515 | + /** |
|
516 | + * This is a map of symbols for formats. |
|
517 | + * The index is the php symbol, the equivalent values are in the array. |
|
518 | + * |
|
519 | + * @var array |
|
520 | + */ |
|
521 | + $symbols_map = array( |
|
522 | + // Day |
|
523 | + //01 |
|
524 | + 'd' => array( |
|
525 | + 'js' => 'dd', |
|
526 | + 'moment' => 'DD', |
|
527 | + ), |
|
528 | + //Mon |
|
529 | + 'D' => array( |
|
530 | + 'js' => 'D', |
|
531 | + 'moment' => 'ddd', |
|
532 | + ), |
|
533 | + //1,2,...31 |
|
534 | + 'j' => array( |
|
535 | + 'js' => 'd', |
|
536 | + 'moment' => 'D', |
|
537 | + ), |
|
538 | + //Monday |
|
539 | + 'l' => array( |
|
540 | + 'js' => 'DD', |
|
541 | + 'moment' => 'dddd', |
|
542 | + ), |
|
543 | + //ISO numeric representation of the day of the week (1-6) |
|
544 | + 'N' => array( |
|
545 | + 'js' => '', |
|
546 | + 'moment' => 'E', |
|
547 | + ), |
|
548 | + //st,nd.rd |
|
549 | + 'S' => array( |
|
550 | + 'js' => '', |
|
551 | + 'moment' => 'o', |
|
552 | + ), |
|
553 | + //numeric representation of day of week (0-6) |
|
554 | + 'w' => array( |
|
555 | + 'js' => '', |
|
556 | + 'moment' => 'd', |
|
557 | + ), |
|
558 | + //day of year starting from 0 (0-365) |
|
559 | + 'z' => array( |
|
560 | + 'js' => 'o', |
|
561 | + 'moment' => 'DDD' //note moment does not start with 0 so will need to modify by subtracting 1 |
|
562 | + ), |
|
563 | + // Week |
|
564 | + //ISO-8601 week number of year (weeks starting on monday) |
|
565 | + 'W' => array( |
|
566 | + 'js' => '', |
|
567 | + 'moment' => 'w', |
|
568 | + ), |
|
569 | + // Month |
|
570 | + // January...December |
|
571 | + 'F' => array( |
|
572 | + 'js' => 'MM', |
|
573 | + 'moment' => 'MMMM', |
|
574 | + ), |
|
575 | + //01...12 |
|
576 | + 'm' => array( |
|
577 | + 'js' => 'mm', |
|
578 | + 'moment' => 'MM', |
|
579 | + ), |
|
580 | + //Jan...Dec |
|
581 | + 'M' => array( |
|
582 | + 'js' => 'M', |
|
583 | + 'moment' => 'MMM', |
|
584 | + ), |
|
585 | + //1-12 |
|
586 | + 'n' => array( |
|
587 | + 'js' => 'm', |
|
588 | + 'moment' => 'M', |
|
589 | + ), |
|
590 | + //number of days in given month |
|
591 | + 't' => array( |
|
592 | + 'js' => '', |
|
593 | + 'moment' => '', |
|
594 | + ), |
|
595 | + // Year |
|
596 | + //whether leap year or not 1/0 |
|
597 | + 'L' => array( |
|
598 | + 'js' => '', |
|
599 | + 'moment' => '', |
|
600 | + ), |
|
601 | + //ISO-8601 year number |
|
602 | + 'o' => array( |
|
603 | + 'js' => '', |
|
604 | + 'moment' => 'GGGG', |
|
605 | + ), |
|
606 | + //1999...2003 |
|
607 | + 'Y' => array( |
|
608 | + 'js' => 'yy', |
|
609 | + 'moment' => 'YYYY', |
|
610 | + ), |
|
611 | + //99...03 |
|
612 | + 'y' => array( |
|
613 | + 'js' => 'y', |
|
614 | + 'moment' => 'YY', |
|
615 | + ), |
|
616 | + // Time |
|
617 | + // am/pm |
|
618 | + 'a' => array( |
|
619 | + 'js' => 'tt', |
|
620 | + 'moment' => 'a', |
|
621 | + ), |
|
622 | + // AM/PM |
|
623 | + 'A' => array( |
|
624 | + 'js' => 'TT', |
|
625 | + 'moment' => 'A', |
|
626 | + ), |
|
627 | + // Swatch Internet Time?!? |
|
628 | + 'B' => array( |
|
629 | + 'js' => '', |
|
630 | + 'moment' => '', |
|
631 | + ), |
|
632 | + //1...12 |
|
633 | + 'g' => array( |
|
634 | + 'js' => 'h', |
|
635 | + 'moment' => 'h', |
|
636 | + ), |
|
637 | + //0...23 |
|
638 | + 'G' => array( |
|
639 | + 'js' => 'H', |
|
640 | + 'moment' => 'H', |
|
641 | + ), |
|
642 | + //01...12 |
|
643 | + 'h' => array( |
|
644 | + 'js' => 'hh', |
|
645 | + 'moment' => 'hh', |
|
646 | + ), |
|
647 | + //00...23 |
|
648 | + 'H' => array( |
|
649 | + 'js' => 'HH', |
|
650 | + 'moment' => 'HH', |
|
651 | + ), |
|
652 | + //00..59 |
|
653 | + 'i' => array( |
|
654 | + 'js' => 'mm', |
|
655 | + 'moment' => 'mm', |
|
656 | + ), |
|
657 | + //seconds... 00...59 |
|
658 | + 's' => array( |
|
659 | + 'js' => 'ss', |
|
660 | + 'moment' => 'ss', |
|
661 | + ), |
|
662 | + //microseconds |
|
663 | + 'u' => array( |
|
664 | + 'js' => '', |
|
665 | + 'moment' => '', |
|
666 | + ), |
|
667 | + ); |
|
668 | + $jquery_ui_format = ''; |
|
669 | + $moment_format = ''; |
|
670 | + $escaping = false; |
|
671 | + $format_string_length = strlen($format_string); |
|
672 | + for ($i = 0; $i < $format_string_length; $i++) { |
|
673 | + $char = $format_string[ $i ]; |
|
674 | + if ($char === '\\') { // PHP date format escaping character |
|
675 | + $i++; |
|
676 | + if ($escaping) { |
|
677 | + $jquery_ui_format .= $format_string[ $i ]; |
|
678 | + $moment_format .= $format_string[ $i ]; |
|
679 | + } else { |
|
680 | + $jquery_ui_format .= '\'' . $format_string[ $i ]; |
|
681 | + $moment_format .= $format_string[ $i ]; |
|
682 | + } |
|
683 | + $escaping = true; |
|
684 | + } else { |
|
685 | + if ($escaping) { |
|
686 | + $jquery_ui_format .= "'"; |
|
687 | + $moment_format .= "'"; |
|
688 | + $escaping = false; |
|
689 | + } |
|
690 | + if (isset($symbols_map[ $char ])) { |
|
691 | + $jquery_ui_format .= $symbols_map[ $char ]['js']; |
|
692 | + $moment_format .= $symbols_map[ $char ]['moment']; |
|
693 | + } else { |
|
694 | + $jquery_ui_format .= $char; |
|
695 | + $moment_format .= $char; |
|
696 | + } |
|
697 | + } |
|
698 | + } |
|
699 | + return array('js' => $jquery_ui_format, 'moment' => $moment_format); |
|
700 | + } |
|
701 | 701 | |
702 | 702 | |
703 | - /** |
|
704 | - * This takes an incoming format string and validates it to ensure it will work fine with PHP. |
|
705 | - * |
|
706 | - * @param string $format_string Incoming format string for php date(). |
|
707 | - * @return mixed bool|array If all is okay then TRUE is returned. Otherwise an array of validation |
|
708 | - * errors is returned. So for client code calling, check for is_array() to |
|
709 | - * indicate failed validations. |
|
710 | - */ |
|
711 | - public static function validate_format_string($format_string) |
|
712 | - { |
|
713 | - $error_msg = array(); |
|
714 | - //time format checks |
|
715 | - switch (true) { |
|
716 | - case strpos($format_string, 'h') !== false : |
|
717 | - case strpos($format_string, 'g') !== false : |
|
718 | - /** |
|
719 | - * if the time string has a lowercase 'h' which == 12 hour time format and there |
|
720 | - * is not any ante meridiem format ('a' or 'A'). Then throw an error because its |
|
721 | - * too ambiguous and PHP won't be able to figure out whether 1 = 1pm or 1am. |
|
722 | - */ |
|
723 | - if (stripos($format_string, 'A') === false) { |
|
724 | - $error_msg[] = esc_html__( |
|
725 | - 'There is a time format for 12 hour time but no "a" or "A" to indicate am/pm. Without this distinction, PHP is unable to determine if a "1" for the hour value equals "1pm" or "1am".', |
|
726 | - 'event_espresso' |
|
727 | - ); |
|
728 | - } |
|
729 | - break; |
|
730 | - } |
|
731 | - return empty($error_msg) ? true : $error_msg; |
|
732 | - } |
|
703 | + /** |
|
704 | + * This takes an incoming format string and validates it to ensure it will work fine with PHP. |
|
705 | + * |
|
706 | + * @param string $format_string Incoming format string for php date(). |
|
707 | + * @return mixed bool|array If all is okay then TRUE is returned. Otherwise an array of validation |
|
708 | + * errors is returned. So for client code calling, check for is_array() to |
|
709 | + * indicate failed validations. |
|
710 | + */ |
|
711 | + public static function validate_format_string($format_string) |
|
712 | + { |
|
713 | + $error_msg = array(); |
|
714 | + //time format checks |
|
715 | + switch (true) { |
|
716 | + case strpos($format_string, 'h') !== false : |
|
717 | + case strpos($format_string, 'g') !== false : |
|
718 | + /** |
|
719 | + * if the time string has a lowercase 'h' which == 12 hour time format and there |
|
720 | + * is not any ante meridiem format ('a' or 'A'). Then throw an error because its |
|
721 | + * too ambiguous and PHP won't be able to figure out whether 1 = 1pm or 1am. |
|
722 | + */ |
|
723 | + if (stripos($format_string, 'A') === false) { |
|
724 | + $error_msg[] = esc_html__( |
|
725 | + 'There is a time format for 12 hour time but no "a" or "A" to indicate am/pm. Without this distinction, PHP is unable to determine if a "1" for the hour value equals "1pm" or "1am".', |
|
726 | + 'event_espresso' |
|
727 | + ); |
|
728 | + } |
|
729 | + break; |
|
730 | + } |
|
731 | + return empty($error_msg) ? true : $error_msg; |
|
732 | + } |
|
733 | 733 | |
734 | 734 | |
735 | - /** |
|
736 | - * If the the first date starts at midnight on one day, and the next date ends at midnight on the |
|
737 | - * very next day then this method will return true. |
|
738 | - * If $date_1 = 2015-12-15 00:00:00 and $date_2 = 2015-12-16 00:00:00 then this function will return true. |
|
739 | - * If $date_1 = 2015-12-15 03:00:00 and $date_2 = 2015-12_16 03:00:00 then this function will return false. |
|
740 | - * If $date_1 = 2015-12-15 00:00:00 and $date_2 = 2015-12-15 00:00:00 then this function will return true. |
|
741 | - * |
|
742 | - * @param mixed $date_1 |
|
743 | - * @param mixed $date_2 |
|
744 | - * @return bool |
|
745 | - */ |
|
746 | - public static function dates_represent_one_24_hour_date($date_1, $date_2) |
|
747 | - { |
|
735 | + /** |
|
736 | + * If the the first date starts at midnight on one day, and the next date ends at midnight on the |
|
737 | + * very next day then this method will return true. |
|
738 | + * If $date_1 = 2015-12-15 00:00:00 and $date_2 = 2015-12-16 00:00:00 then this function will return true. |
|
739 | + * If $date_1 = 2015-12-15 03:00:00 and $date_2 = 2015-12_16 03:00:00 then this function will return false. |
|
740 | + * If $date_1 = 2015-12-15 00:00:00 and $date_2 = 2015-12-15 00:00:00 then this function will return true. |
|
741 | + * |
|
742 | + * @param mixed $date_1 |
|
743 | + * @param mixed $date_2 |
|
744 | + * @return bool |
|
745 | + */ |
|
746 | + public static function dates_represent_one_24_hour_date($date_1, $date_2) |
|
747 | + { |
|
748 | 748 | |
749 | - if ( |
|
750 | - (! $date_1 instanceof DateTime || ! $date_2 instanceof DateTime) |
|
751 | - || ($date_1->format(EE_Datetime_Field::mysql_time_format) !== '00:00:00' |
|
752 | - || $date_2->format( |
|
753 | - EE_Datetime_Field::mysql_time_format |
|
754 | - ) !== '00:00:00') |
|
755 | - ) { |
|
756 | - return false; |
|
757 | - } |
|
758 | - return $date_2->format('U') - $date_1->format('U') === 86400; |
|
759 | - } |
|
749 | + if ( |
|
750 | + (! $date_1 instanceof DateTime || ! $date_2 instanceof DateTime) |
|
751 | + || ($date_1->format(EE_Datetime_Field::mysql_time_format) !== '00:00:00' |
|
752 | + || $date_2->format( |
|
753 | + EE_Datetime_Field::mysql_time_format |
|
754 | + ) !== '00:00:00') |
|
755 | + ) { |
|
756 | + return false; |
|
757 | + } |
|
758 | + return $date_2->format('U') - $date_1->format('U') === 86400; |
|
759 | + } |
|
760 | 760 | |
761 | 761 | |
762 | - /** |
|
763 | - * This returns the appropriate query interval string that can be used in sql queries involving mysql Date |
|
764 | - * Functions. |
|
765 | - * |
|
766 | - * @param string $timezone_string A timezone string in a valid format to instantiate a DateTimeZone object. |
|
767 | - * @param string $field_for_interval The Database field that is the interval is applied to in the query. |
|
768 | - * @return string |
|
769 | - */ |
|
770 | - public static function get_sql_query_interval_for_offset($timezone_string, $field_for_interval) |
|
771 | - { |
|
772 | - try { |
|
773 | - /** need to account for timezone offset on the selects */ |
|
774 | - $DateTimeZone = new DateTimeZone($timezone_string); |
|
775 | - } catch (Exception $e) { |
|
776 | - $DateTimeZone = null; |
|
777 | - } |
|
778 | - /** |
|
779 | - * Note get_option( 'gmt_offset') returns a value in hours, whereas DateTimeZone::getOffset returns values in seconds. |
|
780 | - * Hence we do the calc for DateTimeZone::getOffset. |
|
781 | - */ |
|
782 | - $offset = $DateTimeZone instanceof DateTimeZone |
|
783 | - ? $DateTimeZone->getOffset(new DateTime('now')) / HOUR_IN_SECONDS |
|
784 | - : (float) get_option('gmt_offset'); |
|
785 | - $query_interval = $offset < 0 |
|
786 | - ? 'DATE_SUB(' . $field_for_interval . ', INTERVAL ' . $offset * -1 . ' HOUR)' |
|
787 | - : 'DATE_ADD(' . $field_for_interval . ', INTERVAL ' . $offset . ' HOUR)'; |
|
788 | - return $query_interval; |
|
789 | - } |
|
762 | + /** |
|
763 | + * This returns the appropriate query interval string that can be used in sql queries involving mysql Date |
|
764 | + * Functions. |
|
765 | + * |
|
766 | + * @param string $timezone_string A timezone string in a valid format to instantiate a DateTimeZone object. |
|
767 | + * @param string $field_for_interval The Database field that is the interval is applied to in the query. |
|
768 | + * @return string |
|
769 | + */ |
|
770 | + public static function get_sql_query_interval_for_offset($timezone_string, $field_for_interval) |
|
771 | + { |
|
772 | + try { |
|
773 | + /** need to account for timezone offset on the selects */ |
|
774 | + $DateTimeZone = new DateTimeZone($timezone_string); |
|
775 | + } catch (Exception $e) { |
|
776 | + $DateTimeZone = null; |
|
777 | + } |
|
778 | + /** |
|
779 | + * Note get_option( 'gmt_offset') returns a value in hours, whereas DateTimeZone::getOffset returns values in seconds. |
|
780 | + * Hence we do the calc for DateTimeZone::getOffset. |
|
781 | + */ |
|
782 | + $offset = $DateTimeZone instanceof DateTimeZone |
|
783 | + ? $DateTimeZone->getOffset(new DateTime('now')) / HOUR_IN_SECONDS |
|
784 | + : (float) get_option('gmt_offset'); |
|
785 | + $query_interval = $offset < 0 |
|
786 | + ? 'DATE_SUB(' . $field_for_interval . ', INTERVAL ' . $offset * -1 . ' HOUR)' |
|
787 | + : 'DATE_ADD(' . $field_for_interval . ', INTERVAL ' . $offset . ' HOUR)'; |
|
788 | + return $query_interval; |
|
789 | + } |
|
790 | 790 | |
791 | 791 | |
792 | - /** |
|
793 | - * Retrieves the site's default timezone and returns it formatted so it's ready for display |
|
794 | - * to users. If you want to customize how its displayed feel free to fetch the 'timezone_string' |
|
795 | - * and 'gmt_offset' WordPress options directly; or use the filter |
|
796 | - * FHEE__EEH_DTT_Helper__get_timezone_string_for_display |
|
797 | - * (although note that we remove any HTML that may be added) |
|
798 | - * |
|
799 | - * @return string |
|
800 | - */ |
|
801 | - public static function get_timezone_string_for_display() |
|
802 | - { |
|
803 | - $pretty_timezone = apply_filters('FHEE__EEH_DTT_Helper__get_timezone_string_for_display', ''); |
|
804 | - if (! empty($pretty_timezone)) { |
|
805 | - return esc_html($pretty_timezone); |
|
806 | - } |
|
807 | - $timezone_string = get_option('timezone_string'); |
|
808 | - if ($timezone_string) { |
|
809 | - static $mo_loaded = false; |
|
810 | - // Load translations for continents and cities just like wp_timezone_choice does |
|
811 | - if (! $mo_loaded) { |
|
812 | - $locale = get_locale(); |
|
813 | - $mofile = WP_LANG_DIR . '/continents-cities-' . $locale . '.mo'; |
|
814 | - load_textdomain('continents-cities', $mofile); |
|
815 | - $mo_loaded = true; |
|
816 | - } |
|
817 | - //well that was easy. |
|
818 | - $parts = explode('/', $timezone_string); |
|
819 | - //remove the continent |
|
820 | - unset($parts[0]); |
|
821 | - $t_parts = array(); |
|
822 | - foreach ($parts as $part) { |
|
823 | - $t_parts[] = translate(str_replace('_', ' ', $part), 'continents-cities'); |
|
824 | - } |
|
825 | - return implode(' - ', $t_parts); |
|
826 | - } |
|
827 | - //they haven't set the timezone string, so let's return a string like "UTC+1" |
|
828 | - $gmt_offset = get_option('gmt_offset'); |
|
829 | - $prefix = (int) $gmt_offset >= 0 ? '+' : ''; |
|
830 | - $parts = explode('.', (string) $gmt_offset); |
|
831 | - if (count($parts) === 1) { |
|
832 | - $parts[1] = '00'; |
|
833 | - } else { |
|
834 | - //convert the part after the decimal, eg "5" (from x.5) or "25" (from x.25) |
|
835 | - //to minutes, eg 30 or 15, respectively |
|
836 | - $hour_fraction = (float) ('0.' . $parts[1]); |
|
837 | - $parts[1] = (string) $hour_fraction * 60; |
|
838 | - } |
|
839 | - return sprintf(__('UTC%1$s', 'event_espresso'), $prefix . implode(':', $parts)); |
|
840 | - } |
|
792 | + /** |
|
793 | + * Retrieves the site's default timezone and returns it formatted so it's ready for display |
|
794 | + * to users. If you want to customize how its displayed feel free to fetch the 'timezone_string' |
|
795 | + * and 'gmt_offset' WordPress options directly; or use the filter |
|
796 | + * FHEE__EEH_DTT_Helper__get_timezone_string_for_display |
|
797 | + * (although note that we remove any HTML that may be added) |
|
798 | + * |
|
799 | + * @return string |
|
800 | + */ |
|
801 | + public static function get_timezone_string_for_display() |
|
802 | + { |
|
803 | + $pretty_timezone = apply_filters('FHEE__EEH_DTT_Helper__get_timezone_string_for_display', ''); |
|
804 | + if (! empty($pretty_timezone)) { |
|
805 | + return esc_html($pretty_timezone); |
|
806 | + } |
|
807 | + $timezone_string = get_option('timezone_string'); |
|
808 | + if ($timezone_string) { |
|
809 | + static $mo_loaded = false; |
|
810 | + // Load translations for continents and cities just like wp_timezone_choice does |
|
811 | + if (! $mo_loaded) { |
|
812 | + $locale = get_locale(); |
|
813 | + $mofile = WP_LANG_DIR . '/continents-cities-' . $locale . '.mo'; |
|
814 | + load_textdomain('continents-cities', $mofile); |
|
815 | + $mo_loaded = true; |
|
816 | + } |
|
817 | + //well that was easy. |
|
818 | + $parts = explode('/', $timezone_string); |
|
819 | + //remove the continent |
|
820 | + unset($parts[0]); |
|
821 | + $t_parts = array(); |
|
822 | + foreach ($parts as $part) { |
|
823 | + $t_parts[] = translate(str_replace('_', ' ', $part), 'continents-cities'); |
|
824 | + } |
|
825 | + return implode(' - ', $t_parts); |
|
826 | + } |
|
827 | + //they haven't set the timezone string, so let's return a string like "UTC+1" |
|
828 | + $gmt_offset = get_option('gmt_offset'); |
|
829 | + $prefix = (int) $gmt_offset >= 0 ? '+' : ''; |
|
830 | + $parts = explode('.', (string) $gmt_offset); |
|
831 | + if (count($parts) === 1) { |
|
832 | + $parts[1] = '00'; |
|
833 | + } else { |
|
834 | + //convert the part after the decimal, eg "5" (from x.5) or "25" (from x.25) |
|
835 | + //to minutes, eg 30 or 15, respectively |
|
836 | + $hour_fraction = (float) ('0.' . $parts[1]); |
|
837 | + $parts[1] = (string) $hour_fraction * 60; |
|
838 | + } |
|
839 | + return sprintf(__('UTC%1$s', 'event_espresso'), $prefix . implode(':', $parts)); |
|
840 | + } |
|
841 | 841 | |
842 | 842 | |
843 | 843 | |
844 | - /** |
|
845 | - * So PHP does this awesome thing where if you are trying to get a timestamp |
|
846 | - * for a month using a string like "February" or "February 2017", |
|
847 | - * and you don't specify a day as part of your string, |
|
848 | - * then PHP will use whatever the current day of the month is. |
|
849 | - * IF the current day of the month happens to be the 30th or 31st, |
|
850 | - * then PHP gets really confused by a date like February 30, |
|
851 | - * so instead of saying |
|
852 | - * "Hey February only has 28 days (this year)... |
|
853 | - * ...you must have meant the last day of the month!" |
|
854 | - * PHP does the next most logical thing, and bumps the date up to March 2nd, |
|
855 | - * because someone requesting February 30th obviously meant March 1st! |
|
856 | - * The way around this is to always set the day to the first, |
|
857 | - * so that the month will stay on the month you wanted. |
|
858 | - * this method will add that "1" into your date regardless of the format. |
|
859 | - * |
|
860 | - * @param string $month |
|
861 | - * @return string |
|
862 | - */ |
|
863 | - public static function first_of_month_timestamp($month = '') |
|
864 | - { |
|
865 | - $month = (string) $month; |
|
866 | - $year = ''; |
|
867 | - // check if the incoming string has a year in it or not |
|
868 | - if (preg_match('/\b\d{4}\b/', $month, $matches)) { |
|
869 | - $year = $matches[0]; |
|
870 | - // ten remove that from the month string as well as any spaces |
|
871 | - $month = trim(str_replace($year, '', $month)); |
|
872 | - // add a space before the year |
|
873 | - $year = " {$year}"; |
|
874 | - } |
|
875 | - // return timestamp for something like "February 1 2017" |
|
876 | - return strtotime("{$month} 1{$year}"); |
|
877 | - } |
|
844 | + /** |
|
845 | + * So PHP does this awesome thing where if you are trying to get a timestamp |
|
846 | + * for a month using a string like "February" or "February 2017", |
|
847 | + * and you don't specify a day as part of your string, |
|
848 | + * then PHP will use whatever the current day of the month is. |
|
849 | + * IF the current day of the month happens to be the 30th or 31st, |
|
850 | + * then PHP gets really confused by a date like February 30, |
|
851 | + * so instead of saying |
|
852 | + * "Hey February only has 28 days (this year)... |
|
853 | + * ...you must have meant the last day of the month!" |
|
854 | + * PHP does the next most logical thing, and bumps the date up to March 2nd, |
|
855 | + * because someone requesting February 30th obviously meant March 1st! |
|
856 | + * The way around this is to always set the day to the first, |
|
857 | + * so that the month will stay on the month you wanted. |
|
858 | + * this method will add that "1" into your date regardless of the format. |
|
859 | + * |
|
860 | + * @param string $month |
|
861 | + * @return string |
|
862 | + */ |
|
863 | + public static function first_of_month_timestamp($month = '') |
|
864 | + { |
|
865 | + $month = (string) $month; |
|
866 | + $year = ''; |
|
867 | + // check if the incoming string has a year in it or not |
|
868 | + if (preg_match('/\b\d{4}\b/', $month, $matches)) { |
|
869 | + $year = $matches[0]; |
|
870 | + // ten remove that from the month string as well as any spaces |
|
871 | + $month = trim(str_replace($year, '', $month)); |
|
872 | + // add a space before the year |
|
873 | + $year = " {$year}"; |
|
874 | + } |
|
875 | + // return timestamp for something like "February 1 2017" |
|
876 | + return strtotime("{$month} 1{$year}"); |
|
877 | + } |
|
878 | 878 | |
879 | 879 | |
880 | - /** |
|
881 | - * This simply returns the timestamp for tomorrow (midnight next day) in this sites timezone. So it may be midnight |
|
882 | - * for this sites timezone, but the timestamp could be some other time GMT. |
|
883 | - */ |
|
884 | - public static function tomorrow() |
|
885 | - { |
|
886 | - //The multiplication of -1 ensures that we switch positive offsets to negative and negative offsets to positive |
|
887 | - //before adding to the timestamp. Why? Because we want tomorrow to be for midnight the next day in THIS timezone |
|
888 | - //not an offset from midnight in UTC. So if we're starting with UTC 00:00:00, then we want to make sure the |
|
889 | - //final timestamp is equivalent to midnight in this timezone as represented in GMT. |
|
890 | - return strtotime('tomorrow') + (self::get_site_timezone_gmt_offset() * -1); |
|
891 | - } |
|
880 | + /** |
|
881 | + * This simply returns the timestamp for tomorrow (midnight next day) in this sites timezone. So it may be midnight |
|
882 | + * for this sites timezone, but the timestamp could be some other time GMT. |
|
883 | + */ |
|
884 | + public static function tomorrow() |
|
885 | + { |
|
886 | + //The multiplication of -1 ensures that we switch positive offsets to negative and negative offsets to positive |
|
887 | + //before adding to the timestamp. Why? Because we want tomorrow to be for midnight the next day in THIS timezone |
|
888 | + //not an offset from midnight in UTC. So if we're starting with UTC 00:00:00, then we want to make sure the |
|
889 | + //final timestamp is equivalent to midnight in this timezone as represented in GMT. |
|
890 | + return strtotime('tomorrow') + (self::get_site_timezone_gmt_offset() * -1); |
|
891 | + } |
|
892 | 892 | |
893 | 893 | |
894 | - /** |
|
895 | - * ** |
|
896 | - * Gives a nicely-formatted list of timezone strings. |
|
897 | - * Copied from the core wp function by the same name so we could customize to remove UTC offsets. |
|
898 | - * |
|
899 | - * @since 4.9.40.rc.008 |
|
900 | - * @staticvar bool $mo_loaded |
|
901 | - * @staticvar string $locale_loaded |
|
902 | - * @param string $selected_zone Selected timezone. |
|
903 | - * @param string $locale Optional. Locale to load the timezones in. Default current site locale. |
|
904 | - * @return string |
|
905 | - */ |
|
906 | - public static function wp_timezone_choice($selected_zone, $locale = null) |
|
907 | - { |
|
908 | - static $mo_loaded = false, $locale_loaded = null; |
|
909 | - $continents = array( |
|
910 | - 'Africa', |
|
911 | - 'America', |
|
912 | - 'Antarctica', |
|
913 | - 'Arctic', |
|
914 | - 'Asia', |
|
915 | - 'Atlantic', |
|
916 | - 'Australia', |
|
917 | - 'Europe', |
|
918 | - 'Indian', |
|
919 | - 'Pacific', |
|
920 | - ); |
|
921 | - // Load translations for continents and cities. |
|
922 | - if (! $mo_loaded || $locale !== $locale_loaded) { |
|
923 | - $locale_loaded = $locale ? $locale : get_locale(); |
|
924 | - $mofile = WP_LANG_DIR . '/continents-cities-' . $locale_loaded . '.mo'; |
|
925 | - unload_textdomain('continents-cities'); |
|
926 | - load_textdomain('continents-cities', $mofile); |
|
927 | - $mo_loaded = true; |
|
928 | - } |
|
929 | - $zone_data = array(); |
|
930 | - foreach (timezone_identifiers_list() as $zone) { |
|
931 | - $zone = explode('/', $zone); |
|
932 | - if (! in_array($zone[0], $continents, true)) { |
|
933 | - continue; |
|
934 | - } |
|
935 | - // This determines what gets set and translated - we don't translate Etc/* strings here, they are done later |
|
936 | - $exists = array( |
|
937 | - 0 => isset($zone[0]) && $zone[0], |
|
938 | - 1 => isset($zone[1]) && $zone[1], |
|
939 | - 2 => isset($zone[2]) && $zone[2], |
|
940 | - ); |
|
941 | - $exists[3] = $exists[0] && $zone[0] !== 'Etc'; |
|
942 | - $exists[4] = $exists[1] && $exists[3]; |
|
943 | - $exists[5] = $exists[2] && $exists[3]; |
|
944 | - $zone_data[] = array( |
|
945 | - 'continent' => $exists[0] ? $zone[0] : '', |
|
946 | - 'city' => $exists[1] ? $zone[1] : '', |
|
947 | - 'subcity' => $exists[2] ? $zone[2] : '', |
|
948 | - 't_continent' => $exists[3] |
|
949 | - ? translate(str_replace('_', ' ', $zone[0]), 'continents-cities') |
|
950 | - : '', |
|
951 | - 't_city' => $exists[4] |
|
952 | - ? translate(str_replace('_', ' ', $zone[1]), 'continents-cities') |
|
953 | - : '', |
|
954 | - 't_subcity' => $exists[5] |
|
955 | - ? translate(str_replace('_', ' ', $zone[2]), 'continents-cities') |
|
956 | - : '', |
|
957 | - ); |
|
958 | - } |
|
959 | - usort($zone_data, '_wp_timezone_choice_usort_callback'); |
|
960 | - $structure = array(); |
|
961 | - if (empty($selected_zone)) { |
|
962 | - $structure[] = '<option selected="selected" value="">' . __('Select a city') . '</option>'; |
|
963 | - } |
|
964 | - foreach ($zone_data as $key => $zone) { |
|
965 | - // Build value in an array to join later |
|
966 | - $value = array($zone['continent']); |
|
967 | - if (empty($zone['city'])) { |
|
968 | - // It's at the continent level (generally won't happen) |
|
969 | - $display = $zone['t_continent']; |
|
970 | - } else { |
|
971 | - // It's inside a continent group |
|
972 | - // Continent optgroup |
|
973 | - if (! isset($zone_data[ $key - 1 ]) || $zone_data[ $key - 1 ]['continent'] !== $zone['continent']) { |
|
974 | - $label = $zone['t_continent']; |
|
975 | - $structure[] = '<optgroup label="' . esc_attr($label) . '">'; |
|
976 | - } |
|
977 | - // Add the city to the value |
|
978 | - $value[] = $zone['city']; |
|
979 | - $display = $zone['t_city']; |
|
980 | - if (! empty($zone['subcity'])) { |
|
981 | - // Add the subcity to the value |
|
982 | - $value[] = $zone['subcity']; |
|
983 | - $display .= ' - ' . $zone['t_subcity']; |
|
984 | - } |
|
985 | - } |
|
986 | - // Build the value |
|
987 | - $value = implode('/', $value); |
|
988 | - $selected = $value === $selected_zone ? ' selected="selected"' : ''; |
|
989 | - $structure[] = '<option value="' . esc_attr($value) . '"' . $selected . '>' |
|
990 | - . esc_html($display) |
|
991 | - . '</option>'; |
|
992 | - // Close continent optgroup |
|
993 | - if (! empty($zone['city']) |
|
994 | - && ( |
|
995 | - ! isset($zone_data[ $key + 1 ]) |
|
996 | - || (isset($zone_data[ $key + 1 ]) && $zone_data[ $key + 1 ]['continent'] !== $zone['continent']) |
|
997 | - ) |
|
998 | - ) { |
|
999 | - $structure[] = '</optgroup>'; |
|
1000 | - } |
|
1001 | - } |
|
1002 | - return implode("\n", $structure); |
|
1003 | - } |
|
894 | + /** |
|
895 | + * ** |
|
896 | + * Gives a nicely-formatted list of timezone strings. |
|
897 | + * Copied from the core wp function by the same name so we could customize to remove UTC offsets. |
|
898 | + * |
|
899 | + * @since 4.9.40.rc.008 |
|
900 | + * @staticvar bool $mo_loaded |
|
901 | + * @staticvar string $locale_loaded |
|
902 | + * @param string $selected_zone Selected timezone. |
|
903 | + * @param string $locale Optional. Locale to load the timezones in. Default current site locale. |
|
904 | + * @return string |
|
905 | + */ |
|
906 | + public static function wp_timezone_choice($selected_zone, $locale = null) |
|
907 | + { |
|
908 | + static $mo_loaded = false, $locale_loaded = null; |
|
909 | + $continents = array( |
|
910 | + 'Africa', |
|
911 | + 'America', |
|
912 | + 'Antarctica', |
|
913 | + 'Arctic', |
|
914 | + 'Asia', |
|
915 | + 'Atlantic', |
|
916 | + 'Australia', |
|
917 | + 'Europe', |
|
918 | + 'Indian', |
|
919 | + 'Pacific', |
|
920 | + ); |
|
921 | + // Load translations for continents and cities. |
|
922 | + if (! $mo_loaded || $locale !== $locale_loaded) { |
|
923 | + $locale_loaded = $locale ? $locale : get_locale(); |
|
924 | + $mofile = WP_LANG_DIR . '/continents-cities-' . $locale_loaded . '.mo'; |
|
925 | + unload_textdomain('continents-cities'); |
|
926 | + load_textdomain('continents-cities', $mofile); |
|
927 | + $mo_loaded = true; |
|
928 | + } |
|
929 | + $zone_data = array(); |
|
930 | + foreach (timezone_identifiers_list() as $zone) { |
|
931 | + $zone = explode('/', $zone); |
|
932 | + if (! in_array($zone[0], $continents, true)) { |
|
933 | + continue; |
|
934 | + } |
|
935 | + // This determines what gets set and translated - we don't translate Etc/* strings here, they are done later |
|
936 | + $exists = array( |
|
937 | + 0 => isset($zone[0]) && $zone[0], |
|
938 | + 1 => isset($zone[1]) && $zone[1], |
|
939 | + 2 => isset($zone[2]) && $zone[2], |
|
940 | + ); |
|
941 | + $exists[3] = $exists[0] && $zone[0] !== 'Etc'; |
|
942 | + $exists[4] = $exists[1] && $exists[3]; |
|
943 | + $exists[5] = $exists[2] && $exists[3]; |
|
944 | + $zone_data[] = array( |
|
945 | + 'continent' => $exists[0] ? $zone[0] : '', |
|
946 | + 'city' => $exists[1] ? $zone[1] : '', |
|
947 | + 'subcity' => $exists[2] ? $zone[2] : '', |
|
948 | + 't_continent' => $exists[3] |
|
949 | + ? translate(str_replace('_', ' ', $zone[0]), 'continents-cities') |
|
950 | + : '', |
|
951 | + 't_city' => $exists[4] |
|
952 | + ? translate(str_replace('_', ' ', $zone[1]), 'continents-cities') |
|
953 | + : '', |
|
954 | + 't_subcity' => $exists[5] |
|
955 | + ? translate(str_replace('_', ' ', $zone[2]), 'continents-cities') |
|
956 | + : '', |
|
957 | + ); |
|
958 | + } |
|
959 | + usort($zone_data, '_wp_timezone_choice_usort_callback'); |
|
960 | + $structure = array(); |
|
961 | + if (empty($selected_zone)) { |
|
962 | + $structure[] = '<option selected="selected" value="">' . __('Select a city') . '</option>'; |
|
963 | + } |
|
964 | + foreach ($zone_data as $key => $zone) { |
|
965 | + // Build value in an array to join later |
|
966 | + $value = array($zone['continent']); |
|
967 | + if (empty($zone['city'])) { |
|
968 | + // It's at the continent level (generally won't happen) |
|
969 | + $display = $zone['t_continent']; |
|
970 | + } else { |
|
971 | + // It's inside a continent group |
|
972 | + // Continent optgroup |
|
973 | + if (! isset($zone_data[ $key - 1 ]) || $zone_data[ $key - 1 ]['continent'] !== $zone['continent']) { |
|
974 | + $label = $zone['t_continent']; |
|
975 | + $structure[] = '<optgroup label="' . esc_attr($label) . '">'; |
|
976 | + } |
|
977 | + // Add the city to the value |
|
978 | + $value[] = $zone['city']; |
|
979 | + $display = $zone['t_city']; |
|
980 | + if (! empty($zone['subcity'])) { |
|
981 | + // Add the subcity to the value |
|
982 | + $value[] = $zone['subcity']; |
|
983 | + $display .= ' - ' . $zone['t_subcity']; |
|
984 | + } |
|
985 | + } |
|
986 | + // Build the value |
|
987 | + $value = implode('/', $value); |
|
988 | + $selected = $value === $selected_zone ? ' selected="selected"' : ''; |
|
989 | + $structure[] = '<option value="' . esc_attr($value) . '"' . $selected . '>' |
|
990 | + . esc_html($display) |
|
991 | + . '</option>'; |
|
992 | + // Close continent optgroup |
|
993 | + if (! empty($zone['city']) |
|
994 | + && ( |
|
995 | + ! isset($zone_data[ $key + 1 ]) |
|
996 | + || (isset($zone_data[ $key + 1 ]) && $zone_data[ $key + 1 ]['continent'] !== $zone['continent']) |
|
997 | + ) |
|
998 | + ) { |
|
999 | + $structure[] = '</optgroup>'; |
|
1000 | + } |
|
1001 | + } |
|
1002 | + return implode("\n", $structure); |
|
1003 | + } |
|
1004 | 1004 | |
1005 | 1005 | |
1006 | - /** |
|
1007 | - * Shim for the WP function `get_user_locale` that was added in WordPress 4.7.0 |
|
1008 | - * |
|
1009 | - * @param int|WP_User $user_id |
|
1010 | - * @return string |
|
1011 | - */ |
|
1012 | - public static function get_user_locale($user_id = 0) |
|
1013 | - { |
|
1014 | - if (function_exists('get_user_locale')) { |
|
1015 | - return get_user_locale($user_id); |
|
1016 | - } |
|
1017 | - return get_locale(); |
|
1018 | - } |
|
1006 | + /** |
|
1007 | + * Shim for the WP function `get_user_locale` that was added in WordPress 4.7.0 |
|
1008 | + * |
|
1009 | + * @param int|WP_User $user_id |
|
1010 | + * @return string |
|
1011 | + */ |
|
1012 | + public static function get_user_locale($user_id = 0) |
|
1013 | + { |
|
1014 | + if (function_exists('get_user_locale')) { |
|
1015 | + return get_user_locale($user_id); |
|
1016 | + } |
|
1017 | + return get_locale(); |
|
1018 | + } |
|
1019 | 1019 | |
1020 | 1020 | |
1021 | - /** |
|
1022 | - * Return the appropriate helper adapter for DTT related things. |
|
1023 | - * |
|
1024 | - * @return HelperInterface |
|
1025 | - * @throws InvalidArgumentException |
|
1026 | - * @throws InvalidDataTypeException |
|
1027 | - * @throws InvalidInterfaceException |
|
1028 | - */ |
|
1029 | - private static function getHelperAdapter() { |
|
1030 | - $dtt_helper_fqcn = PHP_VERSION_ID < 50600 |
|
1031 | - ? 'EventEspresso\core\services\helpers\datetime\PhpCompatLessFiveSixHelper' |
|
1032 | - : 'EventEspresso\core\services\helpers\datetime\PhpCompatGreaterFiveSixHelper'; |
|
1033 | - return LoaderFactory::getLoader()->getShared($dtt_helper_fqcn); |
|
1034 | - } |
|
1021 | + /** |
|
1022 | + * Return the appropriate helper adapter for DTT related things. |
|
1023 | + * |
|
1024 | + * @return HelperInterface |
|
1025 | + * @throws InvalidArgumentException |
|
1026 | + * @throws InvalidDataTypeException |
|
1027 | + * @throws InvalidInterfaceException |
|
1028 | + */ |
|
1029 | + private static function getHelperAdapter() { |
|
1030 | + $dtt_helper_fqcn = PHP_VERSION_ID < 50600 |
|
1031 | + ? 'EventEspresso\core\services\helpers\datetime\PhpCompatLessFiveSixHelper' |
|
1032 | + : 'EventEspresso\core\services\helpers\datetime\PhpCompatGreaterFiveSixHelper'; |
|
1033 | + return LoaderFactory::getLoader()->getShared($dtt_helper_fqcn); |
|
1034 | + } |
|
1035 | 1035 | } |
1036 | 1036 | \ No newline at end of file |
@@ -45,8 +45,8 @@ |
||
45 | 45 | } |
46 | 46 | } |
47 | 47 | } |
48 | - return true; |
|
49 | - } |
|
48 | + return true; |
|
49 | + } |
|
50 | 50 | |
51 | 51 | |
52 | 52 |
@@ -1,5 +1,5 @@ discard block |
||
1 | 1 | <?php if ( ! defined('EVENT_ESPRESSO_VERSION')) { |
2 | - exit('No direct script access allowed'); |
|
2 | + exit('No direct script access allowed'); |
|
3 | 3 | } |
4 | 4 | |
5 | 5 | /** |
@@ -24,470 +24,470 @@ discard block |
||
24 | 24 | { |
25 | 25 | |
26 | 26 | |
27 | - /** |
|
28 | - * This gets set in _setup_cpt |
|
29 | - * It will contain the object for the custom post type. |
|
30 | - * |
|
31 | - * @var EE_CPT_Base |
|
32 | - */ |
|
33 | - protected $_cpt_object; |
|
34 | - |
|
35 | - |
|
36 | - |
|
37 | - /** |
|
38 | - * a boolean flag to set whether the current route is a cpt route or not. |
|
39 | - * |
|
40 | - * @var bool |
|
41 | - */ |
|
42 | - protected $_cpt_route = false; |
|
43 | - |
|
44 | - |
|
45 | - |
|
46 | - /** |
|
47 | - * This property allows cpt classes to define multiple routes as cpt routes. |
|
48 | - * //in this array we define what the custom post type for this route is. |
|
49 | - * array( |
|
50 | - * 'route_name' => 'custom_post_type_slug' |
|
51 | - * ) |
|
52 | - * |
|
53 | - * @var array |
|
54 | - */ |
|
55 | - protected $_cpt_routes = array(); |
|
56 | - |
|
27 | + /** |
|
28 | + * This gets set in _setup_cpt |
|
29 | + * It will contain the object for the custom post type. |
|
30 | + * |
|
31 | + * @var EE_CPT_Base |
|
32 | + */ |
|
33 | + protected $_cpt_object; |
|
34 | + |
|
35 | + |
|
36 | + |
|
37 | + /** |
|
38 | + * a boolean flag to set whether the current route is a cpt route or not. |
|
39 | + * |
|
40 | + * @var bool |
|
41 | + */ |
|
42 | + protected $_cpt_route = false; |
|
43 | + |
|
44 | + |
|
45 | + |
|
46 | + /** |
|
47 | + * This property allows cpt classes to define multiple routes as cpt routes. |
|
48 | + * //in this array we define what the custom post type for this route is. |
|
49 | + * array( |
|
50 | + * 'route_name' => 'custom_post_type_slug' |
|
51 | + * ) |
|
52 | + * |
|
53 | + * @var array |
|
54 | + */ |
|
55 | + protected $_cpt_routes = array(); |
|
56 | + |
|
57 | 57 | |
58 | 58 | |
59 | - /** |
|
60 | - * This simply defines what the corresponding routes WP will be redirected to after completing a post save/update. |
|
61 | - * in this format: |
|
62 | - * array( |
|
63 | - * 'post_type_slug' => 'edit_route' |
|
64 | - * ) |
|
65 | - * |
|
66 | - * @var array |
|
67 | - */ |
|
68 | - protected $_cpt_edit_routes = array(); |
|
69 | - |
|
70 | - |
|
71 | - |
|
72 | - /** |
|
73 | - * If child classes set the name of their main model via the $_cpt_obj_models property, EE_Admin_Page_CPT will |
|
74 | - * attempt to retrieve the related object model for the edit pages and assign it to _cpt_page_object. the |
|
75 | - * _cpt_model_names property should be in the following format: array( |
|
76 | - * 'route_defined_by_action_param' => 'Model_Name') |
|
77 | - * |
|
78 | - * @var array $_cpt_model_names |
|
79 | - */ |
|
80 | - protected $_cpt_model_names = array(); |
|
81 | - |
|
82 | - |
|
83 | - /** |
|
84 | - * @var EE_CPT_Base |
|
85 | - */ |
|
86 | - protected $_cpt_model_obj = false; |
|
87 | - |
|
88 | - |
|
89 | - |
|
90 | - /** |
|
91 | - * This will hold an array of autosave containers that will be used to obtain input values and hook into the WP |
|
92 | - * autosave so we can save our inputs on the save_post hook! Children classes should add to this array by using |
|
93 | - * the _register_autosave_containers() method so that we don't override any other containers already registered. |
|
94 | - * Registration of containers should be done before load_page_dependencies() is run. |
|
95 | - * |
|
96 | - * @var array() |
|
97 | - */ |
|
98 | - protected $_autosave_containers = array(); |
|
99 | - protected $_autosave_fields = array(); |
|
100 | - |
|
101 | - /** |
|
102 | - * Array mapping from admin actions to their equivalent wp core pages for custom post types. So when a user visits |
|
103 | - * a page for an action, it will appear as if they were visiting the wp core page for that custom post type |
|
104 | - * |
|
105 | - * @var array |
|
106 | - */ |
|
107 | - protected $_pagenow_map; |
|
108 | - |
|
109 | - |
|
110 | - |
|
111 | - /** |
|
112 | - * This is hooked into the WordPress do_action('save_post') hook and runs after the custom post type has been |
|
113 | - * saved. Child classes are required to declare this method. Typically you would use this to save any additional |
|
114 | - * data. Keep in mind also that "save_post" runs on EVERY post update to the database. ALSO very important. When a |
|
115 | - * post transitions from scheduled to published, the save_post action is fired but you will NOT have any _POST data |
|
116 | - * containing any extra info you may have from other meta saves. So MAKE sure that you handle this accordingly. |
|
117 | - * |
|
118 | - * @access protected |
|
119 | - * @abstract |
|
120 | - * @param string $post_id The ID of the cpt that was saved (so you can link relationally) |
|
121 | - * @param EE_CPT_Base $post The post object of the cpt that was saved. |
|
122 | - * @return void |
|
123 | - */ |
|
124 | - abstract protected function _insert_update_cpt_item($post_id, $post); |
|
125 | - |
|
126 | - |
|
127 | - |
|
128 | - /** |
|
129 | - * This is hooked into the WordPress do_action('trashed_post') hook and runs after a cpt has been trashed. |
|
130 | - * |
|
131 | - * @abstract |
|
132 | - * @access public |
|
133 | - * @param string $post_id The ID of the cpt that was trashed |
|
134 | - * @return void |
|
135 | - */ |
|
136 | - abstract public function trash_cpt_item($post_id); |
|
137 | - |
|
138 | - |
|
139 | - |
|
140 | - /** |
|
141 | - * This is hooked into the WordPress do_action('untrashed_post') hook and runs after a cpt has been untrashed |
|
142 | - * |
|
143 | - * @param string $post_id theID of the cpt that was untrashed |
|
144 | - * @return void |
|
145 | - */ |
|
146 | - abstract public function restore_cpt_item($post_id); |
|
147 | - |
|
148 | - |
|
149 | - |
|
150 | - /** |
|
151 | - * This is hooked into the WordPress do_action('delete_cpt_item') hook and runs after a cpt has been fully deleted |
|
152 | - * from the db |
|
153 | - * |
|
154 | - * @param string $post_id the ID of the cpt that was deleted |
|
155 | - * @return void |
|
156 | - */ |
|
157 | - abstract public function delete_cpt_item($post_id); |
|
158 | - |
|
159 | - |
|
160 | - |
|
161 | - /** |
|
162 | - * Just utilizing the method EE_Admin exposes for doing things before page setup. |
|
163 | - * |
|
164 | - * @access protected |
|
165 | - * @return void |
|
166 | - */ |
|
167 | - protected function _before_page_setup() |
|
168 | - { |
|
169 | - $page = isset($this->_req_data['page']) ? $this->_req_data['page'] : $this->page_slug; |
|
170 | - $this->_cpt_routes = array_merge(array( |
|
171 | - 'create_new' => $this->page_slug, |
|
172 | - 'edit' => $this->page_slug, |
|
173 | - 'trash' => $this->page_slug, |
|
174 | - ), $this->_cpt_routes); |
|
175 | - //let's see if the current route has a value for cpt_object_slug if it does we use that instead of the page |
|
176 | - $this->_cpt_object = isset($this->_req_data['action']) && isset($this->_cpt_routes[$this->_req_data['action']]) |
|
177 | - ? get_post_type_object($this->_cpt_routes[$this->_req_data['action']]) |
|
178 | - : get_post_type_object($page); |
|
179 | - //tweak pagenow for page loading. |
|
180 | - if ( ! $this->_pagenow_map) { |
|
181 | - $this->_pagenow_map = array( |
|
182 | - 'create_new' => 'post-new.php', |
|
183 | - 'edit' => 'post.php', |
|
184 | - 'trash' => 'post.php', |
|
185 | - ); |
|
186 | - } |
|
187 | - add_action('current_screen', array($this, 'modify_pagenow')); |
|
188 | - //TODO the below will need to be reworked to account for the cpt routes that are NOT based off of page but action param. |
|
189 | - //get current page from autosave |
|
190 | - $current_page = isset($this->_req_data['ee_autosave_data']['ee-cpt-hidden-inputs']['current_page']) |
|
191 | - ? $this->_req_data['ee_autosave_data']['ee-cpt-hidden-inputs']['current_page'] |
|
192 | - : null; |
|
193 | - $this->_current_page = isset($this->_req_data['current_page']) |
|
194 | - ? $this->_req_data['current_page'] |
|
195 | - : $current_page; |
|
196 | - //autosave... make sure its only for the correct page |
|
197 | - //if ( ! empty($this->_current_page) && $this->_current_page == $this->page_slug) { |
|
198 | - //setup autosave ajax hook |
|
199 | - //add_action('wp_ajax_ee-autosave', array( $this, 'do_extra_autosave_stuff' ), 10 ); //TODO reactivate when 4.2 autosave is implemented |
|
200 | - //} |
|
201 | - } |
|
202 | - |
|
203 | - |
|
204 | - |
|
205 | - /** |
|
206 | - * Simply ensure that we simulate the correct post route for cpt screens |
|
207 | - * |
|
208 | - * @param WP_Screen $current_screen |
|
209 | - * @return void |
|
210 | - */ |
|
211 | - public function modify_pagenow($current_screen) |
|
212 | - { |
|
213 | - global $pagenow, $hook_suffix; |
|
214 | - //possibly reset pagenow. |
|
215 | - if ( ! empty($this->_req_data['page']) |
|
216 | - && $this->_req_data['page'] == $this->page_slug |
|
217 | - && ! empty($this->_req_data['action']) |
|
218 | - && isset($this->_pagenow_map[$this->_req_data['action']]) |
|
219 | - ) { |
|
220 | - $pagenow = $this->_pagenow_map[$this->_req_data['action']]; |
|
221 | - $hook_suffix = $pagenow; |
|
222 | - } |
|
223 | - } |
|
224 | - |
|
225 | - |
|
226 | - |
|
227 | - /** |
|
228 | - * This method is used to register additional autosave containers to the _autosave_containers property. |
|
229 | - * |
|
230 | - * @todo We should automate this at some point by creating a wrapper for add_post_metabox and in our wrapper we |
|
231 | - * automatically register the id for the post metabox as a container. |
|
232 | - * @param array $ids an array of ids for containers that hold form inputs we want autosave to pickup. Typically |
|
233 | - * you would send along the id of a metabox container. |
|
234 | - * @return void |
|
235 | - */ |
|
236 | - protected function _register_autosave_containers($ids) |
|
237 | - { |
|
238 | - $this->_autosave_containers = array_merge($this->_autosave_fields, (array)$ids); |
|
239 | - } |
|
240 | - |
|
241 | - |
|
242 | - |
|
243 | - /** |
|
244 | - * Something nifty. We're going to loop through all the registered metaboxes and if the CALLBACK is an instance of |
|
245 | - * EE_Admin_Page OR EE_Admin_Hooks, then we'll add the id to our _autosave_containers array. |
|
246 | - */ |
|
247 | - protected function _set_autosave_containers() |
|
248 | - { |
|
249 | - global $wp_meta_boxes; |
|
250 | - $containers = array(); |
|
251 | - if (empty($wp_meta_boxes)) { |
|
252 | - return; |
|
253 | - } |
|
254 | - $current_metaboxes = isset($wp_meta_boxes[$this->page_slug]) ? $wp_meta_boxes[$this->page_slug] : array(); |
|
255 | - foreach ($current_metaboxes as $box_context) { |
|
256 | - foreach ($box_context as $box_details) { |
|
257 | - foreach ($box_details as $box) { |
|
258 | - if ( |
|
259 | - is_array($box['callback']) |
|
260 | - && ( |
|
261 | - $box['callback'][0] instanceof EE_Admin_Page |
|
262 | - || $box['callback'][0] instanceof EE_Admin_Hooks |
|
263 | - ) |
|
264 | - ) { |
|
265 | - $containers[] = $box['id']; |
|
266 | - } |
|
267 | - } |
|
268 | - } |
|
269 | - } |
|
270 | - $this->_autosave_containers = array_merge($this->_autosave_containers, $containers); |
|
271 | - //add hidden inputs container |
|
272 | - $this->_autosave_containers[] = 'ee-cpt-hidden-inputs'; |
|
273 | - } |
|
274 | - |
|
275 | - |
|
276 | - |
|
277 | - protected function _load_autosave_scripts_styles() |
|
278 | - { |
|
279 | - /*wp_register_script('cpt-autosave', EE_ADMIN_URL . 'assets/ee-cpt-autosave.js', array('ee-serialize-full-array', 'event_editor_js'), EVENT_ESPRESSO_VERSION, TRUE ); |
|
59 | + /** |
|
60 | + * This simply defines what the corresponding routes WP will be redirected to after completing a post save/update. |
|
61 | + * in this format: |
|
62 | + * array( |
|
63 | + * 'post_type_slug' => 'edit_route' |
|
64 | + * ) |
|
65 | + * |
|
66 | + * @var array |
|
67 | + */ |
|
68 | + protected $_cpt_edit_routes = array(); |
|
69 | + |
|
70 | + |
|
71 | + |
|
72 | + /** |
|
73 | + * If child classes set the name of their main model via the $_cpt_obj_models property, EE_Admin_Page_CPT will |
|
74 | + * attempt to retrieve the related object model for the edit pages and assign it to _cpt_page_object. the |
|
75 | + * _cpt_model_names property should be in the following format: array( |
|
76 | + * 'route_defined_by_action_param' => 'Model_Name') |
|
77 | + * |
|
78 | + * @var array $_cpt_model_names |
|
79 | + */ |
|
80 | + protected $_cpt_model_names = array(); |
|
81 | + |
|
82 | + |
|
83 | + /** |
|
84 | + * @var EE_CPT_Base |
|
85 | + */ |
|
86 | + protected $_cpt_model_obj = false; |
|
87 | + |
|
88 | + |
|
89 | + |
|
90 | + /** |
|
91 | + * This will hold an array of autosave containers that will be used to obtain input values and hook into the WP |
|
92 | + * autosave so we can save our inputs on the save_post hook! Children classes should add to this array by using |
|
93 | + * the _register_autosave_containers() method so that we don't override any other containers already registered. |
|
94 | + * Registration of containers should be done before load_page_dependencies() is run. |
|
95 | + * |
|
96 | + * @var array() |
|
97 | + */ |
|
98 | + protected $_autosave_containers = array(); |
|
99 | + protected $_autosave_fields = array(); |
|
100 | + |
|
101 | + /** |
|
102 | + * Array mapping from admin actions to their equivalent wp core pages for custom post types. So when a user visits |
|
103 | + * a page for an action, it will appear as if they were visiting the wp core page for that custom post type |
|
104 | + * |
|
105 | + * @var array |
|
106 | + */ |
|
107 | + protected $_pagenow_map; |
|
108 | + |
|
109 | + |
|
110 | + |
|
111 | + /** |
|
112 | + * This is hooked into the WordPress do_action('save_post') hook and runs after the custom post type has been |
|
113 | + * saved. Child classes are required to declare this method. Typically you would use this to save any additional |
|
114 | + * data. Keep in mind also that "save_post" runs on EVERY post update to the database. ALSO very important. When a |
|
115 | + * post transitions from scheduled to published, the save_post action is fired but you will NOT have any _POST data |
|
116 | + * containing any extra info you may have from other meta saves. So MAKE sure that you handle this accordingly. |
|
117 | + * |
|
118 | + * @access protected |
|
119 | + * @abstract |
|
120 | + * @param string $post_id The ID of the cpt that was saved (so you can link relationally) |
|
121 | + * @param EE_CPT_Base $post The post object of the cpt that was saved. |
|
122 | + * @return void |
|
123 | + */ |
|
124 | + abstract protected function _insert_update_cpt_item($post_id, $post); |
|
125 | + |
|
126 | + |
|
127 | + |
|
128 | + /** |
|
129 | + * This is hooked into the WordPress do_action('trashed_post') hook and runs after a cpt has been trashed. |
|
130 | + * |
|
131 | + * @abstract |
|
132 | + * @access public |
|
133 | + * @param string $post_id The ID of the cpt that was trashed |
|
134 | + * @return void |
|
135 | + */ |
|
136 | + abstract public function trash_cpt_item($post_id); |
|
137 | + |
|
138 | + |
|
139 | + |
|
140 | + /** |
|
141 | + * This is hooked into the WordPress do_action('untrashed_post') hook and runs after a cpt has been untrashed |
|
142 | + * |
|
143 | + * @param string $post_id theID of the cpt that was untrashed |
|
144 | + * @return void |
|
145 | + */ |
|
146 | + abstract public function restore_cpt_item($post_id); |
|
147 | + |
|
148 | + |
|
149 | + |
|
150 | + /** |
|
151 | + * This is hooked into the WordPress do_action('delete_cpt_item') hook and runs after a cpt has been fully deleted |
|
152 | + * from the db |
|
153 | + * |
|
154 | + * @param string $post_id the ID of the cpt that was deleted |
|
155 | + * @return void |
|
156 | + */ |
|
157 | + abstract public function delete_cpt_item($post_id); |
|
158 | + |
|
159 | + |
|
160 | + |
|
161 | + /** |
|
162 | + * Just utilizing the method EE_Admin exposes for doing things before page setup. |
|
163 | + * |
|
164 | + * @access protected |
|
165 | + * @return void |
|
166 | + */ |
|
167 | + protected function _before_page_setup() |
|
168 | + { |
|
169 | + $page = isset($this->_req_data['page']) ? $this->_req_data['page'] : $this->page_slug; |
|
170 | + $this->_cpt_routes = array_merge(array( |
|
171 | + 'create_new' => $this->page_slug, |
|
172 | + 'edit' => $this->page_slug, |
|
173 | + 'trash' => $this->page_slug, |
|
174 | + ), $this->_cpt_routes); |
|
175 | + //let's see if the current route has a value for cpt_object_slug if it does we use that instead of the page |
|
176 | + $this->_cpt_object = isset($this->_req_data['action']) && isset($this->_cpt_routes[$this->_req_data['action']]) |
|
177 | + ? get_post_type_object($this->_cpt_routes[$this->_req_data['action']]) |
|
178 | + : get_post_type_object($page); |
|
179 | + //tweak pagenow for page loading. |
|
180 | + if ( ! $this->_pagenow_map) { |
|
181 | + $this->_pagenow_map = array( |
|
182 | + 'create_new' => 'post-new.php', |
|
183 | + 'edit' => 'post.php', |
|
184 | + 'trash' => 'post.php', |
|
185 | + ); |
|
186 | + } |
|
187 | + add_action('current_screen', array($this, 'modify_pagenow')); |
|
188 | + //TODO the below will need to be reworked to account for the cpt routes that are NOT based off of page but action param. |
|
189 | + //get current page from autosave |
|
190 | + $current_page = isset($this->_req_data['ee_autosave_data']['ee-cpt-hidden-inputs']['current_page']) |
|
191 | + ? $this->_req_data['ee_autosave_data']['ee-cpt-hidden-inputs']['current_page'] |
|
192 | + : null; |
|
193 | + $this->_current_page = isset($this->_req_data['current_page']) |
|
194 | + ? $this->_req_data['current_page'] |
|
195 | + : $current_page; |
|
196 | + //autosave... make sure its only for the correct page |
|
197 | + //if ( ! empty($this->_current_page) && $this->_current_page == $this->page_slug) { |
|
198 | + //setup autosave ajax hook |
|
199 | + //add_action('wp_ajax_ee-autosave', array( $this, 'do_extra_autosave_stuff' ), 10 ); //TODO reactivate when 4.2 autosave is implemented |
|
200 | + //} |
|
201 | + } |
|
202 | + |
|
203 | + |
|
204 | + |
|
205 | + /** |
|
206 | + * Simply ensure that we simulate the correct post route for cpt screens |
|
207 | + * |
|
208 | + * @param WP_Screen $current_screen |
|
209 | + * @return void |
|
210 | + */ |
|
211 | + public function modify_pagenow($current_screen) |
|
212 | + { |
|
213 | + global $pagenow, $hook_suffix; |
|
214 | + //possibly reset pagenow. |
|
215 | + if ( ! empty($this->_req_data['page']) |
|
216 | + && $this->_req_data['page'] == $this->page_slug |
|
217 | + && ! empty($this->_req_data['action']) |
|
218 | + && isset($this->_pagenow_map[$this->_req_data['action']]) |
|
219 | + ) { |
|
220 | + $pagenow = $this->_pagenow_map[$this->_req_data['action']]; |
|
221 | + $hook_suffix = $pagenow; |
|
222 | + } |
|
223 | + } |
|
224 | + |
|
225 | + |
|
226 | + |
|
227 | + /** |
|
228 | + * This method is used to register additional autosave containers to the _autosave_containers property. |
|
229 | + * |
|
230 | + * @todo We should automate this at some point by creating a wrapper for add_post_metabox and in our wrapper we |
|
231 | + * automatically register the id for the post metabox as a container. |
|
232 | + * @param array $ids an array of ids for containers that hold form inputs we want autosave to pickup. Typically |
|
233 | + * you would send along the id of a metabox container. |
|
234 | + * @return void |
|
235 | + */ |
|
236 | + protected function _register_autosave_containers($ids) |
|
237 | + { |
|
238 | + $this->_autosave_containers = array_merge($this->_autosave_fields, (array)$ids); |
|
239 | + } |
|
240 | + |
|
241 | + |
|
242 | + |
|
243 | + /** |
|
244 | + * Something nifty. We're going to loop through all the registered metaboxes and if the CALLBACK is an instance of |
|
245 | + * EE_Admin_Page OR EE_Admin_Hooks, then we'll add the id to our _autosave_containers array. |
|
246 | + */ |
|
247 | + protected function _set_autosave_containers() |
|
248 | + { |
|
249 | + global $wp_meta_boxes; |
|
250 | + $containers = array(); |
|
251 | + if (empty($wp_meta_boxes)) { |
|
252 | + return; |
|
253 | + } |
|
254 | + $current_metaboxes = isset($wp_meta_boxes[$this->page_slug]) ? $wp_meta_boxes[$this->page_slug] : array(); |
|
255 | + foreach ($current_metaboxes as $box_context) { |
|
256 | + foreach ($box_context as $box_details) { |
|
257 | + foreach ($box_details as $box) { |
|
258 | + if ( |
|
259 | + is_array($box['callback']) |
|
260 | + && ( |
|
261 | + $box['callback'][0] instanceof EE_Admin_Page |
|
262 | + || $box['callback'][0] instanceof EE_Admin_Hooks |
|
263 | + ) |
|
264 | + ) { |
|
265 | + $containers[] = $box['id']; |
|
266 | + } |
|
267 | + } |
|
268 | + } |
|
269 | + } |
|
270 | + $this->_autosave_containers = array_merge($this->_autosave_containers, $containers); |
|
271 | + //add hidden inputs container |
|
272 | + $this->_autosave_containers[] = 'ee-cpt-hidden-inputs'; |
|
273 | + } |
|
274 | + |
|
275 | + |
|
276 | + |
|
277 | + protected function _load_autosave_scripts_styles() |
|
278 | + { |
|
279 | + /*wp_register_script('cpt-autosave', EE_ADMIN_URL . 'assets/ee-cpt-autosave.js', array('ee-serialize-full-array', 'event_editor_js'), EVENT_ESPRESSO_VERSION, TRUE ); |
|
280 | 280 | wp_enqueue_script('cpt-autosave');/**/ //todo re-enable when we start doing autosave again in 4.2 |
281 | 281 | |
282 | - //filter _autosave_containers |
|
283 | - $containers = apply_filters('FHEE__EE_Admin_Page_CPT___load_autosave_scripts_styles__containers', |
|
284 | - $this->_autosave_containers, $this); |
|
285 | - $containers = apply_filters('FHEE__EE_Admin_Page_CPT__' . get_class($this) . '___load_autosave_scripts_styles__containers', |
|
286 | - $containers, $this); |
|
287 | - |
|
288 | - wp_localize_script('event_editor_js', 'EE_AUTOSAVE_IDS', |
|
289 | - $containers); //todo once we enable autosaves, this needs to be switched to localize with "cpt-autosave" |
|
290 | - |
|
291 | - $unsaved_data_msg = array( |
|
292 | - 'eventmsg' => sprintf(__("The changes you made to this %s will be lost if you navigate away from this page.", |
|
293 | - 'event_espresso'), $this->_cpt_object->labels->singular_name), |
|
294 | - 'inputChanged' => 0, |
|
295 | - ); |
|
296 | - wp_localize_script('event_editor_js', 'UNSAVED_DATA_MSG', $unsaved_data_msg); |
|
297 | - } |
|
298 | - |
|
299 | - |
|
300 | - |
|
301 | - public function load_page_dependencies() |
|
302 | - { |
|
303 | - try { |
|
304 | - $this->_load_page_dependencies(); |
|
305 | - } catch (EE_Error $e) { |
|
306 | - $e->get_error(); |
|
307 | - } |
|
308 | - } |
|
309 | - |
|
310 | - |
|
311 | - |
|
312 | - /** |
|
313 | - * overloading the EE_Admin_Page parent load_page_dependencies so we can get the cpt stuff added in appropriately |
|
314 | - * |
|
315 | - * @access protected |
|
316 | - * @return void |
|
317 | - */ |
|
318 | - protected function _load_page_dependencies() |
|
319 | - { |
|
320 | - //we only add stuff if this is a cpt_route! |
|
321 | - if ( ! $this->_cpt_route) { |
|
322 | - parent::_load_page_dependencies(); |
|
323 | - return; |
|
324 | - } |
|
325 | - // now let's do some automatic filters into the wp_system |
|
326 | - // and we'll check to make sure the CHILD class |
|
327 | - // automatically has the required methods in place. |
|
328 | - // the following filters are for setting all the redirects |
|
329 | - // on DEFAULT WP custom post type actions |
|
330 | - // let's add a hidden input to the post-edit form |
|
331 | - // so we know when we have to trigger our custom redirects! |
|
332 | - // Otherwise the redirects will happen on ALL post saves which wouldn't be good of course! |
|
333 | - add_action('edit_form_after_title', array($this, 'cpt_post_form_hidden_input')); |
|
334 | - // inject our Admin page nav tabs... |
|
335 | - // let's make sure the nav tabs are set if they aren't already |
|
336 | - // if ( empty( $this->_nav_tabs ) ) $this->_set_nav_tabs(); |
|
337 | - add_action('post_edit_form_tag', array($this, 'inject_nav_tabs')); |
|
338 | - // modify the post_updated messages array |
|
339 | - add_action('post_updated_messages', array($this, 'post_update_messages'), 10); |
|
340 | - // add shortlink button to cpt edit screens. We can do this as a universal thing BECAUSE, |
|
341 | - // cpts use the same format for shortlinks as posts! |
|
342 | - add_filter('pre_get_shortlink', array($this, 'add_shortlink_button_to_editor'), 10, 4); |
|
343 | - // This basically allows us to change the title of the "publish" metabox area |
|
344 | - // on CPT pages by setting a 'publishbox' value in the $_labels property array in the child class. |
|
345 | - if ( ! empty($this->_labels['publishbox'])) { |
|
346 | - $box_label = is_array($this->_labels['publishbox']) |
|
347 | - && isset($this->_labels['publishbox'][$this->_req_action]) |
|
348 | - ? $this->_labels['publishbox'][$this->_req_action] |
|
349 | - : $this->_labels['publishbox']; |
|
350 | - add_meta_box( |
|
351 | - 'submitdiv', |
|
352 | - $box_label, |
|
353 | - 'post_submit_meta_box', |
|
354 | - $this->_cpt_routes[$this->_req_action], |
|
355 | - 'side', |
|
356 | - 'core' |
|
357 | - ); |
|
358 | - } |
|
359 | - //let's add page_templates metabox if this cpt added support for it. |
|
360 | - if ($this->_supports_page_templates($this->_cpt_object->name)) { |
|
361 | - add_meta_box( |
|
362 | - 'page_templates', |
|
363 | - __('Page Template', 'event_espresso'), |
|
364 | - array($this, 'page_template_meta_box'), |
|
365 | - $this->_cpt_routes[$this->_req_action], |
|
366 | - 'side', |
|
367 | - 'default' |
|
368 | - ); |
|
369 | - } |
|
370 | - //this is a filter that allows the addition of extra html after the permalink field on the wp post edit-form |
|
371 | - if (method_exists($this, 'extra_permalink_field_buttons')) { |
|
372 | - add_filter('get_sample_permalink_html', array($this, 'extra_permalink_field_buttons'), 10, 4); |
|
373 | - } |
|
374 | - //add preview button |
|
375 | - add_filter('get_sample_permalink_html', array($this, 'preview_button_html'), 5, 4); |
|
376 | - //insert our own post_stati dropdown |
|
377 | - add_action('post_submitbox_misc_actions', array($this, 'custom_post_stati_dropdown'), 10); |
|
378 | - //This allows adding additional information to the publish post submitbox on the wp post edit form |
|
379 | - if (method_exists($this, 'extra_misc_actions_publish_box')) { |
|
380 | - add_action('post_submitbox_misc_actions', array($this, 'extra_misc_actions_publish_box'), 10); |
|
381 | - } |
|
382 | - // This allows for adding additional stuff after the title field on the wp post edit form. |
|
383 | - // This is also before the wp_editor for post description field. |
|
384 | - if (method_exists($this, 'edit_form_after_title')) { |
|
385 | - add_action('edit_form_after_title', array($this, 'edit_form_after_title'), 10); |
|
386 | - } |
|
387 | - /** |
|
388 | - * Filtering WP's esc_url to capture urls pointing to core wp routes so they point to our route. |
|
389 | - */ |
|
390 | - add_filter('clean_url', array($this, 'switch_core_wp_urls_with_ours'), 10, 3); |
|
391 | - parent::_load_page_dependencies(); |
|
392 | - // notice we are ALSO going to load the pagenow hook set for this route |
|
393 | - // (see _before_page_setup for the reset of the pagenow global ). |
|
394 | - // This is for any plugins that are doing things properly |
|
395 | - // and hooking into the load page hook for core wp cpt routes. |
|
396 | - global $pagenow; |
|
397 | - do_action('load-' . $pagenow); |
|
398 | - $this->modify_current_screen(); |
|
399 | - add_action('admin_enqueue_scripts', array($this, 'setup_autosave_hooks'), 30); |
|
400 | - //we route REALLY early. |
|
401 | - try { |
|
402 | - $this->_route_admin_request(); |
|
403 | - } catch (EE_Error $e) { |
|
404 | - $e->get_error(); |
|
405 | - } |
|
406 | - } |
|
407 | - |
|
408 | - |
|
409 | - |
|
410 | - /** |
|
411 | - * Since we don't want users going to default core wp routes, this will check any wp urls run through the |
|
412 | - * esc_url() method and if we see a url matching a pattern for our routes, we'll modify it to point to OUR |
|
413 | - * route instead. |
|
414 | - * |
|
415 | - * @param string $good_protocol_url The escaped url. |
|
416 | - * @param string $original_url The original url. |
|
417 | - * @param string $_context The context sent to the esc_url method. |
|
418 | - * @return string possibly a new url for our route. |
|
419 | - */ |
|
420 | - public function switch_core_wp_urls_with_ours($good_protocol_url, $original_url, $_context) |
|
421 | - { |
|
422 | - $routes_to_match = array( |
|
423 | - 0 => array( |
|
424 | - 'edit.php?post_type=espresso_attendees', |
|
425 | - 'admin.php?page=espresso_registrations&action=contact_list', |
|
426 | - ), |
|
427 | - 1 => array( |
|
428 | - 'edit.php?post_type=' . $this->_cpt_object->name, |
|
429 | - 'admin.php?page=' . $this->_cpt_object->name, |
|
430 | - ), |
|
431 | - ); |
|
432 | - foreach ($routes_to_match as $route_matches) { |
|
433 | - if (strpos($good_protocol_url, $route_matches[0]) !== false) { |
|
434 | - return str_replace($route_matches[0], $route_matches[1], $good_protocol_url); |
|
435 | - } |
|
436 | - } |
|
437 | - return $good_protocol_url; |
|
438 | - } |
|
439 | - |
|
440 | - |
|
441 | - |
|
442 | - /** |
|
443 | - * Determine whether the current cpt supports page templates or not. |
|
444 | - * |
|
445 | - * @since %VER% |
|
446 | - * @param string $cpt_name The cpt slug we're checking on. |
|
447 | - * @return bool True supported, false not. |
|
448 | - */ |
|
449 | - private function _supports_page_templates($cpt_name) |
|
450 | - { |
|
451 | - |
|
452 | - $cpt_args = EE_Register_CPTs::get_CPTs(); |
|
453 | - $cpt_args = isset($cpt_args[$cpt_name]) ? $cpt_args[$cpt_name]['args'] : array(); |
|
454 | - $cpt_has_support = ! empty($cpt_args['page_templates']); |
|
455 | - |
|
456 | - //if the installed version of WP is > 4.7 we do some additional checks. |
|
457 | - if (EE_Recommended_Versions::check_wp_version('4.7','>=')) { |
|
458 | - $post_templates = wp_get_theme()->get_post_templates(); |
|
459 | - //if there are $post_templates for this cpt, then we return false for this method because |
|
460 | - //that means we aren't going to load our page template manager and leave that up to the native |
|
461 | - //cpt template manager. |
|
462 | - $cpt_has_support = ! isset($post_templates[$cpt_name]) ? $cpt_has_support : false; |
|
463 | - } |
|
464 | - |
|
465 | - return $cpt_has_support; |
|
466 | - } |
|
467 | - |
|
468 | - |
|
469 | - /** |
|
470 | - * Callback for the page_templates metabox selector. |
|
471 | - * |
|
472 | - * @since %VER% |
|
473 | - * @return void |
|
474 | - */ |
|
475 | - public function page_template_meta_box() |
|
476 | - { |
|
477 | - global $post; |
|
478 | - $template = ''; |
|
479 | - |
|
480 | - if (EE_Recommended_Versions::check_wp_version('4.7','>=')) { |
|
481 | - $page_template_count = count(get_page_templates()); |
|
482 | - } else { |
|
483 | - $page_template_count = count(get_page_templates($post)); |
|
484 | - }; |
|
485 | - |
|
486 | - if ($page_template_count) { |
|
487 | - $page_template = get_post_meta($post->ID, '_wp_page_template', true); |
|
488 | - $template = ! empty($page_template) ? $page_template : ''; |
|
489 | - } |
|
490 | - ?> |
|
282 | + //filter _autosave_containers |
|
283 | + $containers = apply_filters('FHEE__EE_Admin_Page_CPT___load_autosave_scripts_styles__containers', |
|
284 | + $this->_autosave_containers, $this); |
|
285 | + $containers = apply_filters('FHEE__EE_Admin_Page_CPT__' . get_class($this) . '___load_autosave_scripts_styles__containers', |
|
286 | + $containers, $this); |
|
287 | + |
|
288 | + wp_localize_script('event_editor_js', 'EE_AUTOSAVE_IDS', |
|
289 | + $containers); //todo once we enable autosaves, this needs to be switched to localize with "cpt-autosave" |
|
290 | + |
|
291 | + $unsaved_data_msg = array( |
|
292 | + 'eventmsg' => sprintf(__("The changes you made to this %s will be lost if you navigate away from this page.", |
|
293 | + 'event_espresso'), $this->_cpt_object->labels->singular_name), |
|
294 | + 'inputChanged' => 0, |
|
295 | + ); |
|
296 | + wp_localize_script('event_editor_js', 'UNSAVED_DATA_MSG', $unsaved_data_msg); |
|
297 | + } |
|
298 | + |
|
299 | + |
|
300 | + |
|
301 | + public function load_page_dependencies() |
|
302 | + { |
|
303 | + try { |
|
304 | + $this->_load_page_dependencies(); |
|
305 | + } catch (EE_Error $e) { |
|
306 | + $e->get_error(); |
|
307 | + } |
|
308 | + } |
|
309 | + |
|
310 | + |
|
311 | + |
|
312 | + /** |
|
313 | + * overloading the EE_Admin_Page parent load_page_dependencies so we can get the cpt stuff added in appropriately |
|
314 | + * |
|
315 | + * @access protected |
|
316 | + * @return void |
|
317 | + */ |
|
318 | + protected function _load_page_dependencies() |
|
319 | + { |
|
320 | + //we only add stuff if this is a cpt_route! |
|
321 | + if ( ! $this->_cpt_route) { |
|
322 | + parent::_load_page_dependencies(); |
|
323 | + return; |
|
324 | + } |
|
325 | + // now let's do some automatic filters into the wp_system |
|
326 | + // and we'll check to make sure the CHILD class |
|
327 | + // automatically has the required methods in place. |
|
328 | + // the following filters are for setting all the redirects |
|
329 | + // on DEFAULT WP custom post type actions |
|
330 | + // let's add a hidden input to the post-edit form |
|
331 | + // so we know when we have to trigger our custom redirects! |
|
332 | + // Otherwise the redirects will happen on ALL post saves which wouldn't be good of course! |
|
333 | + add_action('edit_form_after_title', array($this, 'cpt_post_form_hidden_input')); |
|
334 | + // inject our Admin page nav tabs... |
|
335 | + // let's make sure the nav tabs are set if they aren't already |
|
336 | + // if ( empty( $this->_nav_tabs ) ) $this->_set_nav_tabs(); |
|
337 | + add_action('post_edit_form_tag', array($this, 'inject_nav_tabs')); |
|
338 | + // modify the post_updated messages array |
|
339 | + add_action('post_updated_messages', array($this, 'post_update_messages'), 10); |
|
340 | + // add shortlink button to cpt edit screens. We can do this as a universal thing BECAUSE, |
|
341 | + // cpts use the same format for shortlinks as posts! |
|
342 | + add_filter('pre_get_shortlink', array($this, 'add_shortlink_button_to_editor'), 10, 4); |
|
343 | + // This basically allows us to change the title of the "publish" metabox area |
|
344 | + // on CPT pages by setting a 'publishbox' value in the $_labels property array in the child class. |
|
345 | + if ( ! empty($this->_labels['publishbox'])) { |
|
346 | + $box_label = is_array($this->_labels['publishbox']) |
|
347 | + && isset($this->_labels['publishbox'][$this->_req_action]) |
|
348 | + ? $this->_labels['publishbox'][$this->_req_action] |
|
349 | + : $this->_labels['publishbox']; |
|
350 | + add_meta_box( |
|
351 | + 'submitdiv', |
|
352 | + $box_label, |
|
353 | + 'post_submit_meta_box', |
|
354 | + $this->_cpt_routes[$this->_req_action], |
|
355 | + 'side', |
|
356 | + 'core' |
|
357 | + ); |
|
358 | + } |
|
359 | + //let's add page_templates metabox if this cpt added support for it. |
|
360 | + if ($this->_supports_page_templates($this->_cpt_object->name)) { |
|
361 | + add_meta_box( |
|
362 | + 'page_templates', |
|
363 | + __('Page Template', 'event_espresso'), |
|
364 | + array($this, 'page_template_meta_box'), |
|
365 | + $this->_cpt_routes[$this->_req_action], |
|
366 | + 'side', |
|
367 | + 'default' |
|
368 | + ); |
|
369 | + } |
|
370 | + //this is a filter that allows the addition of extra html after the permalink field on the wp post edit-form |
|
371 | + if (method_exists($this, 'extra_permalink_field_buttons')) { |
|
372 | + add_filter('get_sample_permalink_html', array($this, 'extra_permalink_field_buttons'), 10, 4); |
|
373 | + } |
|
374 | + //add preview button |
|
375 | + add_filter('get_sample_permalink_html', array($this, 'preview_button_html'), 5, 4); |
|
376 | + //insert our own post_stati dropdown |
|
377 | + add_action('post_submitbox_misc_actions', array($this, 'custom_post_stati_dropdown'), 10); |
|
378 | + //This allows adding additional information to the publish post submitbox on the wp post edit form |
|
379 | + if (method_exists($this, 'extra_misc_actions_publish_box')) { |
|
380 | + add_action('post_submitbox_misc_actions', array($this, 'extra_misc_actions_publish_box'), 10); |
|
381 | + } |
|
382 | + // This allows for adding additional stuff after the title field on the wp post edit form. |
|
383 | + // This is also before the wp_editor for post description field. |
|
384 | + if (method_exists($this, 'edit_form_after_title')) { |
|
385 | + add_action('edit_form_after_title', array($this, 'edit_form_after_title'), 10); |
|
386 | + } |
|
387 | + /** |
|
388 | + * Filtering WP's esc_url to capture urls pointing to core wp routes so they point to our route. |
|
389 | + */ |
|
390 | + add_filter('clean_url', array($this, 'switch_core_wp_urls_with_ours'), 10, 3); |
|
391 | + parent::_load_page_dependencies(); |
|
392 | + // notice we are ALSO going to load the pagenow hook set for this route |
|
393 | + // (see _before_page_setup for the reset of the pagenow global ). |
|
394 | + // This is for any plugins that are doing things properly |
|
395 | + // and hooking into the load page hook for core wp cpt routes. |
|
396 | + global $pagenow; |
|
397 | + do_action('load-' . $pagenow); |
|
398 | + $this->modify_current_screen(); |
|
399 | + add_action('admin_enqueue_scripts', array($this, 'setup_autosave_hooks'), 30); |
|
400 | + //we route REALLY early. |
|
401 | + try { |
|
402 | + $this->_route_admin_request(); |
|
403 | + } catch (EE_Error $e) { |
|
404 | + $e->get_error(); |
|
405 | + } |
|
406 | + } |
|
407 | + |
|
408 | + |
|
409 | + |
|
410 | + /** |
|
411 | + * Since we don't want users going to default core wp routes, this will check any wp urls run through the |
|
412 | + * esc_url() method and if we see a url matching a pattern for our routes, we'll modify it to point to OUR |
|
413 | + * route instead. |
|
414 | + * |
|
415 | + * @param string $good_protocol_url The escaped url. |
|
416 | + * @param string $original_url The original url. |
|
417 | + * @param string $_context The context sent to the esc_url method. |
|
418 | + * @return string possibly a new url for our route. |
|
419 | + */ |
|
420 | + public function switch_core_wp_urls_with_ours($good_protocol_url, $original_url, $_context) |
|
421 | + { |
|
422 | + $routes_to_match = array( |
|
423 | + 0 => array( |
|
424 | + 'edit.php?post_type=espresso_attendees', |
|
425 | + 'admin.php?page=espresso_registrations&action=contact_list', |
|
426 | + ), |
|
427 | + 1 => array( |
|
428 | + 'edit.php?post_type=' . $this->_cpt_object->name, |
|
429 | + 'admin.php?page=' . $this->_cpt_object->name, |
|
430 | + ), |
|
431 | + ); |
|
432 | + foreach ($routes_to_match as $route_matches) { |
|
433 | + if (strpos($good_protocol_url, $route_matches[0]) !== false) { |
|
434 | + return str_replace($route_matches[0], $route_matches[1], $good_protocol_url); |
|
435 | + } |
|
436 | + } |
|
437 | + return $good_protocol_url; |
|
438 | + } |
|
439 | + |
|
440 | + |
|
441 | + |
|
442 | + /** |
|
443 | + * Determine whether the current cpt supports page templates or not. |
|
444 | + * |
|
445 | + * @since %VER% |
|
446 | + * @param string $cpt_name The cpt slug we're checking on. |
|
447 | + * @return bool True supported, false not. |
|
448 | + */ |
|
449 | + private function _supports_page_templates($cpt_name) |
|
450 | + { |
|
451 | + |
|
452 | + $cpt_args = EE_Register_CPTs::get_CPTs(); |
|
453 | + $cpt_args = isset($cpt_args[$cpt_name]) ? $cpt_args[$cpt_name]['args'] : array(); |
|
454 | + $cpt_has_support = ! empty($cpt_args['page_templates']); |
|
455 | + |
|
456 | + //if the installed version of WP is > 4.7 we do some additional checks. |
|
457 | + if (EE_Recommended_Versions::check_wp_version('4.7','>=')) { |
|
458 | + $post_templates = wp_get_theme()->get_post_templates(); |
|
459 | + //if there are $post_templates for this cpt, then we return false for this method because |
|
460 | + //that means we aren't going to load our page template manager and leave that up to the native |
|
461 | + //cpt template manager. |
|
462 | + $cpt_has_support = ! isset($post_templates[$cpt_name]) ? $cpt_has_support : false; |
|
463 | + } |
|
464 | + |
|
465 | + return $cpt_has_support; |
|
466 | + } |
|
467 | + |
|
468 | + |
|
469 | + /** |
|
470 | + * Callback for the page_templates metabox selector. |
|
471 | + * |
|
472 | + * @since %VER% |
|
473 | + * @return void |
|
474 | + */ |
|
475 | + public function page_template_meta_box() |
|
476 | + { |
|
477 | + global $post; |
|
478 | + $template = ''; |
|
479 | + |
|
480 | + if (EE_Recommended_Versions::check_wp_version('4.7','>=')) { |
|
481 | + $page_template_count = count(get_page_templates()); |
|
482 | + } else { |
|
483 | + $page_template_count = count(get_page_templates($post)); |
|
484 | + }; |
|
485 | + |
|
486 | + if ($page_template_count) { |
|
487 | + $page_template = get_post_meta($post->ID, '_wp_page_template', true); |
|
488 | + $template = ! empty($page_template) ? $page_template : ''; |
|
489 | + } |
|
490 | + ?> |
|
491 | 491 | <p><strong><?php _e('Template') ?></strong></p> |
492 | 492 | <label class="screen-reader-text" for="page_template"><?php _e('Page Template') ?></label><select |
493 | 493 | name="page_template" id="page_template"> |
@@ -495,450 +495,450 @@ discard block |
||
495 | 495 | <?php page_template_dropdown($template); ?> |
496 | 496 | </select> |
497 | 497 | <?php |
498 | - } |
|
499 | - |
|
500 | - |
|
501 | - |
|
502 | - /** |
|
503 | - * if this post is a draft or scheduled post then we provide a preview button for user to click |
|
504 | - * Method is called from parent and is hooked into the wp 'get_sample_permalink_html' filter. |
|
505 | - * |
|
506 | - * @param string $return the current html |
|
507 | - * @param int $id the post id for the page |
|
508 | - * @param string $new_title What the title is |
|
509 | - * @param string $new_slug what the slug is |
|
510 | - * @return string The new html string for the permalink area |
|
511 | - */ |
|
512 | - public function preview_button_html($return, $id, $new_title, $new_slug) |
|
513 | - { |
|
514 | - $post = get_post($id); |
|
515 | - if ('publish' !== get_post_status($post)) { |
|
516 | - //include shims for the `get_preview_post_link` function |
|
517 | - require_once( EE_CORE . 'wordpress-shims.php' ); |
|
518 | - $return .= '<span_id="view-post-btn"><a target="_blank" href="' |
|
519 | - . get_preview_post_link($id) |
|
520 | - . '" class="button button-small">' |
|
521 | - . __('Preview', 'event_espresso') |
|
522 | - . '</a></span>' |
|
523 | - . "\n"; |
|
524 | - } |
|
525 | - return $return; |
|
526 | - } |
|
527 | - |
|
528 | - |
|
529 | - |
|
530 | - /** |
|
531 | - * add our custom post stati dropdown on the wp post page for this cpt |
|
532 | - * |
|
533 | - * @return void |
|
534 | - */ |
|
535 | - public function custom_post_stati_dropdown() |
|
536 | - { |
|
537 | - |
|
538 | - $statuses = $this->_cpt_model_obj->get_custom_post_statuses(); |
|
539 | - $cur_status_label = array_key_exists($this->_cpt_model_obj->status(), $statuses) |
|
540 | - ? $statuses[$this->_cpt_model_obj->status()] |
|
541 | - : ''; |
|
542 | - $template_args = array( |
|
543 | - 'cur_status' => $this->_cpt_model_obj->status(), |
|
544 | - 'statuses' => $statuses, |
|
545 | - 'cur_status_label' => $cur_status_label, |
|
546 | - 'localized_status_save' => sprintf(__('Save %s', 'event_espresso'), $cur_status_label), |
|
547 | - ); |
|
548 | - //we'll add a trash post status (WP doesn't add one for some reason) |
|
549 | - if ($this->_cpt_model_obj->status() === 'trash') { |
|
550 | - $template_args['cur_status_label'] = __('Trashed', 'event_espresso'); |
|
551 | - $statuses['trash'] = __('Trashed', 'event_espresso'); |
|
552 | - $template_args['statuses'] = $statuses; |
|
553 | - } |
|
554 | - |
|
555 | - $template = EE_ADMIN_TEMPLATE . 'status_dropdown.template.php'; |
|
556 | - EEH_Template::display_template($template, $template_args); |
|
557 | - } |
|
558 | - |
|
559 | - |
|
560 | - |
|
561 | - public function setup_autosave_hooks() |
|
562 | - { |
|
563 | - $this->_set_autosave_containers(); |
|
564 | - $this->_load_autosave_scripts_styles(); |
|
565 | - } |
|
566 | - |
|
567 | - |
|
568 | - |
|
569 | - /** |
|
570 | - * This is run on all WordPress autosaves AFTER the autosave is complete and sends along a $_POST object (available |
|
571 | - * in $this->_req_data) containing: post_ID of the saved post autosavenonce for the saved post We'll do the check |
|
572 | - * for the nonce in here, but then this method looks for two things: |
|
573 | - * 1. Execute a method (if exists) matching 'ee_autosave_' and appended with the given route. OR |
|
574 | - * 2. do_actions() for global or class specific actions that have been registered (for plugins/addons not in an |
|
575 | - * EE_Admin_Page class. PLEASE NOTE: Data will be returned using the _return_json() object and so the |
|
576 | - * $_template_args property should be used to hold the $data array. We're expecting the following things set in |
|
577 | - * template args. |
|
578 | - * 1. $template_args['error'] = IF there is an error you can add the message in here. |
|
579 | - * 2. $template_args['data']['items'] = an array of items that are setup in key index pairs of 'where_values_go' |
|
580 | - * => 'values_to_add'. In other words, for the datetime metabox we'll have something like |
|
581 | - * $this->_template_args['data']['items'] = array( |
|
582 | - * 'event-datetime-ids' => '1,2,3'; |
|
583 | - * ); |
|
584 | - * Keep in mind the following things: |
|
585 | - * - "where" index is for the input with the id as that string. |
|
586 | - * - "what" index is what will be used for the value of that input. |
|
587 | - * |
|
588 | - * @return void |
|
589 | - */ |
|
590 | - public function do_extra_autosave_stuff() |
|
591 | - { |
|
592 | - //next let's check for the autosave nonce (we'll use _verify_nonce ) |
|
593 | - $nonce = isset($this->_req_data['autosavenonce']) |
|
594 | - ? $this->_req_data['autosavenonce'] |
|
595 | - : null; |
|
596 | - $this->_verify_nonce($nonce, 'autosave'); |
|
597 | - //make sure we define doing autosave (cause WP isn't triggering this we want to make sure we define it) |
|
598 | - if ( ! defined('DOING_AUTOSAVE')) { |
|
599 | - define('DOING_AUTOSAVE', true); |
|
600 | - } |
|
601 | - //if we made it here then the nonce checked out. Let's run our methods and actions |
|
602 | - $autosave = "_ee_autosave_{$this->_current_view}"; |
|
603 | - if (method_exists($this, $autosave)) { |
|
604 | - $this->$autosave(); |
|
605 | - } else { |
|
606 | - $this->_template_args['success'] = true; |
|
607 | - } |
|
608 | - do_action('AHEE__EE_Admin_Page_CPT__do_extra_autosave_stuff__global_after', $this); |
|
609 | - do_action('AHEE__EE_Admin_Page_CPT__do_extra_autosave_stuff__after_' . get_class($this), $this); |
|
610 | - //now let's return json |
|
611 | - $this->_return_json(); |
|
612 | - } |
|
613 | - |
|
614 | - |
|
615 | - |
|
616 | - /** |
|
617 | - * This takes care of setting up default routes and pages that utilize the core WP admin pages. |
|
618 | - * Child classes can override the defaults (in cases for adding metaboxes etc.) |
|
619 | - * but take care that you include the defaults here otherwise your core WP admin pages for the cpt won't work! |
|
620 | - * |
|
621 | - * @access protected |
|
622 | - * @throws EE_Error |
|
623 | - * @return void |
|
624 | - */ |
|
625 | - protected function _extend_page_config_for_cpt() |
|
626 | - { |
|
627 | - //before doing anything we need to make sure this runs ONLY when the loaded page matches the set page_slug |
|
628 | - if (isset($this->_req_data['page']) && $this->_req_data['page'] !== $this->page_slug) { |
|
629 | - return; |
|
630 | - } |
|
631 | - //set page routes and page config but ONLY if we're not viewing a custom setup cpt route as defined in _cpt_routes |
|
632 | - if ( ! empty($this->_cpt_object)) { |
|
633 | - $this->_page_routes = array_merge(array( |
|
634 | - 'create_new' => '_create_new_cpt_item', |
|
635 | - 'edit' => '_edit_cpt_item', |
|
636 | - ), $this->_page_routes); |
|
637 | - $this->_page_config = array_merge(array( |
|
638 | - 'create_new' => array( |
|
639 | - 'nav' => array( |
|
640 | - 'label' => $this->_cpt_object->labels->add_new_item, |
|
641 | - 'order' => 5, |
|
642 | - ), |
|
643 | - 'require_nonce' => false, |
|
644 | - ), |
|
645 | - 'edit' => array( |
|
646 | - 'nav' => array( |
|
647 | - 'label' => $this->_cpt_object->labels->edit_item, |
|
648 | - 'order' => 5, |
|
649 | - 'persistent' => false, |
|
650 | - 'url' => '', |
|
651 | - ), |
|
652 | - 'require_nonce' => false, |
|
653 | - ), |
|
654 | - ), |
|
655 | - $this->_page_config |
|
656 | - ); |
|
657 | - } |
|
658 | - //load the next section only if this is a matching cpt route as set in the cpt routes array. |
|
659 | - if ( ! isset($this->_cpt_routes[$this->_req_action])) { |
|
660 | - return; |
|
661 | - } |
|
662 | - $this->_cpt_route = isset($this->_cpt_routes[$this->_req_action]) ? true : false; |
|
663 | - //add_action('FHEE__EE_Admin_Page___load_page_dependencies__after_load', array( $this, 'modify_current_screen') ); |
|
664 | - if (empty($this->_cpt_object)) { |
|
665 | - $msg = sprintf(__('This page has been set as being related to a registered custom post type, however, the custom post type object could not be retrieved. There are two possible reasons for this: 1. The "%s" does not match a registered post type. or 2. The custom post type is not registered for the "%s" action as indexed in the "$_cpt_routes" property on this class (%s).'), |
|
666 | - $this->page_slug, $this->_req_action, get_class($this)); |
|
667 | - throw new EE_Error($msg); |
|
668 | - } |
|
669 | - if ($this->_cpt_route) { |
|
670 | - $id = isset($this->_req_data['post']) ? $this->_req_data['post'] : null; |
|
671 | - $this->_set_model_object($id); |
|
672 | - } |
|
673 | - } |
|
674 | - |
|
675 | - |
|
676 | - |
|
677 | - /** |
|
678 | - * Sets the _cpt_model_object property using what has been set for the _cpt_model_name and a given id. |
|
679 | - * |
|
680 | - * @access protected |
|
681 | - * @param int $id The id to retrieve the model object for. If empty we set a default object. |
|
682 | - * @param bool $ignore_route_check |
|
683 | - * @param string $req_type whether the current route is for inserting, updating, or deleting the CPT |
|
684 | - * @throws EE_Error |
|
685 | - */ |
|
686 | - protected function _set_model_object($id = null, $ignore_route_check = false, $req_type = '') |
|
687 | - { |
|
688 | - $model = null; |
|
689 | - if ( |
|
690 | - empty($this->_cpt_model_names) |
|
691 | - || ( |
|
692 | - ! $ignore_route_check |
|
693 | - && ! isset($this->_cpt_routes[$this->_req_action]) |
|
694 | - ) || ( |
|
695 | - $this->_cpt_model_obj instanceof EE_CPT_Base |
|
696 | - && $this->_cpt_model_obj->ID() === $id |
|
697 | - ) |
|
698 | - ) { |
|
699 | - //get out cuz we either don't have a model name OR the object has already been set and it has the same id as what has been sent. |
|
700 | - return; |
|
701 | - } |
|
702 | - //if ignore_route_check is true, then get the model name via EE_Register_CPTs |
|
703 | - if ($ignore_route_check) { |
|
704 | - $model_names = EE_Register_CPTs::get_cpt_model_names(); |
|
705 | - $post_type = get_post_type($id); |
|
706 | - if (isset($model_names[$post_type])) { |
|
707 | - $model = EE_Registry::instance()->load_model($model_names[$post_type]); |
|
708 | - } |
|
709 | - } else { |
|
710 | - $model = EE_Registry::instance()->load_model($this->_cpt_model_names[$this->_req_action]); |
|
711 | - } |
|
712 | - if ($model instanceof EEM_Base) { |
|
713 | - $this->_cpt_model_obj = ! empty($id) ? $model->get_one_by_ID($id) : $model->create_default_object(); |
|
714 | - } |
|
715 | - do_action( |
|
716 | - 'AHEE__EE_Admin_Page_CPT__set_model_object__after_set_object', |
|
717 | - $this->_cpt_model_obj, |
|
718 | - $req_type |
|
719 | - ); |
|
720 | - } |
|
721 | - |
|
722 | - |
|
723 | - |
|
724 | - /** |
|
725 | - * admin_init_global |
|
726 | - * This runs all the code that we want executed within the WP admin_init hook. |
|
727 | - * This method executes for ALL EE Admin pages. |
|
728 | - * |
|
729 | - * @access public |
|
730 | - * @return void |
|
731 | - */ |
|
732 | - public function admin_init_global() |
|
733 | - { |
|
734 | - $post = isset($this->_req_data['post']) ? get_post($this->_req_data['post']) : null; |
|
735 | - //its possible this is a new save so let's catch that instead |
|
736 | - $post = isset($this->_req_data['post_ID']) ? get_post($this->_req_data['post_ID']) : $post; |
|
737 | - $post_type = $post ? $post->post_type : false; |
|
738 | - $current_route = isset($this->_req_data['current_route']) |
|
739 | - ? $this->_req_data['current_route'] |
|
740 | - : 'shouldneverwork'; |
|
741 | - $route_to_check = $post_type && isset($this->_cpt_routes[$current_route]) |
|
742 | - ? $this->_cpt_routes[$current_route] |
|
743 | - : ''; |
|
744 | - add_filter('get_delete_post_link', array($this, 'modify_delete_post_link'), 10, 3); |
|
745 | - add_filter('get_edit_post_link', array($this, 'modify_edit_post_link'), 10, 3); |
|
746 | - if ($post_type === $route_to_check) { |
|
747 | - add_filter('redirect_post_location', array($this, 'cpt_post_location_redirect'), 10, 2); |
|
748 | - } |
|
749 | - //now let's filter redirect if we're on a revision page and the revision is for an event CPT. |
|
750 | - $revision = isset($this->_req_data['revision']) ? $this->_req_data['revision'] : null; |
|
751 | - if ( ! empty($revision)) { |
|
752 | - $action = isset($this->_req_data['action']) ? $this->_req_data['action'] : null; |
|
753 | - //doing a restore? |
|
754 | - if ( ! empty($action) && $action === 'restore') { |
|
755 | - //get post for revision |
|
756 | - $rev_post = get_post($revision); |
|
757 | - $rev_parent = get_post($rev_post->post_parent); |
|
758 | - //only do our redirect filter AND our restore revision action if the post_type for the parent is one of our cpts. |
|
759 | - if ($rev_parent && $rev_parent->post_type === $this->page_slug) { |
|
760 | - add_filter('wp_redirect', array($this, 'revision_redirect'), 10, 2); |
|
761 | - //restores of revisions |
|
762 | - add_action('wp_restore_post_revision', array($this, 'restore_revision'), 10, 2); |
|
763 | - } |
|
764 | - } |
|
765 | - } |
|
766 | - //NOTE we ONLY want to run these hooks if we're on the right class for the given post type. Otherwise we could see some really freaky things happen! |
|
767 | - if ($post_type && $post_type === $route_to_check) { |
|
768 | - //$post_id, $post |
|
769 | - add_action('save_post', array($this, 'insert_update'), 10, 3); |
|
770 | - //$post_id |
|
771 | - add_action('trashed_post', array($this, 'before_trash_cpt_item'), 10); |
|
772 | - add_action('trashed_post', array($this, 'dont_permanently_delete_ee_cpts'), 10); |
|
773 | - add_action('untrashed_post', array($this, 'before_restore_cpt_item'), 10); |
|
774 | - add_action('after_delete_post', array($this, 'before_delete_cpt_item'), 10); |
|
775 | - } |
|
776 | - } |
|
777 | - |
|
778 | - |
|
779 | - |
|
780 | - /** |
|
781 | - * Callback for the WordPress trashed_post hook. |
|
782 | - * Execute some basic checks before calling the trash_cpt_item declared in the child class. |
|
783 | - * |
|
784 | - * @param int $post_id |
|
785 | - * @throws \EE_Error |
|
786 | - */ |
|
787 | - public function before_trash_cpt_item($post_id) |
|
788 | - { |
|
789 | - $this->_set_model_object($post_id, true, 'trash'); |
|
790 | - //if our cpt object isn't existent then get out immediately. |
|
791 | - if ( ! $this->_cpt_model_obj instanceof EE_CPT_Base || $this->_cpt_model_obj->ID() !== $post_id) { |
|
792 | - return; |
|
793 | - } |
|
794 | - $this->trash_cpt_item($post_id); |
|
795 | - } |
|
796 | - |
|
797 | - |
|
798 | - |
|
799 | - /** |
|
800 | - * Callback for the WordPress untrashed_post hook. |
|
801 | - * Execute some basic checks before calling the restore_cpt_method in the child class. |
|
802 | - * |
|
803 | - * @param $post_id |
|
804 | - * @throws \EE_Error |
|
805 | - */ |
|
806 | - public function before_restore_cpt_item($post_id) |
|
807 | - { |
|
808 | - $this->_set_model_object($post_id, true, 'restore'); |
|
809 | - //if our cpt object isn't existent then get out immediately. |
|
810 | - if ( ! $this->_cpt_model_obj instanceof EE_CPT_Base || $this->_cpt_model_obj->ID() !== $post_id) { |
|
811 | - return; |
|
812 | - } |
|
813 | - $this->restore_cpt_item($post_id); |
|
814 | - } |
|
815 | - |
|
816 | - |
|
817 | - |
|
818 | - /** |
|
819 | - * Callback for the WordPress after_delete_post hook. |
|
820 | - * Execute some basic checks before calling the delete_cpt_item method in the child class. |
|
821 | - * |
|
822 | - * @param $post_id |
|
823 | - * @throws \EE_Error |
|
824 | - */ |
|
825 | - public function before_delete_cpt_item($post_id) |
|
826 | - { |
|
827 | - $this->_set_model_object($post_id, true, 'delete'); |
|
828 | - //if our cpt object isn't existent then get out immediately. |
|
829 | - if ( ! $this->_cpt_model_obj instanceof EE_CPT_Base || $this->_cpt_model_obj->ID() !== $post_id) { |
|
830 | - return; |
|
831 | - } |
|
832 | - $this->delete_cpt_item($post_id); |
|
833 | - } |
|
834 | - |
|
835 | - |
|
836 | - |
|
837 | - /** |
|
838 | - * This simply verifies if the cpt_model_object is instantiated for the given page and throws an error message |
|
839 | - * accordingly. |
|
840 | - * |
|
841 | - * @access public |
|
842 | - * @throws EE_Error |
|
843 | - * @return void |
|
844 | - */ |
|
845 | - public function verify_cpt_object() |
|
846 | - { |
|
847 | - $label = ! empty($this->_cpt_object) ? $this->_cpt_object->labels->singular_name : $this->page_label; |
|
848 | - // verify event object |
|
849 | - if ( ! $this->_cpt_model_obj instanceof EE_CPT_Base) { |
|
850 | - throw new EE_Error(sprintf(__('Something has gone wrong with the page load because we are unable to set up the object for the %1$s. This usually happens when the given id for the page route is NOT for the correct custom post type for this page', |
|
851 | - 'event_espresso'), $label)); |
|
852 | - } |
|
853 | - //if auto-draft then throw an error |
|
854 | - if ($this->_cpt_model_obj->get('status') === 'auto-draft') { |
|
855 | - EE_Error::overwrite_errors(); |
|
856 | - EE_Error::add_error(sprintf(__('This %1$s was saved without a title, description, or excerpt which means that none of the extra details you added were saved properly. All autodrafts will show up in the "draft" view of your event list table. You can delete them from there. Please click the "Add %1$s" button to refresh and restart.'), |
|
857 | - $label), __FILE__, __FUNCTION__, __LINE__); |
|
858 | - } |
|
859 | - } |
|
860 | - |
|
861 | - |
|
862 | - |
|
863 | - /** |
|
864 | - * admin_footer_scripts_global |
|
865 | - * Anything triggered by the 'admin_print_footer_scripts' WP hook should be put in here. This particular method |
|
866 | - * will apply on ALL EE_Admin pages. |
|
867 | - * |
|
868 | - * @access public |
|
869 | - * @return void |
|
870 | - */ |
|
871 | - public function admin_footer_scripts_global() |
|
872 | - { |
|
873 | - $this->_add_admin_page_ajax_loading_img(); |
|
874 | - $this->_add_admin_page_overlay(); |
|
875 | - } |
|
876 | - |
|
877 | - |
|
878 | - |
|
879 | - /** |
|
880 | - * add in any global scripts for cpt routes |
|
881 | - * |
|
882 | - * @return void |
|
883 | - */ |
|
884 | - public function load_global_scripts_styles() |
|
885 | - { |
|
886 | - parent::load_global_scripts_styles(); |
|
887 | - if ($this->_cpt_model_obj instanceof EE_CPT_Base) { |
|
888 | - //setup custom post status object for localize script but only if we've got a cpt object |
|
889 | - $statuses = $this->_cpt_model_obj->get_custom_post_statuses(); |
|
890 | - if ( ! empty($statuses)) { |
|
891 | - //get ALL statuses! |
|
892 | - $statuses = $this->_cpt_model_obj->get_all_post_statuses(); |
|
893 | - //setup object |
|
894 | - $ee_cpt_statuses = array(); |
|
895 | - foreach ($statuses as $status => $label) { |
|
896 | - $ee_cpt_statuses[$status] = array( |
|
897 | - 'label' => $label, |
|
898 | - 'save_label' => sprintf(__('Save as %s', 'event_espresso'), $label), |
|
899 | - ); |
|
900 | - } |
|
901 | - wp_localize_script('ee_admin_js', 'eeCPTstatuses', $ee_cpt_statuses); |
|
902 | - } |
|
903 | - } |
|
904 | - } |
|
905 | - |
|
906 | - |
|
907 | - |
|
908 | - /** |
|
909 | - * This is a wrapper for the insert/update routes for cpt items so we can add things that are common to ALL |
|
910 | - * insert/updates |
|
911 | - * |
|
912 | - * @param int $post_id ID of post being updated |
|
913 | - * @param WP_Post $post Post object from WP |
|
914 | - * @param bool $update Whether this is an update or a new save. |
|
915 | - * @return void |
|
916 | - * @throws \EE_Error |
|
917 | - */ |
|
918 | - public function insert_update($post_id, $post, $update) |
|
919 | - { |
|
920 | - //make sure that if this is a revision OR trash action that we don't do any updates! |
|
921 | - if ( |
|
922 | - isset($this->_req_data['action']) |
|
923 | - && ( |
|
924 | - $this->_req_data['action'] === 'restore' |
|
925 | - || $this->_req_data['action'] === 'trash' |
|
926 | - ) |
|
927 | - ) { |
|
928 | - return; |
|
929 | - } |
|
930 | - $this->_set_model_object($post_id, true, 'insert_update'); |
|
931 | - //if our cpt object is not instantiated and its NOT the same post_id as what is triggering this callback, then exit. |
|
932 | - if ($update |
|
933 | - && ( |
|
934 | - ! $this->_cpt_model_obj instanceof EE_CPT_Base |
|
935 | - || $this->_cpt_model_obj->ID() !== $post_id |
|
936 | - ) |
|
937 | - ) { |
|
938 | - return; |
|
939 | - } |
|
940 | - //check for autosave and update our req_data property accordingly. |
|
941 | - /*if ( defined('DOING_AUTOSAVE') && DOING_AUTOSAVE && isset( $this->_req_data['ee_autosave_data'] ) ) { |
|
498 | + } |
|
499 | + |
|
500 | + |
|
501 | + |
|
502 | + /** |
|
503 | + * if this post is a draft or scheduled post then we provide a preview button for user to click |
|
504 | + * Method is called from parent and is hooked into the wp 'get_sample_permalink_html' filter. |
|
505 | + * |
|
506 | + * @param string $return the current html |
|
507 | + * @param int $id the post id for the page |
|
508 | + * @param string $new_title What the title is |
|
509 | + * @param string $new_slug what the slug is |
|
510 | + * @return string The new html string for the permalink area |
|
511 | + */ |
|
512 | + public function preview_button_html($return, $id, $new_title, $new_slug) |
|
513 | + { |
|
514 | + $post = get_post($id); |
|
515 | + if ('publish' !== get_post_status($post)) { |
|
516 | + //include shims for the `get_preview_post_link` function |
|
517 | + require_once( EE_CORE . 'wordpress-shims.php' ); |
|
518 | + $return .= '<span_id="view-post-btn"><a target="_blank" href="' |
|
519 | + . get_preview_post_link($id) |
|
520 | + . '" class="button button-small">' |
|
521 | + . __('Preview', 'event_espresso') |
|
522 | + . '</a></span>' |
|
523 | + . "\n"; |
|
524 | + } |
|
525 | + return $return; |
|
526 | + } |
|
527 | + |
|
528 | + |
|
529 | + |
|
530 | + /** |
|
531 | + * add our custom post stati dropdown on the wp post page for this cpt |
|
532 | + * |
|
533 | + * @return void |
|
534 | + */ |
|
535 | + public function custom_post_stati_dropdown() |
|
536 | + { |
|
537 | + |
|
538 | + $statuses = $this->_cpt_model_obj->get_custom_post_statuses(); |
|
539 | + $cur_status_label = array_key_exists($this->_cpt_model_obj->status(), $statuses) |
|
540 | + ? $statuses[$this->_cpt_model_obj->status()] |
|
541 | + : ''; |
|
542 | + $template_args = array( |
|
543 | + 'cur_status' => $this->_cpt_model_obj->status(), |
|
544 | + 'statuses' => $statuses, |
|
545 | + 'cur_status_label' => $cur_status_label, |
|
546 | + 'localized_status_save' => sprintf(__('Save %s', 'event_espresso'), $cur_status_label), |
|
547 | + ); |
|
548 | + //we'll add a trash post status (WP doesn't add one for some reason) |
|
549 | + if ($this->_cpt_model_obj->status() === 'trash') { |
|
550 | + $template_args['cur_status_label'] = __('Trashed', 'event_espresso'); |
|
551 | + $statuses['trash'] = __('Trashed', 'event_espresso'); |
|
552 | + $template_args['statuses'] = $statuses; |
|
553 | + } |
|
554 | + |
|
555 | + $template = EE_ADMIN_TEMPLATE . 'status_dropdown.template.php'; |
|
556 | + EEH_Template::display_template($template, $template_args); |
|
557 | + } |
|
558 | + |
|
559 | + |
|
560 | + |
|
561 | + public function setup_autosave_hooks() |
|
562 | + { |
|
563 | + $this->_set_autosave_containers(); |
|
564 | + $this->_load_autosave_scripts_styles(); |
|
565 | + } |
|
566 | + |
|
567 | + |
|
568 | + |
|
569 | + /** |
|
570 | + * This is run on all WordPress autosaves AFTER the autosave is complete and sends along a $_POST object (available |
|
571 | + * in $this->_req_data) containing: post_ID of the saved post autosavenonce for the saved post We'll do the check |
|
572 | + * for the nonce in here, but then this method looks for two things: |
|
573 | + * 1. Execute a method (if exists) matching 'ee_autosave_' and appended with the given route. OR |
|
574 | + * 2. do_actions() for global or class specific actions that have been registered (for plugins/addons not in an |
|
575 | + * EE_Admin_Page class. PLEASE NOTE: Data will be returned using the _return_json() object and so the |
|
576 | + * $_template_args property should be used to hold the $data array. We're expecting the following things set in |
|
577 | + * template args. |
|
578 | + * 1. $template_args['error'] = IF there is an error you can add the message in here. |
|
579 | + * 2. $template_args['data']['items'] = an array of items that are setup in key index pairs of 'where_values_go' |
|
580 | + * => 'values_to_add'. In other words, for the datetime metabox we'll have something like |
|
581 | + * $this->_template_args['data']['items'] = array( |
|
582 | + * 'event-datetime-ids' => '1,2,3'; |
|
583 | + * ); |
|
584 | + * Keep in mind the following things: |
|
585 | + * - "where" index is for the input with the id as that string. |
|
586 | + * - "what" index is what will be used for the value of that input. |
|
587 | + * |
|
588 | + * @return void |
|
589 | + */ |
|
590 | + public function do_extra_autosave_stuff() |
|
591 | + { |
|
592 | + //next let's check for the autosave nonce (we'll use _verify_nonce ) |
|
593 | + $nonce = isset($this->_req_data['autosavenonce']) |
|
594 | + ? $this->_req_data['autosavenonce'] |
|
595 | + : null; |
|
596 | + $this->_verify_nonce($nonce, 'autosave'); |
|
597 | + //make sure we define doing autosave (cause WP isn't triggering this we want to make sure we define it) |
|
598 | + if ( ! defined('DOING_AUTOSAVE')) { |
|
599 | + define('DOING_AUTOSAVE', true); |
|
600 | + } |
|
601 | + //if we made it here then the nonce checked out. Let's run our methods and actions |
|
602 | + $autosave = "_ee_autosave_{$this->_current_view}"; |
|
603 | + if (method_exists($this, $autosave)) { |
|
604 | + $this->$autosave(); |
|
605 | + } else { |
|
606 | + $this->_template_args['success'] = true; |
|
607 | + } |
|
608 | + do_action('AHEE__EE_Admin_Page_CPT__do_extra_autosave_stuff__global_after', $this); |
|
609 | + do_action('AHEE__EE_Admin_Page_CPT__do_extra_autosave_stuff__after_' . get_class($this), $this); |
|
610 | + //now let's return json |
|
611 | + $this->_return_json(); |
|
612 | + } |
|
613 | + |
|
614 | + |
|
615 | + |
|
616 | + /** |
|
617 | + * This takes care of setting up default routes and pages that utilize the core WP admin pages. |
|
618 | + * Child classes can override the defaults (in cases for adding metaboxes etc.) |
|
619 | + * but take care that you include the defaults here otherwise your core WP admin pages for the cpt won't work! |
|
620 | + * |
|
621 | + * @access protected |
|
622 | + * @throws EE_Error |
|
623 | + * @return void |
|
624 | + */ |
|
625 | + protected function _extend_page_config_for_cpt() |
|
626 | + { |
|
627 | + //before doing anything we need to make sure this runs ONLY when the loaded page matches the set page_slug |
|
628 | + if (isset($this->_req_data['page']) && $this->_req_data['page'] !== $this->page_slug) { |
|
629 | + return; |
|
630 | + } |
|
631 | + //set page routes and page config but ONLY if we're not viewing a custom setup cpt route as defined in _cpt_routes |
|
632 | + if ( ! empty($this->_cpt_object)) { |
|
633 | + $this->_page_routes = array_merge(array( |
|
634 | + 'create_new' => '_create_new_cpt_item', |
|
635 | + 'edit' => '_edit_cpt_item', |
|
636 | + ), $this->_page_routes); |
|
637 | + $this->_page_config = array_merge(array( |
|
638 | + 'create_new' => array( |
|
639 | + 'nav' => array( |
|
640 | + 'label' => $this->_cpt_object->labels->add_new_item, |
|
641 | + 'order' => 5, |
|
642 | + ), |
|
643 | + 'require_nonce' => false, |
|
644 | + ), |
|
645 | + 'edit' => array( |
|
646 | + 'nav' => array( |
|
647 | + 'label' => $this->_cpt_object->labels->edit_item, |
|
648 | + 'order' => 5, |
|
649 | + 'persistent' => false, |
|
650 | + 'url' => '', |
|
651 | + ), |
|
652 | + 'require_nonce' => false, |
|
653 | + ), |
|
654 | + ), |
|
655 | + $this->_page_config |
|
656 | + ); |
|
657 | + } |
|
658 | + //load the next section only if this is a matching cpt route as set in the cpt routes array. |
|
659 | + if ( ! isset($this->_cpt_routes[$this->_req_action])) { |
|
660 | + return; |
|
661 | + } |
|
662 | + $this->_cpt_route = isset($this->_cpt_routes[$this->_req_action]) ? true : false; |
|
663 | + //add_action('FHEE__EE_Admin_Page___load_page_dependencies__after_load', array( $this, 'modify_current_screen') ); |
|
664 | + if (empty($this->_cpt_object)) { |
|
665 | + $msg = sprintf(__('This page has been set as being related to a registered custom post type, however, the custom post type object could not be retrieved. There are two possible reasons for this: 1. The "%s" does not match a registered post type. or 2. The custom post type is not registered for the "%s" action as indexed in the "$_cpt_routes" property on this class (%s).'), |
|
666 | + $this->page_slug, $this->_req_action, get_class($this)); |
|
667 | + throw new EE_Error($msg); |
|
668 | + } |
|
669 | + if ($this->_cpt_route) { |
|
670 | + $id = isset($this->_req_data['post']) ? $this->_req_data['post'] : null; |
|
671 | + $this->_set_model_object($id); |
|
672 | + } |
|
673 | + } |
|
674 | + |
|
675 | + |
|
676 | + |
|
677 | + /** |
|
678 | + * Sets the _cpt_model_object property using what has been set for the _cpt_model_name and a given id. |
|
679 | + * |
|
680 | + * @access protected |
|
681 | + * @param int $id The id to retrieve the model object for. If empty we set a default object. |
|
682 | + * @param bool $ignore_route_check |
|
683 | + * @param string $req_type whether the current route is for inserting, updating, or deleting the CPT |
|
684 | + * @throws EE_Error |
|
685 | + */ |
|
686 | + protected function _set_model_object($id = null, $ignore_route_check = false, $req_type = '') |
|
687 | + { |
|
688 | + $model = null; |
|
689 | + if ( |
|
690 | + empty($this->_cpt_model_names) |
|
691 | + || ( |
|
692 | + ! $ignore_route_check |
|
693 | + && ! isset($this->_cpt_routes[$this->_req_action]) |
|
694 | + ) || ( |
|
695 | + $this->_cpt_model_obj instanceof EE_CPT_Base |
|
696 | + && $this->_cpt_model_obj->ID() === $id |
|
697 | + ) |
|
698 | + ) { |
|
699 | + //get out cuz we either don't have a model name OR the object has already been set and it has the same id as what has been sent. |
|
700 | + return; |
|
701 | + } |
|
702 | + //if ignore_route_check is true, then get the model name via EE_Register_CPTs |
|
703 | + if ($ignore_route_check) { |
|
704 | + $model_names = EE_Register_CPTs::get_cpt_model_names(); |
|
705 | + $post_type = get_post_type($id); |
|
706 | + if (isset($model_names[$post_type])) { |
|
707 | + $model = EE_Registry::instance()->load_model($model_names[$post_type]); |
|
708 | + } |
|
709 | + } else { |
|
710 | + $model = EE_Registry::instance()->load_model($this->_cpt_model_names[$this->_req_action]); |
|
711 | + } |
|
712 | + if ($model instanceof EEM_Base) { |
|
713 | + $this->_cpt_model_obj = ! empty($id) ? $model->get_one_by_ID($id) : $model->create_default_object(); |
|
714 | + } |
|
715 | + do_action( |
|
716 | + 'AHEE__EE_Admin_Page_CPT__set_model_object__after_set_object', |
|
717 | + $this->_cpt_model_obj, |
|
718 | + $req_type |
|
719 | + ); |
|
720 | + } |
|
721 | + |
|
722 | + |
|
723 | + |
|
724 | + /** |
|
725 | + * admin_init_global |
|
726 | + * This runs all the code that we want executed within the WP admin_init hook. |
|
727 | + * This method executes for ALL EE Admin pages. |
|
728 | + * |
|
729 | + * @access public |
|
730 | + * @return void |
|
731 | + */ |
|
732 | + public function admin_init_global() |
|
733 | + { |
|
734 | + $post = isset($this->_req_data['post']) ? get_post($this->_req_data['post']) : null; |
|
735 | + //its possible this is a new save so let's catch that instead |
|
736 | + $post = isset($this->_req_data['post_ID']) ? get_post($this->_req_data['post_ID']) : $post; |
|
737 | + $post_type = $post ? $post->post_type : false; |
|
738 | + $current_route = isset($this->_req_data['current_route']) |
|
739 | + ? $this->_req_data['current_route'] |
|
740 | + : 'shouldneverwork'; |
|
741 | + $route_to_check = $post_type && isset($this->_cpt_routes[$current_route]) |
|
742 | + ? $this->_cpt_routes[$current_route] |
|
743 | + : ''; |
|
744 | + add_filter('get_delete_post_link', array($this, 'modify_delete_post_link'), 10, 3); |
|
745 | + add_filter('get_edit_post_link', array($this, 'modify_edit_post_link'), 10, 3); |
|
746 | + if ($post_type === $route_to_check) { |
|
747 | + add_filter('redirect_post_location', array($this, 'cpt_post_location_redirect'), 10, 2); |
|
748 | + } |
|
749 | + //now let's filter redirect if we're on a revision page and the revision is for an event CPT. |
|
750 | + $revision = isset($this->_req_data['revision']) ? $this->_req_data['revision'] : null; |
|
751 | + if ( ! empty($revision)) { |
|
752 | + $action = isset($this->_req_data['action']) ? $this->_req_data['action'] : null; |
|
753 | + //doing a restore? |
|
754 | + if ( ! empty($action) && $action === 'restore') { |
|
755 | + //get post for revision |
|
756 | + $rev_post = get_post($revision); |
|
757 | + $rev_parent = get_post($rev_post->post_parent); |
|
758 | + //only do our redirect filter AND our restore revision action if the post_type for the parent is one of our cpts. |
|
759 | + if ($rev_parent && $rev_parent->post_type === $this->page_slug) { |
|
760 | + add_filter('wp_redirect', array($this, 'revision_redirect'), 10, 2); |
|
761 | + //restores of revisions |
|
762 | + add_action('wp_restore_post_revision', array($this, 'restore_revision'), 10, 2); |
|
763 | + } |
|
764 | + } |
|
765 | + } |
|
766 | + //NOTE we ONLY want to run these hooks if we're on the right class for the given post type. Otherwise we could see some really freaky things happen! |
|
767 | + if ($post_type && $post_type === $route_to_check) { |
|
768 | + //$post_id, $post |
|
769 | + add_action('save_post', array($this, 'insert_update'), 10, 3); |
|
770 | + //$post_id |
|
771 | + add_action('trashed_post', array($this, 'before_trash_cpt_item'), 10); |
|
772 | + add_action('trashed_post', array($this, 'dont_permanently_delete_ee_cpts'), 10); |
|
773 | + add_action('untrashed_post', array($this, 'before_restore_cpt_item'), 10); |
|
774 | + add_action('after_delete_post', array($this, 'before_delete_cpt_item'), 10); |
|
775 | + } |
|
776 | + } |
|
777 | + |
|
778 | + |
|
779 | + |
|
780 | + /** |
|
781 | + * Callback for the WordPress trashed_post hook. |
|
782 | + * Execute some basic checks before calling the trash_cpt_item declared in the child class. |
|
783 | + * |
|
784 | + * @param int $post_id |
|
785 | + * @throws \EE_Error |
|
786 | + */ |
|
787 | + public function before_trash_cpt_item($post_id) |
|
788 | + { |
|
789 | + $this->_set_model_object($post_id, true, 'trash'); |
|
790 | + //if our cpt object isn't existent then get out immediately. |
|
791 | + if ( ! $this->_cpt_model_obj instanceof EE_CPT_Base || $this->_cpt_model_obj->ID() !== $post_id) { |
|
792 | + return; |
|
793 | + } |
|
794 | + $this->trash_cpt_item($post_id); |
|
795 | + } |
|
796 | + |
|
797 | + |
|
798 | + |
|
799 | + /** |
|
800 | + * Callback for the WordPress untrashed_post hook. |
|
801 | + * Execute some basic checks before calling the restore_cpt_method in the child class. |
|
802 | + * |
|
803 | + * @param $post_id |
|
804 | + * @throws \EE_Error |
|
805 | + */ |
|
806 | + public function before_restore_cpt_item($post_id) |
|
807 | + { |
|
808 | + $this->_set_model_object($post_id, true, 'restore'); |
|
809 | + //if our cpt object isn't existent then get out immediately. |
|
810 | + if ( ! $this->_cpt_model_obj instanceof EE_CPT_Base || $this->_cpt_model_obj->ID() !== $post_id) { |
|
811 | + return; |
|
812 | + } |
|
813 | + $this->restore_cpt_item($post_id); |
|
814 | + } |
|
815 | + |
|
816 | + |
|
817 | + |
|
818 | + /** |
|
819 | + * Callback for the WordPress after_delete_post hook. |
|
820 | + * Execute some basic checks before calling the delete_cpt_item method in the child class. |
|
821 | + * |
|
822 | + * @param $post_id |
|
823 | + * @throws \EE_Error |
|
824 | + */ |
|
825 | + public function before_delete_cpt_item($post_id) |
|
826 | + { |
|
827 | + $this->_set_model_object($post_id, true, 'delete'); |
|
828 | + //if our cpt object isn't existent then get out immediately. |
|
829 | + if ( ! $this->_cpt_model_obj instanceof EE_CPT_Base || $this->_cpt_model_obj->ID() !== $post_id) { |
|
830 | + return; |
|
831 | + } |
|
832 | + $this->delete_cpt_item($post_id); |
|
833 | + } |
|
834 | + |
|
835 | + |
|
836 | + |
|
837 | + /** |
|
838 | + * This simply verifies if the cpt_model_object is instantiated for the given page and throws an error message |
|
839 | + * accordingly. |
|
840 | + * |
|
841 | + * @access public |
|
842 | + * @throws EE_Error |
|
843 | + * @return void |
|
844 | + */ |
|
845 | + public function verify_cpt_object() |
|
846 | + { |
|
847 | + $label = ! empty($this->_cpt_object) ? $this->_cpt_object->labels->singular_name : $this->page_label; |
|
848 | + // verify event object |
|
849 | + if ( ! $this->_cpt_model_obj instanceof EE_CPT_Base) { |
|
850 | + throw new EE_Error(sprintf(__('Something has gone wrong with the page load because we are unable to set up the object for the %1$s. This usually happens when the given id for the page route is NOT for the correct custom post type for this page', |
|
851 | + 'event_espresso'), $label)); |
|
852 | + } |
|
853 | + //if auto-draft then throw an error |
|
854 | + if ($this->_cpt_model_obj->get('status') === 'auto-draft') { |
|
855 | + EE_Error::overwrite_errors(); |
|
856 | + EE_Error::add_error(sprintf(__('This %1$s was saved without a title, description, or excerpt which means that none of the extra details you added were saved properly. All autodrafts will show up in the "draft" view of your event list table. You can delete them from there. Please click the "Add %1$s" button to refresh and restart.'), |
|
857 | + $label), __FILE__, __FUNCTION__, __LINE__); |
|
858 | + } |
|
859 | + } |
|
860 | + |
|
861 | + |
|
862 | + |
|
863 | + /** |
|
864 | + * admin_footer_scripts_global |
|
865 | + * Anything triggered by the 'admin_print_footer_scripts' WP hook should be put in here. This particular method |
|
866 | + * will apply on ALL EE_Admin pages. |
|
867 | + * |
|
868 | + * @access public |
|
869 | + * @return void |
|
870 | + */ |
|
871 | + public function admin_footer_scripts_global() |
|
872 | + { |
|
873 | + $this->_add_admin_page_ajax_loading_img(); |
|
874 | + $this->_add_admin_page_overlay(); |
|
875 | + } |
|
876 | + |
|
877 | + |
|
878 | + |
|
879 | + /** |
|
880 | + * add in any global scripts for cpt routes |
|
881 | + * |
|
882 | + * @return void |
|
883 | + */ |
|
884 | + public function load_global_scripts_styles() |
|
885 | + { |
|
886 | + parent::load_global_scripts_styles(); |
|
887 | + if ($this->_cpt_model_obj instanceof EE_CPT_Base) { |
|
888 | + //setup custom post status object for localize script but only if we've got a cpt object |
|
889 | + $statuses = $this->_cpt_model_obj->get_custom_post_statuses(); |
|
890 | + if ( ! empty($statuses)) { |
|
891 | + //get ALL statuses! |
|
892 | + $statuses = $this->_cpt_model_obj->get_all_post_statuses(); |
|
893 | + //setup object |
|
894 | + $ee_cpt_statuses = array(); |
|
895 | + foreach ($statuses as $status => $label) { |
|
896 | + $ee_cpt_statuses[$status] = array( |
|
897 | + 'label' => $label, |
|
898 | + 'save_label' => sprintf(__('Save as %s', 'event_espresso'), $label), |
|
899 | + ); |
|
900 | + } |
|
901 | + wp_localize_script('ee_admin_js', 'eeCPTstatuses', $ee_cpt_statuses); |
|
902 | + } |
|
903 | + } |
|
904 | + } |
|
905 | + |
|
906 | + |
|
907 | + |
|
908 | + /** |
|
909 | + * This is a wrapper for the insert/update routes for cpt items so we can add things that are common to ALL |
|
910 | + * insert/updates |
|
911 | + * |
|
912 | + * @param int $post_id ID of post being updated |
|
913 | + * @param WP_Post $post Post object from WP |
|
914 | + * @param bool $update Whether this is an update or a new save. |
|
915 | + * @return void |
|
916 | + * @throws \EE_Error |
|
917 | + */ |
|
918 | + public function insert_update($post_id, $post, $update) |
|
919 | + { |
|
920 | + //make sure that if this is a revision OR trash action that we don't do any updates! |
|
921 | + if ( |
|
922 | + isset($this->_req_data['action']) |
|
923 | + && ( |
|
924 | + $this->_req_data['action'] === 'restore' |
|
925 | + || $this->_req_data['action'] === 'trash' |
|
926 | + ) |
|
927 | + ) { |
|
928 | + return; |
|
929 | + } |
|
930 | + $this->_set_model_object($post_id, true, 'insert_update'); |
|
931 | + //if our cpt object is not instantiated and its NOT the same post_id as what is triggering this callback, then exit. |
|
932 | + if ($update |
|
933 | + && ( |
|
934 | + ! $this->_cpt_model_obj instanceof EE_CPT_Base |
|
935 | + || $this->_cpt_model_obj->ID() !== $post_id |
|
936 | + ) |
|
937 | + ) { |
|
938 | + return; |
|
939 | + } |
|
940 | + //check for autosave and update our req_data property accordingly. |
|
941 | + /*if ( defined('DOING_AUTOSAVE') && DOING_AUTOSAVE && isset( $this->_req_data['ee_autosave_data'] ) ) { |
|
942 | 942 | foreach( (array) $this->_req_data['ee_autosave_data'] as $id => $values ) { |
943 | 943 | |
944 | 944 | foreach ( (array) $values as $key => $value ) { |
@@ -948,542 +948,542 @@ discard block |
||
948 | 948 | |
949 | 949 | }/**/ //TODO reactivate after autosave is implemented in 4.2 |
950 | 950 | |
951 | - //take care of updating any selected page_template IF this cpt supports it. |
|
952 | - if ($this->_supports_page_templates($post->post_type) && ! empty($this->_req_data['page_template'])) { |
|
953 | - //wp version aware. |
|
954 | - if (EE_Recommended_Versions::check_wp_version('4.7', '>=')) { |
|
955 | - $page_templates = wp_get_theme()->get_page_templates(); |
|
956 | - } else { |
|
957 | - $post->page_template = $this->_req_data['page_template']; |
|
958 | - $page_templates = wp_get_theme()->get_page_templates($post); |
|
959 | - } |
|
960 | - if ('default' != $this->_req_data['page_template'] && ! isset($page_templates[$this->_req_data['page_template']])) { |
|
961 | - EE_Error::add_error(__('Invalid Page Template.', 'event_espresso'), __FILE__, __FUNCTION__, __LINE__); |
|
962 | - } else { |
|
963 | - update_post_meta($post_id, '_wp_page_template', $this->_req_data['page_template']); |
|
964 | - } |
|
965 | - } |
|
966 | - if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) { |
|
967 | - return; |
|
968 | - } //TODO we'll remove this after reimplementing autosave in 4.2 |
|
969 | - $this->_insert_update_cpt_item($post_id, $post); |
|
970 | - } |
|
971 | - |
|
972 | - |
|
973 | - |
|
974 | - /** |
|
975 | - * This hooks into the wp_trash_post() function and removes the `_wp_trash_meta_status` and `_wp_trash_meta_time` |
|
976 | - * post meta IF the trashed post is one of our CPT's - note this method should only be called with our cpt routes |
|
977 | - * so we don't have to check for our CPT. |
|
978 | - * |
|
979 | - * @param int $post_id ID of the post |
|
980 | - * @return void |
|
981 | - */ |
|
982 | - public function dont_permanently_delete_ee_cpts($post_id) |
|
983 | - { |
|
984 | - //only do this if we're actually processing one of our CPTs |
|
985 | - //if our cpt object isn't existent then get out immediately. |
|
986 | - if ( ! $this->_cpt_model_obj instanceof EE_CPT_Base) { |
|
987 | - return; |
|
988 | - } |
|
989 | - delete_post_meta($post_id, '_wp_trash_meta_status'); |
|
990 | - delete_post_meta($post_id, '_wp_trash_meta_time'); |
|
991 | - //our cpts may have comments so let's take care of that too |
|
992 | - delete_post_meta($post_id, '_wp_trash_meta_comments_status'); |
|
993 | - } |
|
994 | - |
|
995 | - |
|
996 | - |
|
997 | - /** |
|
998 | - * This is a wrapper for the restore_cpt_revision route for cpt items so we can make sure that when a revision is |
|
999 | - * triggered that we restore related items. In order to work cpt classes MUST have a restore_cpt_revision method |
|
1000 | - * in them. We also have our OWN action in here so addons can hook into the restore process easily. |
|
1001 | - * |
|
1002 | - * @param int $post_id ID of cpt item |
|
1003 | - * @param int $revision_id ID of revision being restored |
|
1004 | - * @return void |
|
1005 | - */ |
|
1006 | - public function restore_revision($post_id, $revision_id) |
|
1007 | - { |
|
1008 | - $this->_restore_cpt_item($post_id, $revision_id); |
|
1009 | - //global action |
|
1010 | - do_action('AHEE_EE_Admin_Page_CPT__restore_revision', $post_id, $revision_id); |
|
1011 | - //class specific action so you can limit hooking into a specific page. |
|
1012 | - do_action('AHEE_EE_Admin_Page_CPT_' . get_class($this) . '__restore_revision', $post_id, $revision_id); |
|
1013 | - } |
|
1014 | - |
|
1015 | - |
|
1016 | - |
|
1017 | - /** |
|
1018 | - * @see restore_revision() for details |
|
1019 | - * @param int $post_id ID of cpt item |
|
1020 | - * @param int $revision_id ID of revision for item |
|
1021 | - * @return void |
|
1022 | - */ |
|
1023 | - abstract protected function _restore_cpt_item($post_id, $revision_id); |
|
1024 | - |
|
1025 | - |
|
1026 | - |
|
1027 | - /** |
|
1028 | - * Execution of this method is added to the end of the load_page_dependencies method in the parent |
|
1029 | - * so that we can fix a bug where default core metaboxes were not being called in the sidebar. |
|
1030 | - * To fix we have to reset the current_screen using the page_slug |
|
1031 | - * (which is identical - or should be - to our registered_post_type id.) |
|
1032 | - * Also, since the core WP file loads the admin_header.php for WP |
|
1033 | - * (and there are a bunch of other things edit-form-advanced.php loads that need to happen really early) |
|
1034 | - * we need to load it NOW, hence our _route_admin_request in here. (Otherwise screen options won't be set). |
|
1035 | - * |
|
1036 | - * @return void |
|
1037 | - */ |
|
1038 | - public function modify_current_screen() |
|
1039 | - { |
|
1040 | - //ONLY do this if the current page_route IS a cpt route |
|
1041 | - if ( ! $this->_cpt_route) { |
|
1042 | - return; |
|
1043 | - } |
|
1044 | - //routing things REALLY early b/c this is a cpt admin page |
|
1045 | - set_current_screen($this->_cpt_routes[$this->_req_action]); |
|
1046 | - $this->_current_screen = get_current_screen(); |
|
1047 | - $this->_current_screen->base = 'event-espresso'; |
|
1048 | - $this->_add_help_tabs(); //we make sure we add any help tabs back in! |
|
1049 | - /*try { |
|
951 | + //take care of updating any selected page_template IF this cpt supports it. |
|
952 | + if ($this->_supports_page_templates($post->post_type) && ! empty($this->_req_data['page_template'])) { |
|
953 | + //wp version aware. |
|
954 | + if (EE_Recommended_Versions::check_wp_version('4.7', '>=')) { |
|
955 | + $page_templates = wp_get_theme()->get_page_templates(); |
|
956 | + } else { |
|
957 | + $post->page_template = $this->_req_data['page_template']; |
|
958 | + $page_templates = wp_get_theme()->get_page_templates($post); |
|
959 | + } |
|
960 | + if ('default' != $this->_req_data['page_template'] && ! isset($page_templates[$this->_req_data['page_template']])) { |
|
961 | + EE_Error::add_error(__('Invalid Page Template.', 'event_espresso'), __FILE__, __FUNCTION__, __LINE__); |
|
962 | + } else { |
|
963 | + update_post_meta($post_id, '_wp_page_template', $this->_req_data['page_template']); |
|
964 | + } |
|
965 | + } |
|
966 | + if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) { |
|
967 | + return; |
|
968 | + } //TODO we'll remove this after reimplementing autosave in 4.2 |
|
969 | + $this->_insert_update_cpt_item($post_id, $post); |
|
970 | + } |
|
971 | + |
|
972 | + |
|
973 | + |
|
974 | + /** |
|
975 | + * This hooks into the wp_trash_post() function and removes the `_wp_trash_meta_status` and `_wp_trash_meta_time` |
|
976 | + * post meta IF the trashed post is one of our CPT's - note this method should only be called with our cpt routes |
|
977 | + * so we don't have to check for our CPT. |
|
978 | + * |
|
979 | + * @param int $post_id ID of the post |
|
980 | + * @return void |
|
981 | + */ |
|
982 | + public function dont_permanently_delete_ee_cpts($post_id) |
|
983 | + { |
|
984 | + //only do this if we're actually processing one of our CPTs |
|
985 | + //if our cpt object isn't existent then get out immediately. |
|
986 | + if ( ! $this->_cpt_model_obj instanceof EE_CPT_Base) { |
|
987 | + return; |
|
988 | + } |
|
989 | + delete_post_meta($post_id, '_wp_trash_meta_status'); |
|
990 | + delete_post_meta($post_id, '_wp_trash_meta_time'); |
|
991 | + //our cpts may have comments so let's take care of that too |
|
992 | + delete_post_meta($post_id, '_wp_trash_meta_comments_status'); |
|
993 | + } |
|
994 | + |
|
995 | + |
|
996 | + |
|
997 | + /** |
|
998 | + * This is a wrapper for the restore_cpt_revision route for cpt items so we can make sure that when a revision is |
|
999 | + * triggered that we restore related items. In order to work cpt classes MUST have a restore_cpt_revision method |
|
1000 | + * in them. We also have our OWN action in here so addons can hook into the restore process easily. |
|
1001 | + * |
|
1002 | + * @param int $post_id ID of cpt item |
|
1003 | + * @param int $revision_id ID of revision being restored |
|
1004 | + * @return void |
|
1005 | + */ |
|
1006 | + public function restore_revision($post_id, $revision_id) |
|
1007 | + { |
|
1008 | + $this->_restore_cpt_item($post_id, $revision_id); |
|
1009 | + //global action |
|
1010 | + do_action('AHEE_EE_Admin_Page_CPT__restore_revision', $post_id, $revision_id); |
|
1011 | + //class specific action so you can limit hooking into a specific page. |
|
1012 | + do_action('AHEE_EE_Admin_Page_CPT_' . get_class($this) . '__restore_revision', $post_id, $revision_id); |
|
1013 | + } |
|
1014 | + |
|
1015 | + |
|
1016 | + |
|
1017 | + /** |
|
1018 | + * @see restore_revision() for details |
|
1019 | + * @param int $post_id ID of cpt item |
|
1020 | + * @param int $revision_id ID of revision for item |
|
1021 | + * @return void |
|
1022 | + */ |
|
1023 | + abstract protected function _restore_cpt_item($post_id, $revision_id); |
|
1024 | + |
|
1025 | + |
|
1026 | + |
|
1027 | + /** |
|
1028 | + * Execution of this method is added to the end of the load_page_dependencies method in the parent |
|
1029 | + * so that we can fix a bug where default core metaboxes were not being called in the sidebar. |
|
1030 | + * To fix we have to reset the current_screen using the page_slug |
|
1031 | + * (which is identical - or should be - to our registered_post_type id.) |
|
1032 | + * Also, since the core WP file loads the admin_header.php for WP |
|
1033 | + * (and there are a bunch of other things edit-form-advanced.php loads that need to happen really early) |
|
1034 | + * we need to load it NOW, hence our _route_admin_request in here. (Otherwise screen options won't be set). |
|
1035 | + * |
|
1036 | + * @return void |
|
1037 | + */ |
|
1038 | + public function modify_current_screen() |
|
1039 | + { |
|
1040 | + //ONLY do this if the current page_route IS a cpt route |
|
1041 | + if ( ! $this->_cpt_route) { |
|
1042 | + return; |
|
1043 | + } |
|
1044 | + //routing things REALLY early b/c this is a cpt admin page |
|
1045 | + set_current_screen($this->_cpt_routes[$this->_req_action]); |
|
1046 | + $this->_current_screen = get_current_screen(); |
|
1047 | + $this->_current_screen->base = 'event-espresso'; |
|
1048 | + $this->_add_help_tabs(); //we make sure we add any help tabs back in! |
|
1049 | + /*try { |
|
1050 | 1050 | $this->_route_admin_request(); |
1051 | 1051 | } catch ( EE_Error $e ) { |
1052 | 1052 | $e->get_error(); |
1053 | 1053 | }/**/ |
1054 | - } |
|
1055 | - |
|
1056 | - |
|
1057 | - |
|
1058 | - /** |
|
1059 | - * This allows child classes to modify the default editor title that appears when people add a new or edit an |
|
1060 | - * existing CPT item. * This uses the _labels property set by the child class via _define_page_props. Just make |
|
1061 | - * sure you have a key in _labels property that equals 'editor_title' and the value can be whatever you want the |
|
1062 | - * default to be. |
|
1063 | - * |
|
1064 | - * @param string $title The new title (or existing if there is no editor_title defined) |
|
1065 | - * @return string |
|
1066 | - */ |
|
1067 | - public function add_custom_editor_default_title($title) |
|
1068 | - { |
|
1069 | - return isset($this->_labels['editor_title'][$this->_cpt_routes[$this->_req_action]]) |
|
1070 | - ? $this->_labels['editor_title'][$this->_cpt_routes[$this->_req_action]] |
|
1071 | - : $title; |
|
1072 | - } |
|
1073 | - |
|
1074 | - |
|
1075 | - |
|
1076 | - /** |
|
1077 | - * hooks into the wp_get_shortlink button and makes sure that the shortlink gets generated |
|
1078 | - * |
|
1079 | - * @param string $shortlink The already generated shortlink |
|
1080 | - * @param int $id Post ID for this item |
|
1081 | - * @param string $context The context for the link |
|
1082 | - * @param bool $allow_slugs Whether to allow post slugs in the shortlink. |
|
1083 | - * @return string |
|
1084 | - */ |
|
1085 | - public function add_shortlink_button_to_editor($shortlink, $id, $context, $allow_slugs) |
|
1086 | - { |
|
1087 | - if ( ! empty($id) && get_option('permalink_structure') !== '') { |
|
1088 | - $post = get_post($id); |
|
1089 | - if (isset($post->post_type) && $this->page_slug === $post->post_type) { |
|
1090 | - $shortlink = home_url('?p=' . $post->ID); |
|
1091 | - } |
|
1092 | - } |
|
1093 | - return $shortlink; |
|
1094 | - } |
|
1095 | - |
|
1096 | - |
|
1097 | - |
|
1098 | - /** |
|
1099 | - * overriding the parent route_admin_request method so we DON'T run the route twice on cpt core page loads (it's |
|
1100 | - * already run in modify_current_screen()) |
|
1101 | - * |
|
1102 | - * @return void |
|
1103 | - */ |
|
1104 | - public function route_admin_request() |
|
1105 | - { |
|
1106 | - if ($this->_cpt_route) { |
|
1107 | - return; |
|
1108 | - } |
|
1109 | - try { |
|
1110 | - $this->_route_admin_request(); |
|
1111 | - } catch (EE_Error $e) { |
|
1112 | - $e->get_error(); |
|
1113 | - } |
|
1114 | - } |
|
1115 | - |
|
1116 | - |
|
1117 | - |
|
1118 | - /** |
|
1119 | - * Add a hidden form input to cpt core pages so that we know to do redirects to our routes on saves |
|
1120 | - * |
|
1121 | - * @return void |
|
1122 | - */ |
|
1123 | - public function cpt_post_form_hidden_input() |
|
1124 | - { |
|
1125 | - echo '<input type="hidden" name="ee_cpt_item_redirect_url" value="' . $this->_admin_base_url . '" />'; |
|
1126 | - //we're also going to add the route value and the current page so we can direct autosave parsing correctly |
|
1127 | - echo '<div id="ee-cpt-hidden-inputs">'; |
|
1128 | - echo '<input type="hidden" id="current_route" name="current_route" value="' . $this->_current_view . '" />'; |
|
1129 | - echo '<input type="hidden" id="current_page" name="current_page" value="' . $this->page_slug . '" />'; |
|
1130 | - echo '</div>'; |
|
1131 | - } |
|
1132 | - |
|
1133 | - |
|
1134 | - |
|
1135 | - /** |
|
1136 | - * This allows us to redirect the location of revision restores when they happen so it goes to our CPT routes. |
|
1137 | - * |
|
1138 | - * @param string $location Original location url |
|
1139 | - * @param int $status Status for http header |
|
1140 | - * @return string new (or original) url to redirect to. |
|
1141 | - */ |
|
1142 | - public function revision_redirect($location, $status) |
|
1143 | - { |
|
1144 | - //get revision |
|
1145 | - $rev_id = isset($this->_req_data['revision']) ? $this->_req_data['revision'] : null; |
|
1146 | - //can't do anything without revision so let's get out if not present |
|
1147 | - if (empty($rev_id)) { |
|
1148 | - return $location; |
|
1149 | - } |
|
1150 | - //get rev_post_data |
|
1151 | - $rev = get_post($rev_id); |
|
1152 | - $admin_url = $this->_admin_base_url; |
|
1153 | - $query_args = array( |
|
1154 | - 'action' => 'edit', |
|
1155 | - 'post' => $rev->post_parent, |
|
1156 | - 'revision' => $rev_id, |
|
1157 | - 'message' => 5, |
|
1158 | - ); |
|
1159 | - $this->_process_notices($query_args, true); |
|
1160 | - return self::add_query_args_and_nonce($query_args, $admin_url); |
|
1161 | - } |
|
1162 | - |
|
1163 | - |
|
1164 | - |
|
1165 | - /** |
|
1166 | - * Modify the edit post link generated by wp core function so that EE CPTs get setup differently. |
|
1167 | - * |
|
1168 | - * @param string $link the original generated link |
|
1169 | - * @param int $id post id |
|
1170 | - * @param string $context optional, defaults to display. How to write the '&' |
|
1171 | - * @return string the link |
|
1172 | - */ |
|
1173 | - public function modify_edit_post_link($link, $id, $context) |
|
1174 | - { |
|
1175 | - $post = get_post($id); |
|
1176 | - if ( ! isset($this->_req_data['action']) |
|
1177 | - || ! isset($this->_cpt_routes[$this->_req_data['action']]) |
|
1178 | - || $post->post_type !== $this->_cpt_routes[$this->_req_data['action']] |
|
1179 | - ) { |
|
1180 | - return $link; |
|
1181 | - } |
|
1182 | - $query_args = array( |
|
1183 | - 'action' => isset($this->_cpt_edit_routes[$post->post_type]) |
|
1184 | - ? $this->_cpt_edit_routes[$post->post_type] |
|
1185 | - : 'edit', |
|
1186 | - 'post' => $id, |
|
1187 | - ); |
|
1188 | - return self::add_query_args_and_nonce($query_args, $this->_admin_base_url); |
|
1189 | - } |
|
1190 | - |
|
1191 | - |
|
1192 | - /** |
|
1193 | - * Modify the trash link on our cpt edit pages so it has the required query var for triggering redirect properly on |
|
1194 | - * our routes. |
|
1195 | - * |
|
1196 | - * @param string $delete_link original delete link |
|
1197 | - * @param int $post_id id of cpt object |
|
1198 | - * @param bool $force_delete whether this is forcing a hard delete instead of trash |
|
1199 | - * @return string new delete link |
|
1200 | - * @throws EE_Error |
|
1201 | - */ |
|
1202 | - public function modify_delete_post_link($delete_link, $post_id, $force_delete) |
|
1203 | - { |
|
1204 | - $post = get_post($post_id); |
|
1205 | - |
|
1206 | - if (empty($this->_req_data['action']) |
|
1207 | - || ! isset($this->_cpt_routes[$this->_req_data['action']]) |
|
1208 | - || ! $post instanceof WP_Post |
|
1209 | - || $post->post_type !== $this->_cpt_routes[$this->_req_data['action']] |
|
1210 | - ) { |
|
1211 | - return $delete_link; |
|
1212 | - } |
|
1213 | - $this->_set_model_object($post->ID, true); |
|
1214 | - |
|
1215 | - //returns something like `trash_event` or `trash_attendee` or `trash_venue` |
|
1216 | - $action = 'trash_' . str_replace('ee_', '', strtolower(get_class($this->_cpt_model_obj))); |
|
1217 | - |
|
1218 | - return EE_Admin_Page::add_query_args_and_nonce( |
|
1219 | - array( |
|
1220 | - 'page' => $this->_req_data['page'], |
|
1221 | - 'action' => $action, |
|
1222 | - $this->_cpt_model_obj->get_model()->get_primary_key_field()->get_name() |
|
1223 | - => $post->ID |
|
1224 | - ), |
|
1225 | - admin_url() |
|
1226 | - ); |
|
1227 | - } |
|
1228 | - |
|
1229 | - |
|
1230 | - |
|
1231 | - /** |
|
1232 | - * This is the callback for the 'redirect_post_location' filter in wp-admin/post.php |
|
1233 | - * so that we can hijack the default redirect locations for wp custom post types |
|
1234 | - * that WE'RE using and send back to OUR routes. This should only be hooked in on the right route. |
|
1235 | - * |
|
1236 | - * @param string $location This is the incoming currently set redirect location |
|
1237 | - * @param string $post_id This is the 'ID' value of the wp_posts table |
|
1238 | - * @return string the new location to redirect to |
|
1239 | - */ |
|
1240 | - public function cpt_post_location_redirect($location, $post_id) |
|
1241 | - { |
|
1242 | - //we DO have a match so let's setup the url |
|
1243 | - //we have to get the post to determine our route |
|
1244 | - $post = get_post($post_id); |
|
1245 | - $edit_route = $this->_cpt_edit_routes[$post->post_type]; |
|
1246 | - //shared query_args |
|
1247 | - $query_args = array('action' => $edit_route, 'post' => $post_id); |
|
1248 | - $admin_url = $this->_admin_base_url; |
|
1249 | - if (isset($this->_req_data['save']) || isset($this->_req_data['publish'])) { |
|
1250 | - $status = get_post_status($post_id); |
|
1251 | - if (isset($this->_req_data['publish'])) { |
|
1252 | - switch ($status) { |
|
1253 | - case 'pending': |
|
1254 | - $message = 8; |
|
1255 | - break; |
|
1256 | - case 'future': |
|
1257 | - $message = 9; |
|
1258 | - break; |
|
1259 | - default: |
|
1260 | - $message = 6; |
|
1261 | - } |
|
1262 | - } else { |
|
1263 | - $message = 'draft' === $status ? 10 : 1; |
|
1264 | - } |
|
1265 | - } else if (isset($this->_req_data['addmeta']) && $this->_req_data['addmeta']) { |
|
1266 | - $message = 2; |
|
1267 | - // $append = '#postcustom'; |
|
1268 | - } else if (isset($this->_req_data['deletemeta']) && $this->_req_data['deletemeta']) { |
|
1269 | - $message = 3; |
|
1270 | - // $append = '#postcustom'; |
|
1271 | - } elseif ($this->_req_data['action'] === 'post-quickpress-save-cont') { |
|
1272 | - $message = 7; |
|
1273 | - } else { |
|
1274 | - $message = 4; |
|
1275 | - } |
|
1276 | - //change the message if the post type is not viewable on the frontend |
|
1277 | - $this->_cpt_object = get_post_type_object($post->post_type); |
|
1278 | - $message = $message === 1 && ! $this->_cpt_object->publicly_queryable ? 4 : $message; |
|
1279 | - $query_args = array_merge(array('message' => $message), $query_args); |
|
1280 | - $this->_process_notices($query_args, true); |
|
1281 | - return self::add_query_args_and_nonce($query_args, $admin_url); |
|
1282 | - } |
|
1283 | - |
|
1284 | - |
|
1285 | - |
|
1286 | - /** |
|
1287 | - * This method is called to inject nav tabs on core WP cpt pages |
|
1288 | - * |
|
1289 | - * @access public |
|
1290 | - * @return void |
|
1291 | - */ |
|
1292 | - public function inject_nav_tabs() |
|
1293 | - { |
|
1294 | - //can we hijack and insert the nav_tabs? |
|
1295 | - $nav_tabs = $this->_get_main_nav_tabs(); |
|
1296 | - //first close off existing form tag |
|
1297 | - $html = '>'; |
|
1298 | - $html .= $nav_tabs; |
|
1299 | - //now let's handle the remaining tag ( missing ">" is CORRECT ) |
|
1300 | - $html .= '<span></span'; |
|
1301 | - echo $html; |
|
1302 | - } |
|
1303 | - |
|
1304 | - |
|
1305 | - |
|
1306 | - /** |
|
1307 | - * This just sets up the post update messages when an update form is loaded |
|
1308 | - * |
|
1309 | - * @access public |
|
1310 | - * @param array $messages the original messages array |
|
1311 | - * @return array the new messages array |
|
1312 | - */ |
|
1313 | - public function post_update_messages($messages) |
|
1314 | - { |
|
1315 | - global $post; |
|
1316 | - $id = isset($this->_req_data['post']) ? $this->_req_data['post'] : null; |
|
1317 | - $id = empty($id) && is_object($post) ? $post->ID : null; |
|
1318 | - // $post_type = $post ? $post->post_type : false; |
|
1319 | - /*$current_route = isset($this->_req_data['current_route']) ? $this->_req_data['current_route'] : 'shouldneverwork'; |
|
1054 | + } |
|
1055 | + |
|
1056 | + |
|
1057 | + |
|
1058 | + /** |
|
1059 | + * This allows child classes to modify the default editor title that appears when people add a new or edit an |
|
1060 | + * existing CPT item. * This uses the _labels property set by the child class via _define_page_props. Just make |
|
1061 | + * sure you have a key in _labels property that equals 'editor_title' and the value can be whatever you want the |
|
1062 | + * default to be. |
|
1063 | + * |
|
1064 | + * @param string $title The new title (or existing if there is no editor_title defined) |
|
1065 | + * @return string |
|
1066 | + */ |
|
1067 | + public function add_custom_editor_default_title($title) |
|
1068 | + { |
|
1069 | + return isset($this->_labels['editor_title'][$this->_cpt_routes[$this->_req_action]]) |
|
1070 | + ? $this->_labels['editor_title'][$this->_cpt_routes[$this->_req_action]] |
|
1071 | + : $title; |
|
1072 | + } |
|
1073 | + |
|
1074 | + |
|
1075 | + |
|
1076 | + /** |
|
1077 | + * hooks into the wp_get_shortlink button and makes sure that the shortlink gets generated |
|
1078 | + * |
|
1079 | + * @param string $shortlink The already generated shortlink |
|
1080 | + * @param int $id Post ID for this item |
|
1081 | + * @param string $context The context for the link |
|
1082 | + * @param bool $allow_slugs Whether to allow post slugs in the shortlink. |
|
1083 | + * @return string |
|
1084 | + */ |
|
1085 | + public function add_shortlink_button_to_editor($shortlink, $id, $context, $allow_slugs) |
|
1086 | + { |
|
1087 | + if ( ! empty($id) && get_option('permalink_structure') !== '') { |
|
1088 | + $post = get_post($id); |
|
1089 | + if (isset($post->post_type) && $this->page_slug === $post->post_type) { |
|
1090 | + $shortlink = home_url('?p=' . $post->ID); |
|
1091 | + } |
|
1092 | + } |
|
1093 | + return $shortlink; |
|
1094 | + } |
|
1095 | + |
|
1096 | + |
|
1097 | + |
|
1098 | + /** |
|
1099 | + * overriding the parent route_admin_request method so we DON'T run the route twice on cpt core page loads (it's |
|
1100 | + * already run in modify_current_screen()) |
|
1101 | + * |
|
1102 | + * @return void |
|
1103 | + */ |
|
1104 | + public function route_admin_request() |
|
1105 | + { |
|
1106 | + if ($this->_cpt_route) { |
|
1107 | + return; |
|
1108 | + } |
|
1109 | + try { |
|
1110 | + $this->_route_admin_request(); |
|
1111 | + } catch (EE_Error $e) { |
|
1112 | + $e->get_error(); |
|
1113 | + } |
|
1114 | + } |
|
1115 | + |
|
1116 | + |
|
1117 | + |
|
1118 | + /** |
|
1119 | + * Add a hidden form input to cpt core pages so that we know to do redirects to our routes on saves |
|
1120 | + * |
|
1121 | + * @return void |
|
1122 | + */ |
|
1123 | + public function cpt_post_form_hidden_input() |
|
1124 | + { |
|
1125 | + echo '<input type="hidden" name="ee_cpt_item_redirect_url" value="' . $this->_admin_base_url . '" />'; |
|
1126 | + //we're also going to add the route value and the current page so we can direct autosave parsing correctly |
|
1127 | + echo '<div id="ee-cpt-hidden-inputs">'; |
|
1128 | + echo '<input type="hidden" id="current_route" name="current_route" value="' . $this->_current_view . '" />'; |
|
1129 | + echo '<input type="hidden" id="current_page" name="current_page" value="' . $this->page_slug . '" />'; |
|
1130 | + echo '</div>'; |
|
1131 | + } |
|
1132 | + |
|
1133 | + |
|
1134 | + |
|
1135 | + /** |
|
1136 | + * This allows us to redirect the location of revision restores when they happen so it goes to our CPT routes. |
|
1137 | + * |
|
1138 | + * @param string $location Original location url |
|
1139 | + * @param int $status Status for http header |
|
1140 | + * @return string new (or original) url to redirect to. |
|
1141 | + */ |
|
1142 | + public function revision_redirect($location, $status) |
|
1143 | + { |
|
1144 | + //get revision |
|
1145 | + $rev_id = isset($this->_req_data['revision']) ? $this->_req_data['revision'] : null; |
|
1146 | + //can't do anything without revision so let's get out if not present |
|
1147 | + if (empty($rev_id)) { |
|
1148 | + return $location; |
|
1149 | + } |
|
1150 | + //get rev_post_data |
|
1151 | + $rev = get_post($rev_id); |
|
1152 | + $admin_url = $this->_admin_base_url; |
|
1153 | + $query_args = array( |
|
1154 | + 'action' => 'edit', |
|
1155 | + 'post' => $rev->post_parent, |
|
1156 | + 'revision' => $rev_id, |
|
1157 | + 'message' => 5, |
|
1158 | + ); |
|
1159 | + $this->_process_notices($query_args, true); |
|
1160 | + return self::add_query_args_and_nonce($query_args, $admin_url); |
|
1161 | + } |
|
1162 | + |
|
1163 | + |
|
1164 | + |
|
1165 | + /** |
|
1166 | + * Modify the edit post link generated by wp core function so that EE CPTs get setup differently. |
|
1167 | + * |
|
1168 | + * @param string $link the original generated link |
|
1169 | + * @param int $id post id |
|
1170 | + * @param string $context optional, defaults to display. How to write the '&' |
|
1171 | + * @return string the link |
|
1172 | + */ |
|
1173 | + public function modify_edit_post_link($link, $id, $context) |
|
1174 | + { |
|
1175 | + $post = get_post($id); |
|
1176 | + if ( ! isset($this->_req_data['action']) |
|
1177 | + || ! isset($this->_cpt_routes[$this->_req_data['action']]) |
|
1178 | + || $post->post_type !== $this->_cpt_routes[$this->_req_data['action']] |
|
1179 | + ) { |
|
1180 | + return $link; |
|
1181 | + } |
|
1182 | + $query_args = array( |
|
1183 | + 'action' => isset($this->_cpt_edit_routes[$post->post_type]) |
|
1184 | + ? $this->_cpt_edit_routes[$post->post_type] |
|
1185 | + : 'edit', |
|
1186 | + 'post' => $id, |
|
1187 | + ); |
|
1188 | + return self::add_query_args_and_nonce($query_args, $this->_admin_base_url); |
|
1189 | + } |
|
1190 | + |
|
1191 | + |
|
1192 | + /** |
|
1193 | + * Modify the trash link on our cpt edit pages so it has the required query var for triggering redirect properly on |
|
1194 | + * our routes. |
|
1195 | + * |
|
1196 | + * @param string $delete_link original delete link |
|
1197 | + * @param int $post_id id of cpt object |
|
1198 | + * @param bool $force_delete whether this is forcing a hard delete instead of trash |
|
1199 | + * @return string new delete link |
|
1200 | + * @throws EE_Error |
|
1201 | + */ |
|
1202 | + public function modify_delete_post_link($delete_link, $post_id, $force_delete) |
|
1203 | + { |
|
1204 | + $post = get_post($post_id); |
|
1205 | + |
|
1206 | + if (empty($this->_req_data['action']) |
|
1207 | + || ! isset($this->_cpt_routes[$this->_req_data['action']]) |
|
1208 | + || ! $post instanceof WP_Post |
|
1209 | + || $post->post_type !== $this->_cpt_routes[$this->_req_data['action']] |
|
1210 | + ) { |
|
1211 | + return $delete_link; |
|
1212 | + } |
|
1213 | + $this->_set_model_object($post->ID, true); |
|
1214 | + |
|
1215 | + //returns something like `trash_event` or `trash_attendee` or `trash_venue` |
|
1216 | + $action = 'trash_' . str_replace('ee_', '', strtolower(get_class($this->_cpt_model_obj))); |
|
1217 | + |
|
1218 | + return EE_Admin_Page::add_query_args_and_nonce( |
|
1219 | + array( |
|
1220 | + 'page' => $this->_req_data['page'], |
|
1221 | + 'action' => $action, |
|
1222 | + $this->_cpt_model_obj->get_model()->get_primary_key_field()->get_name() |
|
1223 | + => $post->ID |
|
1224 | + ), |
|
1225 | + admin_url() |
|
1226 | + ); |
|
1227 | + } |
|
1228 | + |
|
1229 | + |
|
1230 | + |
|
1231 | + /** |
|
1232 | + * This is the callback for the 'redirect_post_location' filter in wp-admin/post.php |
|
1233 | + * so that we can hijack the default redirect locations for wp custom post types |
|
1234 | + * that WE'RE using and send back to OUR routes. This should only be hooked in on the right route. |
|
1235 | + * |
|
1236 | + * @param string $location This is the incoming currently set redirect location |
|
1237 | + * @param string $post_id This is the 'ID' value of the wp_posts table |
|
1238 | + * @return string the new location to redirect to |
|
1239 | + */ |
|
1240 | + public function cpt_post_location_redirect($location, $post_id) |
|
1241 | + { |
|
1242 | + //we DO have a match so let's setup the url |
|
1243 | + //we have to get the post to determine our route |
|
1244 | + $post = get_post($post_id); |
|
1245 | + $edit_route = $this->_cpt_edit_routes[$post->post_type]; |
|
1246 | + //shared query_args |
|
1247 | + $query_args = array('action' => $edit_route, 'post' => $post_id); |
|
1248 | + $admin_url = $this->_admin_base_url; |
|
1249 | + if (isset($this->_req_data['save']) || isset($this->_req_data['publish'])) { |
|
1250 | + $status = get_post_status($post_id); |
|
1251 | + if (isset($this->_req_data['publish'])) { |
|
1252 | + switch ($status) { |
|
1253 | + case 'pending': |
|
1254 | + $message = 8; |
|
1255 | + break; |
|
1256 | + case 'future': |
|
1257 | + $message = 9; |
|
1258 | + break; |
|
1259 | + default: |
|
1260 | + $message = 6; |
|
1261 | + } |
|
1262 | + } else { |
|
1263 | + $message = 'draft' === $status ? 10 : 1; |
|
1264 | + } |
|
1265 | + } else if (isset($this->_req_data['addmeta']) && $this->_req_data['addmeta']) { |
|
1266 | + $message = 2; |
|
1267 | + // $append = '#postcustom'; |
|
1268 | + } else if (isset($this->_req_data['deletemeta']) && $this->_req_data['deletemeta']) { |
|
1269 | + $message = 3; |
|
1270 | + // $append = '#postcustom'; |
|
1271 | + } elseif ($this->_req_data['action'] === 'post-quickpress-save-cont') { |
|
1272 | + $message = 7; |
|
1273 | + } else { |
|
1274 | + $message = 4; |
|
1275 | + } |
|
1276 | + //change the message if the post type is not viewable on the frontend |
|
1277 | + $this->_cpt_object = get_post_type_object($post->post_type); |
|
1278 | + $message = $message === 1 && ! $this->_cpt_object->publicly_queryable ? 4 : $message; |
|
1279 | + $query_args = array_merge(array('message' => $message), $query_args); |
|
1280 | + $this->_process_notices($query_args, true); |
|
1281 | + return self::add_query_args_and_nonce($query_args, $admin_url); |
|
1282 | + } |
|
1283 | + |
|
1284 | + |
|
1285 | + |
|
1286 | + /** |
|
1287 | + * This method is called to inject nav tabs on core WP cpt pages |
|
1288 | + * |
|
1289 | + * @access public |
|
1290 | + * @return void |
|
1291 | + */ |
|
1292 | + public function inject_nav_tabs() |
|
1293 | + { |
|
1294 | + //can we hijack and insert the nav_tabs? |
|
1295 | + $nav_tabs = $this->_get_main_nav_tabs(); |
|
1296 | + //first close off existing form tag |
|
1297 | + $html = '>'; |
|
1298 | + $html .= $nav_tabs; |
|
1299 | + //now let's handle the remaining tag ( missing ">" is CORRECT ) |
|
1300 | + $html .= '<span></span'; |
|
1301 | + echo $html; |
|
1302 | + } |
|
1303 | + |
|
1304 | + |
|
1305 | + |
|
1306 | + /** |
|
1307 | + * This just sets up the post update messages when an update form is loaded |
|
1308 | + * |
|
1309 | + * @access public |
|
1310 | + * @param array $messages the original messages array |
|
1311 | + * @return array the new messages array |
|
1312 | + */ |
|
1313 | + public function post_update_messages($messages) |
|
1314 | + { |
|
1315 | + global $post; |
|
1316 | + $id = isset($this->_req_data['post']) ? $this->_req_data['post'] : null; |
|
1317 | + $id = empty($id) && is_object($post) ? $post->ID : null; |
|
1318 | + // $post_type = $post ? $post->post_type : false; |
|
1319 | + /*$current_route = isset($this->_req_data['current_route']) ? $this->_req_data['current_route'] : 'shouldneverwork'; |
|
1320 | 1320 | |
1321 | 1321 | $route_to_check = $post_type && isset( $this->_cpt_routes[$current_route]) ? $this->_cpt_routes[$current_route] : '';/**/ |
1322 | - $messages[$post->post_type] = array( |
|
1323 | - 0 => '', //Unused. Messages start at index 1. |
|
1324 | - 1 => sprintf( |
|
1325 | - __('%1$s updated. %2$sView %1$s%3$s', 'event_espresso'), |
|
1326 | - $this->_cpt_object->labels->singular_name, |
|
1327 | - '<a href="' . esc_url(get_permalink($id)) . '">', |
|
1328 | - '</a>' |
|
1329 | - ), |
|
1330 | - 2 => __('Custom field updated'), |
|
1331 | - 3 => __('Custom field deleted.'), |
|
1332 | - 4 => sprintf(__('%1$s updated.', 'event_espresso'), $this->_cpt_object->labels->singular_name), |
|
1333 | - 5 => isset($_GET['revision']) ? sprintf(__('%s restored to revision from %s', 'event_espresso'), |
|
1334 | - $this->_cpt_object->labels->singular_name, wp_post_revision_title((int)$_GET['revision'], false)) |
|
1335 | - : false, |
|
1336 | - 6 => sprintf( |
|
1337 | - __('%1$s published. %2$sView %1$s%3$s', 'event_espresso'), |
|
1338 | - $this->_cpt_object->labels->singular_name, |
|
1339 | - '<a href="' . esc_url(get_permalink($id)) . '">', |
|
1340 | - '</a>' |
|
1341 | - ), |
|
1342 | - 7 => sprintf(__('%1$s saved.', 'event_espresso'), $this->_cpt_object->labels->singular_name), |
|
1343 | - 8 => sprintf( |
|
1344 | - __('%1$s submitted. %2$sPreview %1$s%3$s', 'event_espresso'), |
|
1345 | - $this->_cpt_object->labels->singular_name, |
|
1346 | - '<a target="_blank" href="' . esc_url(add_query_arg('preview', 'true', get_permalink($id))) . '">', |
|
1347 | - '</a>' |
|
1348 | - ), |
|
1349 | - 9 => sprintf( |
|
1350 | - __('%1$s scheduled for: %2$s. %3$s">Preview %1$s%3$s', 'event_espresso'), |
|
1351 | - $this->_cpt_object->labels->singular_name, |
|
1352 | - '<strong>' . date_i18n(__('M j, Y @ G:i'), strtotime($post->post_date)) . '</strong>', |
|
1353 | - '<a target="_blank" href="' . esc_url(get_permalink($id)), |
|
1354 | - '</a>' |
|
1355 | - ), |
|
1356 | - 10 => sprintf( |
|
1357 | - __('%1$s draft updated. %2$s">Preview page%3$s', 'event_espresso'), |
|
1358 | - $this->_cpt_object->labels->singular_name, |
|
1359 | - '<a target="_blank" href="' . esc_url(add_query_arg('preview', 'true', get_permalink($id))), |
|
1360 | - '</a>' |
|
1361 | - ), |
|
1362 | - ); |
|
1363 | - return $messages; |
|
1364 | - } |
|
1365 | - |
|
1366 | - |
|
1367 | - |
|
1368 | - /** |
|
1369 | - * default method for the 'create_new' route for cpt admin pages. |
|
1370 | - * For reference what to include in here, see wp-admin/post-new.php |
|
1371 | - * |
|
1372 | - * @access protected |
|
1373 | - * @return void |
|
1374 | - */ |
|
1375 | - protected function _create_new_cpt_item() |
|
1376 | - { |
|
1377 | - // gather template vars for WP_ADMIN_PATH . 'edit-form-advanced.php' |
|
1378 | - global $post, $title, $is_IE, $post_type, $post_type_object; |
|
1379 | - $post_type = $this->_cpt_routes[$this->_req_action]; |
|
1380 | - $post_type_object = $this->_cpt_object; |
|
1381 | - $title = $post_type_object->labels->add_new_item; |
|
1382 | - $post = $post = get_default_post_to_edit($this->_cpt_routes[$this->_req_action], true); |
|
1383 | - add_action('admin_print_styles', array($this, 'add_new_admin_page_global')); |
|
1384 | - //modify the default editor title field with default title. |
|
1385 | - add_filter('enter_title_here', array($this, 'add_custom_editor_default_title'), 10); |
|
1386 | - $this->loadEditorTemplate(true); |
|
1387 | - } |
|
1388 | - |
|
1389 | - |
|
1390 | - /** |
|
1391 | - * Enqueues auto-save and loads the editor template |
|
1392 | - * |
|
1393 | - * @param bool $creating |
|
1394 | - */ |
|
1395 | - private function loadEditorTemplate($creating = true) { |
|
1396 | - global $post, $title, $is_IE, $post_type, $post_type_object; |
|
1397 | - //these vars are used by the template |
|
1398 | - $editing = true; |
|
1399 | - $post_ID = $post->ID; |
|
1400 | - if (apply_filters('FHEE__EE_Admin_Page_CPT___create_new_cpt_item__replace_editor', false, $post) === false) { |
|
1401 | - //only enqueue autosave when creating event (necessary to get permalink/url generated) |
|
1402 | - //otherwise EE doesn't support autosave fully, so to prevent user confusion we disable it in edit context. |
|
1403 | - if ($creating) { |
|
1404 | - wp_enqueue_script('autosave'); |
|
1405 | - } else { |
|
1406 | - if (isset($this->_cpt_routes[$this->_req_data['action']]) |
|
1407 | - && ! isset($this->_labels['hide_add_button_on_cpt_route'][$this->_req_data['action']]) |
|
1408 | - ) { |
|
1409 | - $create_new_action = apply_filters('FHEE__EE_Admin_Page_CPT___edit_cpt_item__create_new_action', |
|
1410 | - 'create_new', $this); |
|
1411 | - $post_new_file = EE_Admin_Page::add_query_args_and_nonce(array( |
|
1412 | - 'action' => $create_new_action, |
|
1413 | - 'page' => $this->page_slug, |
|
1414 | - ), 'admin.php'); |
|
1415 | - } |
|
1416 | - } |
|
1417 | - include_once WP_ADMIN_PATH . 'edit-form-advanced.php'; |
|
1418 | - } |
|
1419 | - } |
|
1420 | - |
|
1421 | - |
|
1422 | - |
|
1423 | - public function add_new_admin_page_global() |
|
1424 | - { |
|
1425 | - $admin_page = ! empty($this->_req_data['post']) ? 'post-php' : 'post-new-php'; |
|
1426 | - ?> |
|
1322 | + $messages[$post->post_type] = array( |
|
1323 | + 0 => '', //Unused. Messages start at index 1. |
|
1324 | + 1 => sprintf( |
|
1325 | + __('%1$s updated. %2$sView %1$s%3$s', 'event_espresso'), |
|
1326 | + $this->_cpt_object->labels->singular_name, |
|
1327 | + '<a href="' . esc_url(get_permalink($id)) . '">', |
|
1328 | + '</a>' |
|
1329 | + ), |
|
1330 | + 2 => __('Custom field updated'), |
|
1331 | + 3 => __('Custom field deleted.'), |
|
1332 | + 4 => sprintf(__('%1$s updated.', 'event_espresso'), $this->_cpt_object->labels->singular_name), |
|
1333 | + 5 => isset($_GET['revision']) ? sprintf(__('%s restored to revision from %s', 'event_espresso'), |
|
1334 | + $this->_cpt_object->labels->singular_name, wp_post_revision_title((int)$_GET['revision'], false)) |
|
1335 | + : false, |
|
1336 | + 6 => sprintf( |
|
1337 | + __('%1$s published. %2$sView %1$s%3$s', 'event_espresso'), |
|
1338 | + $this->_cpt_object->labels->singular_name, |
|
1339 | + '<a href="' . esc_url(get_permalink($id)) . '">', |
|
1340 | + '</a>' |
|
1341 | + ), |
|
1342 | + 7 => sprintf(__('%1$s saved.', 'event_espresso'), $this->_cpt_object->labels->singular_name), |
|
1343 | + 8 => sprintf( |
|
1344 | + __('%1$s submitted. %2$sPreview %1$s%3$s', 'event_espresso'), |
|
1345 | + $this->_cpt_object->labels->singular_name, |
|
1346 | + '<a target="_blank" href="' . esc_url(add_query_arg('preview', 'true', get_permalink($id))) . '">', |
|
1347 | + '</a>' |
|
1348 | + ), |
|
1349 | + 9 => sprintf( |
|
1350 | + __('%1$s scheduled for: %2$s. %3$s">Preview %1$s%3$s', 'event_espresso'), |
|
1351 | + $this->_cpt_object->labels->singular_name, |
|
1352 | + '<strong>' . date_i18n(__('M j, Y @ G:i'), strtotime($post->post_date)) . '</strong>', |
|
1353 | + '<a target="_blank" href="' . esc_url(get_permalink($id)), |
|
1354 | + '</a>' |
|
1355 | + ), |
|
1356 | + 10 => sprintf( |
|
1357 | + __('%1$s draft updated. %2$s">Preview page%3$s', 'event_espresso'), |
|
1358 | + $this->_cpt_object->labels->singular_name, |
|
1359 | + '<a target="_blank" href="' . esc_url(add_query_arg('preview', 'true', get_permalink($id))), |
|
1360 | + '</a>' |
|
1361 | + ), |
|
1362 | + ); |
|
1363 | + return $messages; |
|
1364 | + } |
|
1365 | + |
|
1366 | + |
|
1367 | + |
|
1368 | + /** |
|
1369 | + * default method for the 'create_new' route for cpt admin pages. |
|
1370 | + * For reference what to include in here, see wp-admin/post-new.php |
|
1371 | + * |
|
1372 | + * @access protected |
|
1373 | + * @return void |
|
1374 | + */ |
|
1375 | + protected function _create_new_cpt_item() |
|
1376 | + { |
|
1377 | + // gather template vars for WP_ADMIN_PATH . 'edit-form-advanced.php' |
|
1378 | + global $post, $title, $is_IE, $post_type, $post_type_object; |
|
1379 | + $post_type = $this->_cpt_routes[$this->_req_action]; |
|
1380 | + $post_type_object = $this->_cpt_object; |
|
1381 | + $title = $post_type_object->labels->add_new_item; |
|
1382 | + $post = $post = get_default_post_to_edit($this->_cpt_routes[$this->_req_action], true); |
|
1383 | + add_action('admin_print_styles', array($this, 'add_new_admin_page_global')); |
|
1384 | + //modify the default editor title field with default title. |
|
1385 | + add_filter('enter_title_here', array($this, 'add_custom_editor_default_title'), 10); |
|
1386 | + $this->loadEditorTemplate(true); |
|
1387 | + } |
|
1388 | + |
|
1389 | + |
|
1390 | + /** |
|
1391 | + * Enqueues auto-save and loads the editor template |
|
1392 | + * |
|
1393 | + * @param bool $creating |
|
1394 | + */ |
|
1395 | + private function loadEditorTemplate($creating = true) { |
|
1396 | + global $post, $title, $is_IE, $post_type, $post_type_object; |
|
1397 | + //these vars are used by the template |
|
1398 | + $editing = true; |
|
1399 | + $post_ID = $post->ID; |
|
1400 | + if (apply_filters('FHEE__EE_Admin_Page_CPT___create_new_cpt_item__replace_editor', false, $post) === false) { |
|
1401 | + //only enqueue autosave when creating event (necessary to get permalink/url generated) |
|
1402 | + //otherwise EE doesn't support autosave fully, so to prevent user confusion we disable it in edit context. |
|
1403 | + if ($creating) { |
|
1404 | + wp_enqueue_script('autosave'); |
|
1405 | + } else { |
|
1406 | + if (isset($this->_cpt_routes[$this->_req_data['action']]) |
|
1407 | + && ! isset($this->_labels['hide_add_button_on_cpt_route'][$this->_req_data['action']]) |
|
1408 | + ) { |
|
1409 | + $create_new_action = apply_filters('FHEE__EE_Admin_Page_CPT___edit_cpt_item__create_new_action', |
|
1410 | + 'create_new', $this); |
|
1411 | + $post_new_file = EE_Admin_Page::add_query_args_and_nonce(array( |
|
1412 | + 'action' => $create_new_action, |
|
1413 | + 'page' => $this->page_slug, |
|
1414 | + ), 'admin.php'); |
|
1415 | + } |
|
1416 | + } |
|
1417 | + include_once WP_ADMIN_PATH . 'edit-form-advanced.php'; |
|
1418 | + } |
|
1419 | + } |
|
1420 | + |
|
1421 | + |
|
1422 | + |
|
1423 | + public function add_new_admin_page_global() |
|
1424 | + { |
|
1425 | + $admin_page = ! empty($this->_req_data['post']) ? 'post-php' : 'post-new-php'; |
|
1426 | + ?> |
|
1427 | 1427 | <script type="text/javascript"> |
1428 | 1428 | adminpage = '<?php echo $admin_page; ?>'; |
1429 | 1429 | </script> |
1430 | 1430 | <?php |
1431 | - } |
|
1432 | - |
|
1433 | - |
|
1434 | - |
|
1435 | - /** |
|
1436 | - * default method for the 'edit' route for cpt admin pages |
|
1437 | - * For reference on what to put in here, refer to wp-admin/post.php |
|
1438 | - * |
|
1439 | - * @access protected |
|
1440 | - * @return string template for edit cpt form |
|
1441 | - */ |
|
1442 | - protected function _edit_cpt_item() |
|
1443 | - { |
|
1444 | - global $post, $title, $is_IE, $post_type, $post_type_object; |
|
1445 | - $post_id = isset($this->_req_data['post']) ? $this->_req_data['post'] : null; |
|
1446 | - $post = ! empty($post_id) ? get_post($post_id, OBJECT, 'edit') : null; |
|
1447 | - if (empty ($post)) { |
|
1448 | - wp_die(__('You attempted to edit an item that doesn’t exist. Perhaps it was deleted?')); |
|
1449 | - } |
|
1450 | - if ( ! empty($_GET['get-post-lock'])) { |
|
1451 | - wp_set_post_lock($post_id); |
|
1452 | - wp_redirect(get_edit_post_link($post_id, 'url')); |
|
1453 | - exit(); |
|
1454 | - } |
|
1455 | - |
|
1456 | - // template vars for WP_ADMIN_PATH . 'edit-form-advanced.php' |
|
1457 | - $post_type = $this->_cpt_routes[$this->_req_action]; |
|
1458 | - $post_type_object = $this->_cpt_object; |
|
1459 | - |
|
1460 | - if ( ! wp_check_post_lock($post->ID)) { |
|
1461 | - wp_set_post_lock($post->ID); |
|
1462 | - } |
|
1463 | - add_action('admin_footer', '_admin_notice_post_locked'); |
|
1464 | - if (post_type_supports($this->_cpt_routes[$this->_req_action], 'comments')) { |
|
1465 | - wp_enqueue_script('admin-comments'); |
|
1466 | - enqueue_comment_hotkeys_js(); |
|
1467 | - } |
|
1468 | - add_action('admin_print_styles', array($this, 'add_new_admin_page_global')); |
|
1469 | - //modify the default editor title field with default title. |
|
1470 | - add_filter('enter_title_here', array($this, 'add_custom_editor_default_title'), 10); |
|
1471 | - $this->loadEditorTemplate(false); |
|
1472 | - } |
|
1473 | - |
|
1474 | - |
|
1475 | - |
|
1476 | - /** |
|
1477 | - * some getters |
|
1478 | - */ |
|
1479 | - /** |
|
1480 | - * This returns the protected _cpt_model_obj property |
|
1481 | - * |
|
1482 | - * @return EE_CPT_Base |
|
1483 | - */ |
|
1484 | - public function get_cpt_model_obj() |
|
1485 | - { |
|
1486 | - return $this->_cpt_model_obj; |
|
1487 | - } |
|
1431 | + } |
|
1432 | + |
|
1433 | + |
|
1434 | + |
|
1435 | + /** |
|
1436 | + * default method for the 'edit' route for cpt admin pages |
|
1437 | + * For reference on what to put in here, refer to wp-admin/post.php |
|
1438 | + * |
|
1439 | + * @access protected |
|
1440 | + * @return string template for edit cpt form |
|
1441 | + */ |
|
1442 | + protected function _edit_cpt_item() |
|
1443 | + { |
|
1444 | + global $post, $title, $is_IE, $post_type, $post_type_object; |
|
1445 | + $post_id = isset($this->_req_data['post']) ? $this->_req_data['post'] : null; |
|
1446 | + $post = ! empty($post_id) ? get_post($post_id, OBJECT, 'edit') : null; |
|
1447 | + if (empty ($post)) { |
|
1448 | + wp_die(__('You attempted to edit an item that doesn’t exist. Perhaps it was deleted?')); |
|
1449 | + } |
|
1450 | + if ( ! empty($_GET['get-post-lock'])) { |
|
1451 | + wp_set_post_lock($post_id); |
|
1452 | + wp_redirect(get_edit_post_link($post_id, 'url')); |
|
1453 | + exit(); |
|
1454 | + } |
|
1455 | + |
|
1456 | + // template vars for WP_ADMIN_PATH . 'edit-form-advanced.php' |
|
1457 | + $post_type = $this->_cpt_routes[$this->_req_action]; |
|
1458 | + $post_type_object = $this->_cpt_object; |
|
1459 | + |
|
1460 | + if ( ! wp_check_post_lock($post->ID)) { |
|
1461 | + wp_set_post_lock($post->ID); |
|
1462 | + } |
|
1463 | + add_action('admin_footer', '_admin_notice_post_locked'); |
|
1464 | + if (post_type_supports($this->_cpt_routes[$this->_req_action], 'comments')) { |
|
1465 | + wp_enqueue_script('admin-comments'); |
|
1466 | + enqueue_comment_hotkeys_js(); |
|
1467 | + } |
|
1468 | + add_action('admin_print_styles', array($this, 'add_new_admin_page_global')); |
|
1469 | + //modify the default editor title field with default title. |
|
1470 | + add_filter('enter_title_here', array($this, 'add_custom_editor_default_title'), 10); |
|
1471 | + $this->loadEditorTemplate(false); |
|
1472 | + } |
|
1473 | + |
|
1474 | + |
|
1475 | + |
|
1476 | + /** |
|
1477 | + * some getters |
|
1478 | + */ |
|
1479 | + /** |
|
1480 | + * This returns the protected _cpt_model_obj property |
|
1481 | + * |
|
1482 | + * @return EE_CPT_Base |
|
1483 | + */ |
|
1484 | + public function get_cpt_model_obj() |
|
1485 | + { |
|
1486 | + return $this->_cpt_model_obj; |
|
1487 | + } |
|
1488 | 1488 | |
1489 | 1489 | } |
@@ -235,7 +235,7 @@ discard block |
||
235 | 235 | */ |
236 | 236 | protected function _register_autosave_containers($ids) |
237 | 237 | { |
238 | - $this->_autosave_containers = array_merge($this->_autosave_fields, (array)$ids); |
|
238 | + $this->_autosave_containers = array_merge($this->_autosave_fields, (array) $ids); |
|
239 | 239 | } |
240 | 240 | |
241 | 241 | |
@@ -282,7 +282,7 @@ discard block |
||
282 | 282 | //filter _autosave_containers |
283 | 283 | $containers = apply_filters('FHEE__EE_Admin_Page_CPT___load_autosave_scripts_styles__containers', |
284 | 284 | $this->_autosave_containers, $this); |
285 | - $containers = apply_filters('FHEE__EE_Admin_Page_CPT__' . get_class($this) . '___load_autosave_scripts_styles__containers', |
|
285 | + $containers = apply_filters('FHEE__EE_Admin_Page_CPT__'.get_class($this).'___load_autosave_scripts_styles__containers', |
|
286 | 286 | $containers, $this); |
287 | 287 | |
288 | 288 | wp_localize_script('event_editor_js', 'EE_AUTOSAVE_IDS', |
@@ -394,7 +394,7 @@ discard block |
||
394 | 394 | // This is for any plugins that are doing things properly |
395 | 395 | // and hooking into the load page hook for core wp cpt routes. |
396 | 396 | global $pagenow; |
397 | - do_action('load-' . $pagenow); |
|
397 | + do_action('load-'.$pagenow); |
|
398 | 398 | $this->modify_current_screen(); |
399 | 399 | add_action('admin_enqueue_scripts', array($this, 'setup_autosave_hooks'), 30); |
400 | 400 | //we route REALLY early. |
@@ -425,8 +425,8 @@ discard block |
||
425 | 425 | 'admin.php?page=espresso_registrations&action=contact_list', |
426 | 426 | ), |
427 | 427 | 1 => array( |
428 | - 'edit.php?post_type=' . $this->_cpt_object->name, |
|
429 | - 'admin.php?page=' . $this->_cpt_object->name, |
|
428 | + 'edit.php?post_type='.$this->_cpt_object->name, |
|
429 | + 'admin.php?page='.$this->_cpt_object->name, |
|
430 | 430 | ), |
431 | 431 | ); |
432 | 432 | foreach ($routes_to_match as $route_matches) { |
@@ -454,7 +454,7 @@ discard block |
||
454 | 454 | $cpt_has_support = ! empty($cpt_args['page_templates']); |
455 | 455 | |
456 | 456 | //if the installed version of WP is > 4.7 we do some additional checks. |
457 | - if (EE_Recommended_Versions::check_wp_version('4.7','>=')) { |
|
457 | + if (EE_Recommended_Versions::check_wp_version('4.7', '>=')) { |
|
458 | 458 | $post_templates = wp_get_theme()->get_post_templates(); |
459 | 459 | //if there are $post_templates for this cpt, then we return false for this method because |
460 | 460 | //that means we aren't going to load our page template manager and leave that up to the native |
@@ -477,7 +477,7 @@ discard block |
||
477 | 477 | global $post; |
478 | 478 | $template = ''; |
479 | 479 | |
480 | - if (EE_Recommended_Versions::check_wp_version('4.7','>=')) { |
|
480 | + if (EE_Recommended_Versions::check_wp_version('4.7', '>=')) { |
|
481 | 481 | $page_template_count = count(get_page_templates()); |
482 | 482 | } else { |
483 | 483 | $page_template_count = count(get_page_templates($post)); |
@@ -514,7 +514,7 @@ discard block |
||
514 | 514 | $post = get_post($id); |
515 | 515 | if ('publish' !== get_post_status($post)) { |
516 | 516 | //include shims for the `get_preview_post_link` function |
517 | - require_once( EE_CORE . 'wordpress-shims.php' ); |
|
517 | + require_once(EE_CORE.'wordpress-shims.php'); |
|
518 | 518 | $return .= '<span_id="view-post-btn"><a target="_blank" href="' |
519 | 519 | . get_preview_post_link($id) |
520 | 520 | . '" class="button button-small">' |
@@ -552,7 +552,7 @@ discard block |
||
552 | 552 | $template_args['statuses'] = $statuses; |
553 | 553 | } |
554 | 554 | |
555 | - $template = EE_ADMIN_TEMPLATE . 'status_dropdown.template.php'; |
|
555 | + $template = EE_ADMIN_TEMPLATE.'status_dropdown.template.php'; |
|
556 | 556 | EEH_Template::display_template($template, $template_args); |
557 | 557 | } |
558 | 558 | |
@@ -606,7 +606,7 @@ discard block |
||
606 | 606 | $this->_template_args['success'] = true; |
607 | 607 | } |
608 | 608 | do_action('AHEE__EE_Admin_Page_CPT__do_extra_autosave_stuff__global_after', $this); |
609 | - do_action('AHEE__EE_Admin_Page_CPT__do_extra_autosave_stuff__after_' . get_class($this), $this); |
|
609 | + do_action('AHEE__EE_Admin_Page_CPT__do_extra_autosave_stuff__after_'.get_class($this), $this); |
|
610 | 610 | //now let's return json |
611 | 611 | $this->_return_json(); |
612 | 612 | } |
@@ -1009,7 +1009,7 @@ discard block |
||
1009 | 1009 | //global action |
1010 | 1010 | do_action('AHEE_EE_Admin_Page_CPT__restore_revision', $post_id, $revision_id); |
1011 | 1011 | //class specific action so you can limit hooking into a specific page. |
1012 | - do_action('AHEE_EE_Admin_Page_CPT_' . get_class($this) . '__restore_revision', $post_id, $revision_id); |
|
1012 | + do_action('AHEE_EE_Admin_Page_CPT_'.get_class($this).'__restore_revision', $post_id, $revision_id); |
|
1013 | 1013 | } |
1014 | 1014 | |
1015 | 1015 | |
@@ -1087,7 +1087,7 @@ discard block |
||
1087 | 1087 | if ( ! empty($id) && get_option('permalink_structure') !== '') { |
1088 | 1088 | $post = get_post($id); |
1089 | 1089 | if (isset($post->post_type) && $this->page_slug === $post->post_type) { |
1090 | - $shortlink = home_url('?p=' . $post->ID); |
|
1090 | + $shortlink = home_url('?p='.$post->ID); |
|
1091 | 1091 | } |
1092 | 1092 | } |
1093 | 1093 | return $shortlink; |
@@ -1122,11 +1122,11 @@ discard block |
||
1122 | 1122 | */ |
1123 | 1123 | public function cpt_post_form_hidden_input() |
1124 | 1124 | { |
1125 | - echo '<input type="hidden" name="ee_cpt_item_redirect_url" value="' . $this->_admin_base_url . '" />'; |
|
1125 | + echo '<input type="hidden" name="ee_cpt_item_redirect_url" value="'.$this->_admin_base_url.'" />'; |
|
1126 | 1126 | //we're also going to add the route value and the current page so we can direct autosave parsing correctly |
1127 | 1127 | echo '<div id="ee-cpt-hidden-inputs">'; |
1128 | - echo '<input type="hidden" id="current_route" name="current_route" value="' . $this->_current_view . '" />'; |
|
1129 | - echo '<input type="hidden" id="current_page" name="current_page" value="' . $this->page_slug . '" />'; |
|
1128 | + echo '<input type="hidden" id="current_route" name="current_route" value="'.$this->_current_view.'" />'; |
|
1129 | + echo '<input type="hidden" id="current_page" name="current_page" value="'.$this->page_slug.'" />'; |
|
1130 | 1130 | echo '</div>'; |
1131 | 1131 | } |
1132 | 1132 | |
@@ -1213,7 +1213,7 @@ discard block |
||
1213 | 1213 | $this->_set_model_object($post->ID, true); |
1214 | 1214 | |
1215 | 1215 | //returns something like `trash_event` or `trash_attendee` or `trash_venue` |
1216 | - $action = 'trash_' . str_replace('ee_', '', strtolower(get_class($this->_cpt_model_obj))); |
|
1216 | + $action = 'trash_'.str_replace('ee_', '', strtolower(get_class($this->_cpt_model_obj))); |
|
1217 | 1217 | |
1218 | 1218 | return EE_Admin_Page::add_query_args_and_nonce( |
1219 | 1219 | array( |
@@ -1324,39 +1324,39 @@ discard block |
||
1324 | 1324 | 1 => sprintf( |
1325 | 1325 | __('%1$s updated. %2$sView %1$s%3$s', 'event_espresso'), |
1326 | 1326 | $this->_cpt_object->labels->singular_name, |
1327 | - '<a href="' . esc_url(get_permalink($id)) . '">', |
|
1327 | + '<a href="'.esc_url(get_permalink($id)).'">', |
|
1328 | 1328 | '</a>' |
1329 | 1329 | ), |
1330 | 1330 | 2 => __('Custom field updated'), |
1331 | 1331 | 3 => __('Custom field deleted.'), |
1332 | 1332 | 4 => sprintf(__('%1$s updated.', 'event_espresso'), $this->_cpt_object->labels->singular_name), |
1333 | 1333 | 5 => isset($_GET['revision']) ? sprintf(__('%s restored to revision from %s', 'event_espresso'), |
1334 | - $this->_cpt_object->labels->singular_name, wp_post_revision_title((int)$_GET['revision'], false)) |
|
1334 | + $this->_cpt_object->labels->singular_name, wp_post_revision_title((int) $_GET['revision'], false)) |
|
1335 | 1335 | : false, |
1336 | 1336 | 6 => sprintf( |
1337 | 1337 | __('%1$s published. %2$sView %1$s%3$s', 'event_espresso'), |
1338 | 1338 | $this->_cpt_object->labels->singular_name, |
1339 | - '<a href="' . esc_url(get_permalink($id)) . '">', |
|
1339 | + '<a href="'.esc_url(get_permalink($id)).'">', |
|
1340 | 1340 | '</a>' |
1341 | 1341 | ), |
1342 | 1342 | 7 => sprintf(__('%1$s saved.', 'event_espresso'), $this->_cpt_object->labels->singular_name), |
1343 | 1343 | 8 => sprintf( |
1344 | 1344 | __('%1$s submitted. %2$sPreview %1$s%3$s', 'event_espresso'), |
1345 | 1345 | $this->_cpt_object->labels->singular_name, |
1346 | - '<a target="_blank" href="' . esc_url(add_query_arg('preview', 'true', get_permalink($id))) . '">', |
|
1346 | + '<a target="_blank" href="'.esc_url(add_query_arg('preview', 'true', get_permalink($id))).'">', |
|
1347 | 1347 | '</a>' |
1348 | 1348 | ), |
1349 | 1349 | 9 => sprintf( |
1350 | 1350 | __('%1$s scheduled for: %2$s. %3$s">Preview %1$s%3$s', 'event_espresso'), |
1351 | 1351 | $this->_cpt_object->labels->singular_name, |
1352 | - '<strong>' . date_i18n(__('M j, Y @ G:i'), strtotime($post->post_date)) . '</strong>', |
|
1353 | - '<a target="_blank" href="' . esc_url(get_permalink($id)), |
|
1352 | + '<strong>'.date_i18n(__('M j, Y @ G:i'), strtotime($post->post_date)).'</strong>', |
|
1353 | + '<a target="_blank" href="'.esc_url(get_permalink($id)), |
|
1354 | 1354 | '</a>' |
1355 | 1355 | ), |
1356 | 1356 | 10 => sprintf( |
1357 | 1357 | __('%1$s draft updated. %2$s">Preview page%3$s', 'event_espresso'), |
1358 | 1358 | $this->_cpt_object->labels->singular_name, |
1359 | - '<a target="_blank" href="' . esc_url(add_query_arg('preview', 'true', get_permalink($id))), |
|
1359 | + '<a target="_blank" href="'.esc_url(add_query_arg('preview', 'true', get_permalink($id))), |
|
1360 | 1360 | '</a>' |
1361 | 1361 | ), |
1362 | 1362 | ); |
@@ -1379,7 +1379,7 @@ discard block |
||
1379 | 1379 | $post_type = $this->_cpt_routes[$this->_req_action]; |
1380 | 1380 | $post_type_object = $this->_cpt_object; |
1381 | 1381 | $title = $post_type_object->labels->add_new_item; |
1382 | - $post = $post = get_default_post_to_edit($this->_cpt_routes[$this->_req_action], true); |
|
1382 | + $post = $post = get_default_post_to_edit($this->_cpt_routes[$this->_req_action], true); |
|
1383 | 1383 | add_action('admin_print_styles', array($this, 'add_new_admin_page_global')); |
1384 | 1384 | //modify the default editor title field with default title. |
1385 | 1385 | add_filter('enter_title_here', array($this, 'add_custom_editor_default_title'), 10); |
@@ -1414,7 +1414,7 @@ discard block |
||
1414 | 1414 | ), 'admin.php'); |
1415 | 1415 | } |
1416 | 1416 | } |
1417 | - include_once WP_ADMIN_PATH . 'edit-form-advanced.php'; |
|
1417 | + include_once WP_ADMIN_PATH.'edit-form-advanced.php'; |
|
1418 | 1418 | } |
1419 | 1419 | } |
1420 | 1420 |