Completed
Branch BUG/11268/session-ticket-relea... (f9aa59)
by
unknown
13:30 queued 24s
created
core/EE_Cron_Tasks.core.php 2 patches
Indentation   +601 added lines, -601 removed lines patch added patch discarded remove patch
@@ -17,607 +17,607 @@
 block discarded – undo
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
Please login to merge, or discard this patch.
Spacing   +14 added lines, -14 removed lines patch added patch discarded remove patch
@@ -40,7 +40,7 @@  discard block
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 
Please login to merge, or discard this patch.
core/db_models/EEM_Transaction.model.php 1 patch
Indentation   +401 added lines, -401 removed lines patch added patch discarded remove patch
@@ -4,7 +4,7 @@  discard block
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 }
Please login to merge, or discard this patch.
widgets/upcoming_events/EEW_Upcoming_Events.widget.php 1 patch
Spacing   +80 added lines, -80 removed lines patch added patch discarded remove patch
@@ -31,8 +31,8 @@  discard block
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 }
Please login to merge, or discard this patch.
core/libraries/messages/EE_Messages_Queue.lib.php 2 patches
Indentation   +689 added lines, -689 removed lines patch added patch discarded remove patch
@@ -2,7 +2,7 @@  discard block
 block discarded – undo
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
 block discarded – undo
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
Please login to merge, or discard this patch.
Spacing   +8 added lines, -8 removed lines patch added patch discarded remove patch
@@ -1,7 +1,7 @@  discard block
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
     }
Please login to merge, or discard this patch.
admin_pages/payments/Payment_Log_Admin_List_Table.class.php 3 patches
Doc Comments   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -101,7 +101,7 @@
 block discarded – undo
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
     {
Please login to merge, or discard this patch.
Indentation   +195 added lines, -195 removed lines patch added patch discarded remove patch
@@ -1,6 +1,6 @@  discard block
 block discarded – undo
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
 block discarded – undo
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
 
Please login to merge, or discard this patch.
Spacing   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -1,5 +1,5 @@  discard block
 block discarded – undo
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
 block discarded – undo
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
 
Please login to merge, or discard this patch.
core/libraries/rest_api/ModelDataTranslator.php 3 patches
Unused Use Statements   -2 removed lines patch added patch discarded remove patch
@@ -2,11 +2,9 @@
 block discarded – undo
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;
Please login to merge, or discard this patch.
Indentation   +834 added lines, -834 removed lines patch added patch discarded remove patch
@@ -12,7 +12,7 @@  discard block
 block discarded – undo
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
 block discarded – undo
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
 }
Please login to merge, or discard this patch.
Spacing   +16 added lines, -16 removed lines patch added patch discarded remove patch
@@ -11,7 +11,7 @@  discard block
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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(
Please login to merge, or discard this patch.
core/helpers/EEH_DTT_Helper.helper.php 1 patch
Indentation   +955 added lines, -955 removed lines patch added patch discarded remove patch
@@ -21,1015 +21,1015 @@
 block discarded – undo
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
Please login to merge, or discard this patch.
strategies/validation/EE_Many_Valued_Validation_Strategy.strategy.php 1 patch
Indentation   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -45,8 +45,8 @@
 block discarded – undo
45 45
 				}
46 46
 			}
47 47
 		}
48
-        return true;
49
-    }
48
+		return true;
49
+	}
50 50
 
51 51
 
52 52
 
Please login to merge, or discard this patch.
core/admin/EE_Admin_Page_CPT.core.php 2 patches
Indentation   +1432 added lines, -1432 removed lines patch added patch discarded remove patch
@@ -1,5 +1,5 @@  discard block
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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&#8217;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&#8217;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
 }
Please login to merge, or discard this patch.
Spacing   +25 added lines, -25 removed lines patch added patch discarded remove patch
@@ -235,7 +235,7 @@  discard block
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 block discarded – undo
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
 
Please login to merge, or discard this patch.