Completed
Branch master (87d3f3)
by
unknown
03:30
created
payment_methods/Paypal_Express/EEG_Paypal_Express.gateway.php 1 patch
Indentation   +544 added lines, -544 removed lines patch added patch discarded remove patch
@@ -12,548 +12,548 @@
 block discarded – undo
12 12
  */
13 13
 class EEG_Paypal_Express extends EE_Offsite_Gateway
14 14
 {
15
-    /**
16
-     * Merchant API Username.
17
-     *
18
-     * @var string
19
-     */
20
-    protected $_api_username;
21
-
22
-    /**
23
-     * Merchant API Password.
24
-     *
25
-     * @var string
26
-     */
27
-    protected $_api_password;
28
-
29
-    /**
30
-     * API Signature.
31
-     *
32
-     * @var string
33
-     */
34
-    protected $_api_signature;
35
-
36
-    /**
37
-     * Request Shipping address on PP checkout page.
38
-     *
39
-     * @var string
40
-     */
41
-    protected $_request_shipping_addr;
42
-
43
-    /**
44
-     * Business/personal logo.
45
-     *
46
-     * @var string
47
-     */
48
-    protected $_image_url = '';
49
-
50
-    /**
51
-     * gateway URL variable
52
-     *
53
-     * @var string
54
-     */
55
-    protected $_base_gateway_url = '';
56
-
57
-
58
-    /**
59
-     * number of decimal places to round numbers to when performing calculations
60
-     *
61
-     * @var integer
62
-     */
63
-    protected $decimal_precision = 6;
64
-
65
-    /**
66
-     * @var ItemizedOrder
67
-     * @since $VID:$
68
-     */
69
-    protected $itemized_order;
70
-
71
-    /**
72
-     * @var TokenRequest
73
-     * @since $VID:$
74
-     */
75
-    protected $token_request;
76
-
77
-
78
-    /**
79
-     * EEG_Paypal_Express constructor.
80
-     */
81
-    public function __construct()
82
-    {
83
-        require_once 'polyfills.php';
84
-        $this->_currencies_supported = [
85
-            'USD',
86
-            'AUD',
87
-            'BRL',
88
-            'CAD',
89
-            'CZK',
90
-            'DKK',
91
-            'EUR',
92
-            'HKD',
93
-            'HUF',
94
-            'ILS',
95
-            'JPY',
96
-            'MYR',
97
-            'MXN',
98
-            'NOK',
99
-            'NZD',
100
-            'PHP',
101
-            'PLN',
102
-            'GBP',
103
-            'RUB',
104
-            'SGD',
105
-            'SEK',
106
-            'CHF',
107
-            'TWD',
108
-            'THB',
109
-            'TRY',
110
-            'INR',
111
-        ];
112
-        parent::__construct();
113
-        $this->decimal_precision = EE_Registry::instance()->CFG->currency->dec_plc;
114
-    }
115
-
116
-
117
-    /**
118
-     * Sets the gateway URL variable based on whether debug mode is enabled or not.
119
-     *
120
-     * @param array $settings_array
121
-     */
122
-    public function set_settings(array $settings_array)
123
-    {
124
-        parent::set_settings($settings_array);
125
-        // Redirect URL.
126
-        $this->_base_gateway_url = $this->_debug_mode
127
-            ? 'https://api-3t.sandbox.paypal.com/nvp'
128
-            : 'https://api-3t.paypal.com/nvp';
129
-    }
130
-
131
-
132
-    /**
133
-     * @param EE_Payment $payment
134
-     * @param array       $billing_info
135
-     * @param string      $return_url
136
-     * @param string      $notify_url
137
-     * @param string      $cancel_url
138
-     * @return EE_Payment
139
-     * @throws EE_Error
140
-     * @throws ReflectionException
141
-     * @throws Exception
142
-     */
143
-    public function set_redirection_info(
144
-        $payment,
145
-        $billing_info = [],
146
-        $return_url = null,
147
-        $notify_url = null,
148
-        $cancel_url = null
149
-    ) {
150
-        if (! $this->validatePayment($payment)) {
151
-            return $payment;
152
-        }
153
-        if (! $this->validateTransaction($payment)) {
154
-            return $payment;
155
-        }
156
-        $this->token_request = new TokenRequest($this->_get_gateway_formatter());
157
-        $token_request_details = apply_filters(
158
-            'FHEE__EEG_Paypal_Express__set_redirection_info__arguments',
159
-            $this->token_request->generateDetails(
160
-                $payment,
161
-                $this->getOrderItems($payment),
162
-                $return_url ?? '',
163
-                $cancel_url ?? '',
164
-                $this->_image_url ?? '',
165
-                $this->_request_shipping_addr ?? ''
166
-            ),
167
-            $this
168
-        );
169
-        // Request PayPal token.
170
-        $token_request_response = $this->_ppExpress_request($token_request_details, 'Payment Token', $payment);
171
-        $token_request_status   = $this->_ppExpress_check_response($token_request_response);
172
-        $this->token_request->processResponse($payment, $token_request_status, $this->isInSandboxMode());
173
-
174
-        return $payment;
175
-    }
176
-
177
-
178
-    /**
179
-     * @param array           $update_info {
180
-     * @type string           $gateway_txn_id
181
-     * @type string           $status      an EEMI_Payment status
182
-     *                                     }
183
-     * @param EE_Transaction $transaction
184
-     * @return EE_Payment
185
-     * @throws Exception
186
-     */
187
-    public function handle_payment_update($update_info, $transaction): EE_Payment
188
-    {
189
-        // if the supplied transaction is valid, we'll retrieve the actual payment object from it
190
-        // but we'll use a temporary payment for now that we can return with errors if things go wrong
191
-        $payment = EE_Payment::new_instance();
192
-        if (! $this->validateTransaction($payment, $transaction)) {
193
-            return $payment;
194
-        }
195
-        $payment = $transaction->last_payment();
196
-        if (! $this->validatePayment($payment)) {
197
-            return $payment;
198
-        }
199
-        // payment appears to be good... so far
200
-        $this->log(['Return from Authorization' => $update_info], $payment);
201
-        $payment_token = $this->getPaymentToken($payment);
202
-        $customer_details = $this->requestCustomerDetails($payment, $payment_token);
203
-        // We got the PayerID so now we can Complete the transaction.
204
-        $this->processPayment($payment, $payment_token, $customer_details);
205
-
206
-        return $payment;
207
-    }
208
-
209
-
210
-    /**
211
-     * @throws Exception
212
-     */
213
-    private function getOrderItems(EE_Payment $payment, array $request_response_args = []): array
214
-    {
215
-        $this->itemized_order = new ItemizedOrder($this->_get_gateway_formatter());
216
-        try {
217
-            $itemized_order = $this->itemized_order->getExistingItemizedOrder($request_response_args);
218
-        } catch (Exception $exception) {
219
-            if (WP_DEBUG) {
220
-                throw $exception;
221
-            }
222
-            // Reset the list and log an error, maybe allow to try and generate a new list (below).
223
-            $itemized_order = [];
224
-            $this->log(
225
-                [
226
-                    esc_html__(
227
-                        'Could not generate a proper item list with:',
228
-                        'event_espresso'
229
-                    ) => $request_response_args,
230
-                ],
231
-                $payment
232
-            );
233
-        }
234
-        if (empty($itemized_order)) {
235
-            $itemized_order = $this->itemized_order->generateItemizedOrder($payment);
236
-        }
237
-        return $itemized_order;
238
-    }
239
-
240
-
241
-    /**
242
-     *  Make the Express checkout request.
243
-     *
244
-     * @param array       $request_params
245
-     * @param string      $request_text
246
-     * @param EE_Payment $payment
247
-     * @return array|WP_Error
248
-     */
249
-    public function _ppExpress_request(array $request_params, string $request_text, EE_Payment $payment)
250
-    {
251
-        $request_dtls = [
252
-            'VERSION'      => '204.0',
253
-            'USER'         => $this->_api_username,
254
-            'PWD'          => $this->_api_password,
255
-            'SIGNATURE'    => $this->_api_signature,
256
-            // EE will blow up if you change this
257
-            'BUTTONSOURCE' => 'EventEspresso_SP',
258
-        ];
259
-        $dtls         = array_merge($request_dtls, $request_params);
260
-        $this->_log_clean_request($dtls, $payment, $request_text . ' Request');
261
-        // Request Customer Details.
262
-        $request_response = wp_remote_post(
263
-            $this->_base_gateway_url,
264
-            [
265
-                'method'      => 'POST',
266
-                'timeout'     => 45,
267
-                'httpversion' => '1.1',
268
-                'cookies'     => [],
269
-                'headers'     => [],
270
-                'body'        => http_build_query($dtls),
271
-            ]
272
-        );
273
-        // Log the response.
274
-        $this->log([$request_text . ' Response' => $request_response], $payment);
275
-        return $request_response;
276
-    }
277
-
278
-
279
-    /**
280
-     *  Check the response status.
281
-     *
282
-     * @param mixed $request_response
283
-     * @return array
284
-     */
285
-    public function _ppExpress_check_response($request_response): array
286
-    {
287
-        if (is_wp_error($request_response) || empty($request_response['body'])) {
288
-            // If we got here then there was an error in this request.
289
-            return ['status' => false, 'args' => $request_response];
290
-        }
291
-        $response_args = [];
292
-        parse_str(urldecode($request_response['body']), $response_args);
293
-        if (! isset($response_args['ACK'])) {
294
-            return ['status' => false, 'args' => $request_response];
295
-        }
296
-        if (
297
-            (
298
-                isset($response_args['PAYERID'])
299
-                || isset($response_args['TOKEN'])
300
-                || isset($response_args['PAYMENTINFO_0_TRANSACTIONID'])
301
-                || (isset($response_args['PAYMENTSTATUS']) && $response_args['PAYMENTSTATUS'] === 'Completed')
302
-            )
303
-            && in_array($response_args['ACK'], ['Success', 'SuccessWithWarning'], true)
304
-        ) {
305
-            // Response status OK, return response parameters for further processing.
306
-            return ['status' => true, 'args' => $response_args];
307
-        }
308
-        $errors = $this->_get_errors($response_args);
309
-        return ['status' => false, 'args' => $errors];
310
-    }
311
-
312
-
313
-    /**
314
-     *  Log a "Cleared" request.
315
-     *
316
-     * @param array       $request
317
-     * @param EE_Payment $payment
318
-     * @param string      $info
319
-     * @return void
320
-     */
321
-    private function _log_clean_request(array $request, EE_Payment $payment, string $info)
322
-    {
323
-        $cleaned_request_data = $request;
324
-        unset($cleaned_request_data['PWD'], $cleaned_request_data['USER'], $cleaned_request_data['SIGNATURE']);
325
-        $this->log([$info => $cleaned_request_data], $payment);
326
-    }
327
-
328
-
329
-    /**
330
-     *  Get error from the response data.
331
-     *
332
-     * @param array $data_array
333
-     * @return array
334
-     */
335
-    private function _get_errors(array $data_array): array
336
-    {
337
-        $errors = [];
338
-        $n      = 0;
339
-        while (isset($data_array[ "L_ERRORCODE{$n}" ])) {
340
-            $l_error_code    = $data_array[ "L_ERRORCODE{$n}" ] ?? '';
341
-            $l_severity_code = $data_array[ "L_SEVERITYCODE{$n}" ] ?? '';
342
-            $l_short_message = $data_array[ "L_SHORTMESSAGE{$n}" ] ?? '';
343
-            $l_long_message  = $data_array[ "L_LONGMESSAGE{$n}" ] ?? '';
344
-            if ($n === 0) {
345
-                $errors = [
346
-                    'L_ERRORCODE'    => $l_error_code,
347
-                    'L_SHORTMESSAGE' => $l_short_message,
348
-                    'L_LONGMESSAGE'  => $l_long_message,
349
-                    'L_SEVERITYCODE' => $l_severity_code,
350
-                ];
351
-            } else {
352
-                $errors['L_ERRORCODE']    .= ', ' . $l_error_code;
353
-                $errors['L_SHORTMESSAGE'] .= ', ' . $l_short_message;
354
-                $errors['L_LONGMESSAGE']  .= ', ' . $l_long_message;
355
-                $errors['L_SEVERITYCODE'] .= ', ' . $l_severity_code;
356
-            }
357
-            $n++;
358
-        }
359
-        return $errors;
360
-    }
361
-
362
-
363
-    /**
364
-     * @param EE_Payment $payment
365
-     * @return mixed|null
366
-     * @throws EE_Error
367
-     * @since   $VID:$
368
-     */
369
-    private function getPaymentToken(EE_Payment $payment)
370
-    {
371
-        $payment_details = $payment->details();
372
-        // Check if we still have the token.
373
-        if (! isset($payment_details['TOKEN']) || empty($payment_details['TOKEN'])) {
374
-            $payment->set_status($this->_pay_model->failed_status());
375
-            return null;
376
-        }
377
-        return $payment_details['TOKEN'];
378
-    }
379
-
380
-    /**
381
-     * @param EE_Payment $payment
382
-     * @param array      $checkout_response
383
-     * @param array      $customer_data
384
-     * @throws EE_Error
385
-     * @throws ReflectionException
386
-     * @since   $VID:$
387
-     */
388
-    private function paymentApproved(EE_Payment $payment, array $checkout_response, array $customer_data)
389
-    {
390
-        $primary_registrant = $payment->transaction()->primary_registration();
391
-        $primary_registration_code = $primary_registrant instanceof EE_Registration ?
392
-            $primary_registrant->reg_code()
393
-            : '';
394
-        $payment->set_extra_accntng($primary_registration_code);
395
-        $payment_amount = $checkout_response['PAYMENTINFO_0_AMT'] ?? 0;
396
-        $payment->set_amount((float) $payment_amount);
397
-        $payment->set_txn_id_chq_nmbr($checkout_response['PAYMENTINFO_0_TRANSACTIONID'] ?? null);
398
-        $payment->set_details($customer_data);
399
-        $payment->set_gateway_response($checkout_response['PAYMENTINFO_0_ACK'] ?? '');
400
-        $payment->set_status($this->_pay_model->approved_status());
401
-    }
402
-
403
-
404
-    /**
405
-     * @param EE_Payment $payment
406
-     * @param array      $checkout_response
407
-     * @throws EE_Error
408
-     * @since   $VID:$
409
-     */
410
-    private function paymentDeclined(EE_Payment $payment, array $checkout_response)
411
-    {
412
-        $gateway_response = isset($checkout_response['L_ERRORCODE'])
413
-            ? $checkout_response['L_ERRORCODE'] . '; ' . $checkout_response['L_SHORTMESSAGE']
414
-            : esc_html__('Error occurred while trying to Capture the funds.', 'event_espresso');
415
-
416
-        $payment->set_gateway_response($gateway_response);
417
-        $payment->set_details($checkout_response);
418
-        $payment->set_status($this->_pay_model->declined_status());
419
-    }
420
-
421
-
422
-    /**
423
-     * @param EE_Payment $payment
424
-     * @param array $customer_data
425
-     * @throws EE_Error
426
-     * @since   $VID:$
427
-     */
428
-    private function paymentFailed(EE_Payment $payment, array $customer_data)
429
-    {
430
-        $gateway_response = isset($customer_data['L_ERRORCODE'])
431
-            ? $customer_data['L_ERRORCODE'] . '; ' . $customer_data['L_SHORTMESSAGE']
432
-            : esc_html__('Error occurred while trying to get payment Details from PayPal.', 'event_espresso');
433
-
434
-        $payment->set_gateway_response($gateway_response);
435
-        $payment->set_details($customer_data);
436
-        $payment->set_status($this->_pay_model->failed_status());
437
-    }
438
-
439
-
440
-    /**
441
-     * @param EE_Payment $payment
442
-     * @param string     $payment_token
443
-     * @param array      $customer_details
444
-     * @return void
445
-     * @throws EE_Error
446
-     * @throws ReflectionException
447
-     * @throws Exception
448
-     * @since   $VID:$
449
-     */
450
-    private function processPayment(EE_Payment $payment, string $payment_token, array $customer_details)
451
-    {
452
-        $checkout_request_dtls = [
453
-            'METHOD'                         => 'DoExpressCheckoutPayment',
454
-            'PAYERID'                        => $customer_details['PAYERID'],
455
-            'TOKEN'                          => $payment_token,
456
-            'PAYMENTREQUEST_0_PAYMENTACTION' => 'Sale',
457
-            'PAYMENTREQUEST_0_AMT'           => $payment->amount(),
458
-            'PAYMENTREQUEST_0_CURRENCYCODE'  => $payment->currency_code(),
459
-        ];
460
-        // Include itemized list.
461
-        $itemized_list         = $this->getOrderItems($payment, $customer_details);
462
-        $checkout_request_dtls = array_merge($checkout_request_dtls, $itemized_list);
463
-        // Payment Checkout/Capture.
464
-        $checkout_request_response = $this->_ppExpress_request(
465
-            $checkout_request_dtls,
466
-            'Do Payment',
467
-            $payment
468
-        );
469
-        $checkout_request_status   = $this->_ppExpress_check_response($checkout_request_response);
470
-        $checkout_response         =
471
-            isset($checkout_request_status['args']) && is_array($checkout_request_status['args'])
472
-                ? $checkout_request_status['args']
473
-                : [];
474
-        if ($checkout_request_status['status']) {
475
-            // All is well, payment approved.
476
-            $this->paymentApproved($payment, $checkout_response, $customer_details);
477
-        } else {
478
-            $this->paymentDeclined($payment, $checkout_response);
479
-        }
480
-    }
481
-
482
-
483
-    /**
484
-     * @param EE_Payment $payment
485
-     * @param string $payment_token
486
-     * @return array
487
-     * @throws EE_Error
488
-     * @since   $VID:$
489
-     */
490
-    private function requestCustomerDetails(EE_Payment $payment, string $payment_token): array
491
-    {
492
-        $customer_details_request_dtls = [
493
-            'METHOD' => 'GetExpressCheckoutDetails',
494
-            'TOKEN'  => $payment_token,
495
-        ];
496
-        // Request Customer Details.
497
-        $customer_details_request_response = $this->_ppExpress_request(
498
-            $customer_details_request_dtls,
499
-            'Customer Details',
500
-            $payment
501
-        );
502
-        $customer_details_rstatus          = $this->_ppExpress_check_response($customer_details_request_response);
503
-        $customer_details = isset($customer_details_rstatus['args']) && is_array($customer_details_rstatus['args'])
504
-            ? $customer_details_rstatus['args']
505
-            : [];
506
-        if (! $customer_details_rstatus['status']) {
507
-            $this->paymentFailed($payment, $customer_details);
508
-        }
509
-        return $customer_details;
510
-    }
511
-
512
-
513
-
514
-    /**
515
-     * @param EE_Payment|null $payment
516
-     * @return bool
517
-     * @throws EE_Error
518
-     * @since   $VID:$
519
-     */
520
-    private function validatePayment(?EE_Payment $payment): bool
521
-    {
522
-        if (! $payment instanceof EE_Payment) {
523
-            $payment = EE_Payment::new_instance();
524
-            $payment->set_gateway_response(
525
-                esc_html__(
526
-                    'An error occurred while trying to process the payment.',
527
-                    'event_espresso'
528
-                )
529
-            );
530
-            $payment->set_status($this->_pay_model->failed_status());
531
-            return false;
532
-        }
533
-        return true;
534
-    }
535
-
536
-
537
-    /**
538
-     * @param EE_Payment          $payment
539
-     * @param EE_Transaction|null $transaction
540
-     * @return bool
541
-     * @throws EE_Error
542
-     * @since   $VID:$
543
-     */
544
-    private function validateTransaction(EE_Payment $payment, ?EE_Transaction $transaction = null): bool
545
-    {
546
-        $transaction = $transaction ?? $payment->transaction();
547
-        if (! $transaction instanceof EE_Transaction) {
548
-            $payment->set_gateway_response(
549
-                esc_html__(
550
-                    'Could not process this payment because it has no associated transaction.',
551
-                    'event_espresso'
552
-                )
553
-            );
554
-            $payment->set_status($this->_pay_model->failed_status());
555
-            return false;
556
-        }
557
-        return true;
558
-    }
15
+	/**
16
+	 * Merchant API Username.
17
+	 *
18
+	 * @var string
19
+	 */
20
+	protected $_api_username;
21
+
22
+	/**
23
+	 * Merchant API Password.
24
+	 *
25
+	 * @var string
26
+	 */
27
+	protected $_api_password;
28
+
29
+	/**
30
+	 * API Signature.
31
+	 *
32
+	 * @var string
33
+	 */
34
+	protected $_api_signature;
35
+
36
+	/**
37
+	 * Request Shipping address on PP checkout page.
38
+	 *
39
+	 * @var string
40
+	 */
41
+	protected $_request_shipping_addr;
42
+
43
+	/**
44
+	 * Business/personal logo.
45
+	 *
46
+	 * @var string
47
+	 */
48
+	protected $_image_url = '';
49
+
50
+	/**
51
+	 * gateway URL variable
52
+	 *
53
+	 * @var string
54
+	 */
55
+	protected $_base_gateway_url = '';
56
+
57
+
58
+	/**
59
+	 * number of decimal places to round numbers to when performing calculations
60
+	 *
61
+	 * @var integer
62
+	 */
63
+	protected $decimal_precision = 6;
64
+
65
+	/**
66
+	 * @var ItemizedOrder
67
+	 * @since $VID:$
68
+	 */
69
+	protected $itemized_order;
70
+
71
+	/**
72
+	 * @var TokenRequest
73
+	 * @since $VID:$
74
+	 */
75
+	protected $token_request;
76
+
77
+
78
+	/**
79
+	 * EEG_Paypal_Express constructor.
80
+	 */
81
+	public function __construct()
82
+	{
83
+		require_once 'polyfills.php';
84
+		$this->_currencies_supported = [
85
+			'USD',
86
+			'AUD',
87
+			'BRL',
88
+			'CAD',
89
+			'CZK',
90
+			'DKK',
91
+			'EUR',
92
+			'HKD',
93
+			'HUF',
94
+			'ILS',
95
+			'JPY',
96
+			'MYR',
97
+			'MXN',
98
+			'NOK',
99
+			'NZD',
100
+			'PHP',
101
+			'PLN',
102
+			'GBP',
103
+			'RUB',
104
+			'SGD',
105
+			'SEK',
106
+			'CHF',
107
+			'TWD',
108
+			'THB',
109
+			'TRY',
110
+			'INR',
111
+		];
112
+		parent::__construct();
113
+		$this->decimal_precision = EE_Registry::instance()->CFG->currency->dec_plc;
114
+	}
115
+
116
+
117
+	/**
118
+	 * Sets the gateway URL variable based on whether debug mode is enabled or not.
119
+	 *
120
+	 * @param array $settings_array
121
+	 */
122
+	public function set_settings(array $settings_array)
123
+	{
124
+		parent::set_settings($settings_array);
125
+		// Redirect URL.
126
+		$this->_base_gateway_url = $this->_debug_mode
127
+			? 'https://api-3t.sandbox.paypal.com/nvp'
128
+			: 'https://api-3t.paypal.com/nvp';
129
+	}
130
+
131
+
132
+	/**
133
+	 * @param EE_Payment $payment
134
+	 * @param array       $billing_info
135
+	 * @param string      $return_url
136
+	 * @param string      $notify_url
137
+	 * @param string      $cancel_url
138
+	 * @return EE_Payment
139
+	 * @throws EE_Error
140
+	 * @throws ReflectionException
141
+	 * @throws Exception
142
+	 */
143
+	public function set_redirection_info(
144
+		$payment,
145
+		$billing_info = [],
146
+		$return_url = null,
147
+		$notify_url = null,
148
+		$cancel_url = null
149
+	) {
150
+		if (! $this->validatePayment($payment)) {
151
+			return $payment;
152
+		}
153
+		if (! $this->validateTransaction($payment)) {
154
+			return $payment;
155
+		}
156
+		$this->token_request = new TokenRequest($this->_get_gateway_formatter());
157
+		$token_request_details = apply_filters(
158
+			'FHEE__EEG_Paypal_Express__set_redirection_info__arguments',
159
+			$this->token_request->generateDetails(
160
+				$payment,
161
+				$this->getOrderItems($payment),
162
+				$return_url ?? '',
163
+				$cancel_url ?? '',
164
+				$this->_image_url ?? '',
165
+				$this->_request_shipping_addr ?? ''
166
+			),
167
+			$this
168
+		);
169
+		// Request PayPal token.
170
+		$token_request_response = $this->_ppExpress_request($token_request_details, 'Payment Token', $payment);
171
+		$token_request_status   = $this->_ppExpress_check_response($token_request_response);
172
+		$this->token_request->processResponse($payment, $token_request_status, $this->isInSandboxMode());
173
+
174
+		return $payment;
175
+	}
176
+
177
+
178
+	/**
179
+	 * @param array           $update_info {
180
+	 * @type string           $gateway_txn_id
181
+	 * @type string           $status      an EEMI_Payment status
182
+	 *                                     }
183
+	 * @param EE_Transaction $transaction
184
+	 * @return EE_Payment
185
+	 * @throws Exception
186
+	 */
187
+	public function handle_payment_update($update_info, $transaction): EE_Payment
188
+	{
189
+		// if the supplied transaction is valid, we'll retrieve the actual payment object from it
190
+		// but we'll use a temporary payment for now that we can return with errors if things go wrong
191
+		$payment = EE_Payment::new_instance();
192
+		if (! $this->validateTransaction($payment, $transaction)) {
193
+			return $payment;
194
+		}
195
+		$payment = $transaction->last_payment();
196
+		if (! $this->validatePayment($payment)) {
197
+			return $payment;
198
+		}
199
+		// payment appears to be good... so far
200
+		$this->log(['Return from Authorization' => $update_info], $payment);
201
+		$payment_token = $this->getPaymentToken($payment);
202
+		$customer_details = $this->requestCustomerDetails($payment, $payment_token);
203
+		// We got the PayerID so now we can Complete the transaction.
204
+		$this->processPayment($payment, $payment_token, $customer_details);
205
+
206
+		return $payment;
207
+	}
208
+
209
+
210
+	/**
211
+	 * @throws Exception
212
+	 */
213
+	private function getOrderItems(EE_Payment $payment, array $request_response_args = []): array
214
+	{
215
+		$this->itemized_order = new ItemizedOrder($this->_get_gateway_formatter());
216
+		try {
217
+			$itemized_order = $this->itemized_order->getExistingItemizedOrder($request_response_args);
218
+		} catch (Exception $exception) {
219
+			if (WP_DEBUG) {
220
+				throw $exception;
221
+			}
222
+			// Reset the list and log an error, maybe allow to try and generate a new list (below).
223
+			$itemized_order = [];
224
+			$this->log(
225
+				[
226
+					esc_html__(
227
+						'Could not generate a proper item list with:',
228
+						'event_espresso'
229
+					) => $request_response_args,
230
+				],
231
+				$payment
232
+			);
233
+		}
234
+		if (empty($itemized_order)) {
235
+			$itemized_order = $this->itemized_order->generateItemizedOrder($payment);
236
+		}
237
+		return $itemized_order;
238
+	}
239
+
240
+
241
+	/**
242
+	 *  Make the Express checkout request.
243
+	 *
244
+	 * @param array       $request_params
245
+	 * @param string      $request_text
246
+	 * @param EE_Payment $payment
247
+	 * @return array|WP_Error
248
+	 */
249
+	public function _ppExpress_request(array $request_params, string $request_text, EE_Payment $payment)
250
+	{
251
+		$request_dtls = [
252
+			'VERSION'      => '204.0',
253
+			'USER'         => $this->_api_username,
254
+			'PWD'          => $this->_api_password,
255
+			'SIGNATURE'    => $this->_api_signature,
256
+			// EE will blow up if you change this
257
+			'BUTTONSOURCE' => 'EventEspresso_SP',
258
+		];
259
+		$dtls         = array_merge($request_dtls, $request_params);
260
+		$this->_log_clean_request($dtls, $payment, $request_text . ' Request');
261
+		// Request Customer Details.
262
+		$request_response = wp_remote_post(
263
+			$this->_base_gateway_url,
264
+			[
265
+				'method'      => 'POST',
266
+				'timeout'     => 45,
267
+				'httpversion' => '1.1',
268
+				'cookies'     => [],
269
+				'headers'     => [],
270
+				'body'        => http_build_query($dtls),
271
+			]
272
+		);
273
+		// Log the response.
274
+		$this->log([$request_text . ' Response' => $request_response], $payment);
275
+		return $request_response;
276
+	}
277
+
278
+
279
+	/**
280
+	 *  Check the response status.
281
+	 *
282
+	 * @param mixed $request_response
283
+	 * @return array
284
+	 */
285
+	public function _ppExpress_check_response($request_response): array
286
+	{
287
+		if (is_wp_error($request_response) || empty($request_response['body'])) {
288
+			// If we got here then there was an error in this request.
289
+			return ['status' => false, 'args' => $request_response];
290
+		}
291
+		$response_args = [];
292
+		parse_str(urldecode($request_response['body']), $response_args);
293
+		if (! isset($response_args['ACK'])) {
294
+			return ['status' => false, 'args' => $request_response];
295
+		}
296
+		if (
297
+			(
298
+				isset($response_args['PAYERID'])
299
+				|| isset($response_args['TOKEN'])
300
+				|| isset($response_args['PAYMENTINFO_0_TRANSACTIONID'])
301
+				|| (isset($response_args['PAYMENTSTATUS']) && $response_args['PAYMENTSTATUS'] === 'Completed')
302
+			)
303
+			&& in_array($response_args['ACK'], ['Success', 'SuccessWithWarning'], true)
304
+		) {
305
+			// Response status OK, return response parameters for further processing.
306
+			return ['status' => true, 'args' => $response_args];
307
+		}
308
+		$errors = $this->_get_errors($response_args);
309
+		return ['status' => false, 'args' => $errors];
310
+	}
311
+
312
+
313
+	/**
314
+	 *  Log a "Cleared" request.
315
+	 *
316
+	 * @param array       $request
317
+	 * @param EE_Payment $payment
318
+	 * @param string      $info
319
+	 * @return void
320
+	 */
321
+	private function _log_clean_request(array $request, EE_Payment $payment, string $info)
322
+	{
323
+		$cleaned_request_data = $request;
324
+		unset($cleaned_request_data['PWD'], $cleaned_request_data['USER'], $cleaned_request_data['SIGNATURE']);
325
+		$this->log([$info => $cleaned_request_data], $payment);
326
+	}
327
+
328
+
329
+	/**
330
+	 *  Get error from the response data.
331
+	 *
332
+	 * @param array $data_array
333
+	 * @return array
334
+	 */
335
+	private function _get_errors(array $data_array): array
336
+	{
337
+		$errors = [];
338
+		$n      = 0;
339
+		while (isset($data_array[ "L_ERRORCODE{$n}" ])) {
340
+			$l_error_code    = $data_array[ "L_ERRORCODE{$n}" ] ?? '';
341
+			$l_severity_code = $data_array[ "L_SEVERITYCODE{$n}" ] ?? '';
342
+			$l_short_message = $data_array[ "L_SHORTMESSAGE{$n}" ] ?? '';
343
+			$l_long_message  = $data_array[ "L_LONGMESSAGE{$n}" ] ?? '';
344
+			if ($n === 0) {
345
+				$errors = [
346
+					'L_ERRORCODE'    => $l_error_code,
347
+					'L_SHORTMESSAGE' => $l_short_message,
348
+					'L_LONGMESSAGE'  => $l_long_message,
349
+					'L_SEVERITYCODE' => $l_severity_code,
350
+				];
351
+			} else {
352
+				$errors['L_ERRORCODE']    .= ', ' . $l_error_code;
353
+				$errors['L_SHORTMESSAGE'] .= ', ' . $l_short_message;
354
+				$errors['L_LONGMESSAGE']  .= ', ' . $l_long_message;
355
+				$errors['L_SEVERITYCODE'] .= ', ' . $l_severity_code;
356
+			}
357
+			$n++;
358
+		}
359
+		return $errors;
360
+	}
361
+
362
+
363
+	/**
364
+	 * @param EE_Payment $payment
365
+	 * @return mixed|null
366
+	 * @throws EE_Error
367
+	 * @since   $VID:$
368
+	 */
369
+	private function getPaymentToken(EE_Payment $payment)
370
+	{
371
+		$payment_details = $payment->details();
372
+		// Check if we still have the token.
373
+		if (! isset($payment_details['TOKEN']) || empty($payment_details['TOKEN'])) {
374
+			$payment->set_status($this->_pay_model->failed_status());
375
+			return null;
376
+		}
377
+		return $payment_details['TOKEN'];
378
+	}
379
+
380
+	/**
381
+	 * @param EE_Payment $payment
382
+	 * @param array      $checkout_response
383
+	 * @param array      $customer_data
384
+	 * @throws EE_Error
385
+	 * @throws ReflectionException
386
+	 * @since   $VID:$
387
+	 */
388
+	private function paymentApproved(EE_Payment $payment, array $checkout_response, array $customer_data)
389
+	{
390
+		$primary_registrant = $payment->transaction()->primary_registration();
391
+		$primary_registration_code = $primary_registrant instanceof EE_Registration ?
392
+			$primary_registrant->reg_code()
393
+			: '';
394
+		$payment->set_extra_accntng($primary_registration_code);
395
+		$payment_amount = $checkout_response['PAYMENTINFO_0_AMT'] ?? 0;
396
+		$payment->set_amount((float) $payment_amount);
397
+		$payment->set_txn_id_chq_nmbr($checkout_response['PAYMENTINFO_0_TRANSACTIONID'] ?? null);
398
+		$payment->set_details($customer_data);
399
+		$payment->set_gateway_response($checkout_response['PAYMENTINFO_0_ACK'] ?? '');
400
+		$payment->set_status($this->_pay_model->approved_status());
401
+	}
402
+
403
+
404
+	/**
405
+	 * @param EE_Payment $payment
406
+	 * @param array      $checkout_response
407
+	 * @throws EE_Error
408
+	 * @since   $VID:$
409
+	 */
410
+	private function paymentDeclined(EE_Payment $payment, array $checkout_response)
411
+	{
412
+		$gateway_response = isset($checkout_response['L_ERRORCODE'])
413
+			? $checkout_response['L_ERRORCODE'] . '; ' . $checkout_response['L_SHORTMESSAGE']
414
+			: esc_html__('Error occurred while trying to Capture the funds.', 'event_espresso');
415
+
416
+		$payment->set_gateway_response($gateway_response);
417
+		$payment->set_details($checkout_response);
418
+		$payment->set_status($this->_pay_model->declined_status());
419
+	}
420
+
421
+
422
+	/**
423
+	 * @param EE_Payment $payment
424
+	 * @param array $customer_data
425
+	 * @throws EE_Error
426
+	 * @since   $VID:$
427
+	 */
428
+	private function paymentFailed(EE_Payment $payment, array $customer_data)
429
+	{
430
+		$gateway_response = isset($customer_data['L_ERRORCODE'])
431
+			? $customer_data['L_ERRORCODE'] . '; ' . $customer_data['L_SHORTMESSAGE']
432
+			: esc_html__('Error occurred while trying to get payment Details from PayPal.', 'event_espresso');
433
+
434
+		$payment->set_gateway_response($gateway_response);
435
+		$payment->set_details($customer_data);
436
+		$payment->set_status($this->_pay_model->failed_status());
437
+	}
438
+
439
+
440
+	/**
441
+	 * @param EE_Payment $payment
442
+	 * @param string     $payment_token
443
+	 * @param array      $customer_details
444
+	 * @return void
445
+	 * @throws EE_Error
446
+	 * @throws ReflectionException
447
+	 * @throws Exception
448
+	 * @since   $VID:$
449
+	 */
450
+	private function processPayment(EE_Payment $payment, string $payment_token, array $customer_details)
451
+	{
452
+		$checkout_request_dtls = [
453
+			'METHOD'                         => 'DoExpressCheckoutPayment',
454
+			'PAYERID'                        => $customer_details['PAYERID'],
455
+			'TOKEN'                          => $payment_token,
456
+			'PAYMENTREQUEST_0_PAYMENTACTION' => 'Sale',
457
+			'PAYMENTREQUEST_0_AMT'           => $payment->amount(),
458
+			'PAYMENTREQUEST_0_CURRENCYCODE'  => $payment->currency_code(),
459
+		];
460
+		// Include itemized list.
461
+		$itemized_list         = $this->getOrderItems($payment, $customer_details);
462
+		$checkout_request_dtls = array_merge($checkout_request_dtls, $itemized_list);
463
+		// Payment Checkout/Capture.
464
+		$checkout_request_response = $this->_ppExpress_request(
465
+			$checkout_request_dtls,
466
+			'Do Payment',
467
+			$payment
468
+		);
469
+		$checkout_request_status   = $this->_ppExpress_check_response($checkout_request_response);
470
+		$checkout_response         =
471
+			isset($checkout_request_status['args']) && is_array($checkout_request_status['args'])
472
+				? $checkout_request_status['args']
473
+				: [];
474
+		if ($checkout_request_status['status']) {
475
+			// All is well, payment approved.
476
+			$this->paymentApproved($payment, $checkout_response, $customer_details);
477
+		} else {
478
+			$this->paymentDeclined($payment, $checkout_response);
479
+		}
480
+	}
481
+
482
+
483
+	/**
484
+	 * @param EE_Payment $payment
485
+	 * @param string $payment_token
486
+	 * @return array
487
+	 * @throws EE_Error
488
+	 * @since   $VID:$
489
+	 */
490
+	private function requestCustomerDetails(EE_Payment $payment, string $payment_token): array
491
+	{
492
+		$customer_details_request_dtls = [
493
+			'METHOD' => 'GetExpressCheckoutDetails',
494
+			'TOKEN'  => $payment_token,
495
+		];
496
+		// Request Customer Details.
497
+		$customer_details_request_response = $this->_ppExpress_request(
498
+			$customer_details_request_dtls,
499
+			'Customer Details',
500
+			$payment
501
+		);
502
+		$customer_details_rstatus          = $this->_ppExpress_check_response($customer_details_request_response);
503
+		$customer_details = isset($customer_details_rstatus['args']) && is_array($customer_details_rstatus['args'])
504
+			? $customer_details_rstatus['args']
505
+			: [];
506
+		if (! $customer_details_rstatus['status']) {
507
+			$this->paymentFailed($payment, $customer_details);
508
+		}
509
+		return $customer_details;
510
+	}
511
+
512
+
513
+
514
+	/**
515
+	 * @param EE_Payment|null $payment
516
+	 * @return bool
517
+	 * @throws EE_Error
518
+	 * @since   $VID:$
519
+	 */
520
+	private function validatePayment(?EE_Payment $payment): bool
521
+	{
522
+		if (! $payment instanceof EE_Payment) {
523
+			$payment = EE_Payment::new_instance();
524
+			$payment->set_gateway_response(
525
+				esc_html__(
526
+					'An error occurred while trying to process the payment.',
527
+					'event_espresso'
528
+				)
529
+			);
530
+			$payment->set_status($this->_pay_model->failed_status());
531
+			return false;
532
+		}
533
+		return true;
534
+	}
535
+
536
+
537
+	/**
538
+	 * @param EE_Payment          $payment
539
+	 * @param EE_Transaction|null $transaction
540
+	 * @return bool
541
+	 * @throws EE_Error
542
+	 * @since   $VID:$
543
+	 */
544
+	private function validateTransaction(EE_Payment $payment, ?EE_Transaction $transaction = null): bool
545
+	{
546
+		$transaction = $transaction ?? $payment->transaction();
547
+		if (! $transaction instanceof EE_Transaction) {
548
+			$payment->set_gateway_response(
549
+				esc_html__(
550
+					'Could not process this payment because it has no associated transaction.',
551
+					'event_espresso'
552
+				)
553
+			);
554
+			$payment->set_status($this->_pay_model->failed_status());
555
+			return false;
556
+		}
557
+		return true;
558
+	}
559 559
 }
Please login to merge, or discard this patch.
modules/ticket_selector/DisplayTicketSelector.php 1 patch
Indentation   +863 added lines, -863 removed lines patch added patch discarded remove patch
@@ -40,870 +40,870 @@
 block discarded – undo
40 40
  */
41 41
 class DisplayTicketSelector
42 42
 {
43
-    /**
44
-     * @var RequestInterface
45
-     */
46
-    protected $request;
47
-
48
-    /**
49
-     * @var EE_Ticket_Selector_Config
50
-     */
51
-    protected $config;
52
-
53
-    /**
54
-     * event that ticket selector is being generated for
55
-     *
56
-     * @access protected
57
-     * @var EE_Event $event
58
-     */
59
-    protected $event;
60
-
61
-    /**
62
-     * Used to flag when the ticket selector is being called from an external iframe.
63
-     *
64
-     * @var bool $iframe
65
-     */
66
-    protected $iframe = false;
67
-
68
-    /**
69
-     * max attendees that can register for event at one time
70
-     *
71
-     * @var int $max_attendees
72
-     */
73
-    private $max_attendees = EE_INF;
74
-
75
-    /**
76
-     * @var string $date_format
77
-     */
78
-    private $date_format;
79
-
80
-    /**
81
-     * @var string $time_format
82
-     */
83
-    private $time_format;
84
-
85
-    /**
86
-     * @var boolean $display_full_ui
87
-     */
88
-    private $display_full_ui;
89
-
90
-    /**
91
-     * @var CurrentUser
92
-     */
93
-    private $current_user;
94
-
95
-
96
-    /**
97
-     * DisplayTicketSelector constructor.
98
-     *
99
-     * @param CurrentUser $current_user
100
-     * @param RequestInterface          $request
101
-     * @param EE_Ticket_Selector_Config $config
102
-     * @param bool                      $iframe
103
-     */
104
-    public function __construct(
105
-        CurrentUser $current_user,
106
-        RequestInterface $request,
107
-        EE_Ticket_Selector_Config $config,
108
-        bool $iframe = false
109
-    ) {
110
-        $this->current_user = $current_user;
111
-        $this->request     = $request;
112
-        $this->config      = $config;
113
-        $this->setIframe($iframe);
114
-        $this->date_format = apply_filters(
115
-            'FHEE__EED_Ticket_Selector__display_ticket_selector__date_format',
116
-            get_option('date_format')
117
-        );
118
-        $this->time_format  = apply_filters(
119
-            'FHEE__EED_Ticket_Selector__display_ticket_selector__time_format',
120
-            get_option('time_format')
121
-        );
122
-    }
123
-
124
-
125
-    /**
126
-     * @return bool
127
-     */
128
-    public function isIframe(): bool
129
-    {
130
-        return $this->iframe;
131
-    }
132
-
133
-
134
-    /**
135
-     * @param boolean $iframe
136
-     */
137
-    public function setIframe(bool $iframe = true)
138
-    {
139
-        $this->iframe = filter_var($iframe, FILTER_VALIDATE_BOOLEAN);
140
-    }
141
-
142
-
143
-    /**
144
-     * finds and sets the \EE_Event object for use throughout class
145
-     *
146
-     * @param mixed $event
147
-     * @return bool
148
-     * @throws EE_Error
149
-     * @throws InvalidDataTypeException
150
-     * @throws InvalidInterfaceException
151
-     * @throws InvalidArgumentException
152
-     */
153
-    protected function setEvent($event = null): bool
154
-    {
155
-        if ($event === null) {
156
-            global $post;
157
-            $event = $post;
158
-        }
159
-        if ($event instanceof EE_Event) {
160
-            $this->event = $event;
161
-        } elseif ($event instanceof WP_Post) {
162
-            if (isset($event->EE_Event) && $event->EE_Event instanceof EE_Event) {
163
-                $this->event = $event->EE_Event;
164
-            } elseif ($event->post_type === 'espresso_events') {
165
-                $event->EE_Event = EEM_Event::instance()->instantiate_class_from_post_object($event);
166
-                $this->event     = $event->EE_Event;
167
-            }
168
-        } else {
169
-            $user_msg = esc_html__('No Event object or an invalid Event object was supplied.', 'event_espresso');
170
-            $dev_msg  = $user_msg . esc_html__(
171
-                'In order to generate a ticket selector, please ensure you are passing either an EE_Event object or a WP_Post object of the post type "espresso_event" to the EE_Ticket_Selector class constructor.',
172
-                'event_espresso'
173
-            );
174
-            EE_Error::add_error($user_msg . '||' . $dev_msg, __FILE__, __FUNCTION__, __LINE__);
175
-            return false;
176
-        }
177
-        return true;
178
-    }
179
-
180
-
181
-    /**
182
-     * @return int
183
-     */
184
-    public function getMaxAttendees(): int
185
-    {
186
-        return $this->max_attendees;
187
-    }
188
-
189
-
190
-    /**
191
-     * @param int $max_attendees
192
-     */
193
-    public function setMaxAttendees(int $max_attendees)
194
-    {
195
-        $this->max_attendees = absint(
196
-            apply_filters(
197
-                'FHEE__EE_Ticket_Selector__display_ticket_selector__max_tickets',
198
-                $max_attendees
199
-            )
200
-        );
201
-    }
202
-
203
-
204
-    /**
205
-     * Returns whether or not the full ticket selector should be shown or not.
206
-     * Currently, it displays on the frontend (including ajax requests) but not the backend
207
-     *
208
-     * @return bool
209
-     */
210
-    private function display_full_ui(): bool
211
-    {
212
-        if ($this->display_full_ui === null) {
213
-            $this->display_full_ui = ! is_admin() || (defined('DOING_AJAX') && DOING_AJAX);
214
-        }
215
-        return $this->display_full_ui;
216
-    }
217
-
218
-
219
-    /**
220
-     * creates buttons for selecting number of attendees for an event
221
-     *
222
-     * @param WP_Post|int $event
223
-     * @param bool        $view_details
224
-     * @return string
225
-     * @throws EE_Error
226
-     * @throws InvalidArgumentException
227
-     * @throws InvalidDataTypeException
228
-     * @throws InvalidInterfaceException
229
-     * @throws ReflectionException
230
-     * @throws Exception
231
-     */
232
-    public function display($event = null, bool $view_details = false)
233
-    {
234
-        // reset filter for displaying submit button
235
-        remove_filter('FHEE__EE_Ticket_Selector__display_ticket_selector_submit', '__return_true');
236
-        // poke and prod incoming event till it tells us what it is
237
-        if (! $this->setEvent($event)) {
238
-            return $this->handleMissingEvent();
239
-        }
240
-        // is the event expired ?
241
-        $template_args['event_is_expired'] = ! is_admin() && $this->event->is_expired();
242
-        if ($template_args['event_is_expired']) {
243
-            return is_single()
244
-                ? $this->expiredEventMessage()
245
-                : $this->expiredEventMessage() . $this->displayViewDetailsButton();
246
-        }
247
-        // begin gathering template arguments by getting event status
248
-        $template_args = ['event_status' => $this->event->get_active_status()];
249
-        if (
250
-            $this->activeEventAndShowTicketSelector(
251
-                $event,
252
-                $template_args['event_status'],
253
-                $view_details
254
-            )
255
-        ) {
256
-            return ! is_single() ? $this->displayViewDetailsButton() : '';
257
-        }
258
-        // filter the maximum qty that can appear in the Ticket Selector qty dropdowns
259
-        $this->setMaxAttendees($this->event->additional_limit());
260
-        if ($this->getMaxAttendees() < 1) {
261
-            return $this->ticketSalesClosedMessage();
262
-        }
263
-        // get all tickets for this event ordered by the datetime
264
-        $tickets = $this->getTickets();
265
-        if (count($tickets) < 1) {
266
-            return $this->noTicketAvailableMessage();
267
-        }
268
-        // redirecting to another site for registration ??
269
-        $external_url = (string) $this->event->external_url()
270
-                        && $this->event->external_url() !== get_the_permalink()
271
-            ? $this->event->external_url()
272
-            : '';
273
-        // if redirecting to another site for registration, then we don't load the TS
274
-        $ticket_selector = $external_url
275
-            ? $this->externalEventRegistration()
276
-            : $this->loadTicketSelector($tickets, $template_args);
277
-        // now set up the form (but not for the admin)
278
-        $ticket_selector = $this->display_full_ui()
279
-            ? $this->formOpen($this->event->ID(), $external_url) . $ticket_selector
280
-            : $ticket_selector;
281
-        // submit button and form close tag
282
-        $ticket_selector .= $this->display_full_ui() ? $this->displaySubmitButton($external_url) : '';
283
-        return $ticket_selector;
284
-    }
285
-
286
-
287
-    /**
288
-     * displayTicketSelector
289
-     * examines the event properties and determines whether a Ticket Selector should be displayed
290
-     *
291
-     * @param WP_Post|int $event
292
-     * @param string      $_event_active_status
293
-     * @param bool        $view_details
294
-     * @return bool
295
-     * @throws EE_Error
296
-     * @throws ReflectionException
297
-     */
298
-    protected function activeEventAndShowTicketSelector($event, string $_event_active_status, bool $view_details): bool
299
-    {
300
-        $event_post = $this->event instanceof EE_Event ? $this->event->ID() : $event;
301
-        return $this->display_full_ui()
302
-               && (
303
-                   ! $this->event->display_ticket_selector()
304
-                   || $view_details
305
-                   || post_password_required($event_post)
306
-                   || (
307
-                       $_event_active_status !== EE_Datetime::active
308
-                       && $_event_active_status !== EE_Datetime::upcoming
309
-                       && $_event_active_status !== EE_Datetime::sold_out
310
-                       && ! (
311
-                           $_event_active_status === EE_Datetime::inactive
312
-                           && is_user_logged_in()
313
-                       )
314
-                   )
315
-               );
316
-    }
317
-
318
-
319
-    /**
320
-     * noTicketAvailableMessage
321
-     * notice displayed if event is expired
322
-     *
323
-     * @return string
324
-     */
325
-    protected function expiredEventMessage(): string
326
-    {
327
-        return '<div class="ee-event-expired-notice"><span class="important-notice">'
328
-           . esc_html__(
329
-               'We\'re sorry, but all tickets sales have ended because the event is expired.',
330
-               'event_espresso'
331
-           )
332
-           . '</span></div><!-- .ee-event-expired-notice -->';
333
-    }
334
-
335
-
336
-    /**
337
-     * noTicketAvailableMessage
338
-     * notice displayed if event has no more tickets available
339
-     *
340
-     * @return string
341
-     * @throws EE_Error
342
-     * @throws ReflectionException
343
-     */
344
-    protected function noTicketAvailableMessage(): string
345
-    {
346
-        $no_ticket_available_msg = esc_html__('We\'re sorry, but all ticket sales have ended.', 'event_espresso');
347
-        if (current_user_can('edit_post', $this->event->ID())) {
348
-            $no_ticket_available_msg .= sprintf(
349
-                esc_html__(
350
-                    '%1$sNote to Event Admin:%2$sNo tickets were found for this event. This effectively turns off ticket sales. Please ensure that at least one ticket is available for if you want people to be able to register.%3$s(click to edit this event)%4$s',
351
-                    'event_espresso'
352
-                ),
353
-                '<div class="ee-attention" style="text-align: left;"><b>',
354
-                '</b><br />',
355
-                '<span class="edit-link"><a class="post-edit-link" href="'
356
-                . get_edit_post_link($this->event->ID())
357
-                . '">',
358
-                '</a></span></div><!-- .ee-attention noTicketAvailableMessage -->'
359
-            );
360
-        }
361
-        return '
43
+	/**
44
+	 * @var RequestInterface
45
+	 */
46
+	protected $request;
47
+
48
+	/**
49
+	 * @var EE_Ticket_Selector_Config
50
+	 */
51
+	protected $config;
52
+
53
+	/**
54
+	 * event that ticket selector is being generated for
55
+	 *
56
+	 * @access protected
57
+	 * @var EE_Event $event
58
+	 */
59
+	protected $event;
60
+
61
+	/**
62
+	 * Used to flag when the ticket selector is being called from an external iframe.
63
+	 *
64
+	 * @var bool $iframe
65
+	 */
66
+	protected $iframe = false;
67
+
68
+	/**
69
+	 * max attendees that can register for event at one time
70
+	 *
71
+	 * @var int $max_attendees
72
+	 */
73
+	private $max_attendees = EE_INF;
74
+
75
+	/**
76
+	 * @var string $date_format
77
+	 */
78
+	private $date_format;
79
+
80
+	/**
81
+	 * @var string $time_format
82
+	 */
83
+	private $time_format;
84
+
85
+	/**
86
+	 * @var boolean $display_full_ui
87
+	 */
88
+	private $display_full_ui;
89
+
90
+	/**
91
+	 * @var CurrentUser
92
+	 */
93
+	private $current_user;
94
+
95
+
96
+	/**
97
+	 * DisplayTicketSelector constructor.
98
+	 *
99
+	 * @param CurrentUser $current_user
100
+	 * @param RequestInterface          $request
101
+	 * @param EE_Ticket_Selector_Config $config
102
+	 * @param bool                      $iframe
103
+	 */
104
+	public function __construct(
105
+		CurrentUser $current_user,
106
+		RequestInterface $request,
107
+		EE_Ticket_Selector_Config $config,
108
+		bool $iframe = false
109
+	) {
110
+		$this->current_user = $current_user;
111
+		$this->request     = $request;
112
+		$this->config      = $config;
113
+		$this->setIframe($iframe);
114
+		$this->date_format = apply_filters(
115
+			'FHEE__EED_Ticket_Selector__display_ticket_selector__date_format',
116
+			get_option('date_format')
117
+		);
118
+		$this->time_format  = apply_filters(
119
+			'FHEE__EED_Ticket_Selector__display_ticket_selector__time_format',
120
+			get_option('time_format')
121
+		);
122
+	}
123
+
124
+
125
+	/**
126
+	 * @return bool
127
+	 */
128
+	public function isIframe(): bool
129
+	{
130
+		return $this->iframe;
131
+	}
132
+
133
+
134
+	/**
135
+	 * @param boolean $iframe
136
+	 */
137
+	public function setIframe(bool $iframe = true)
138
+	{
139
+		$this->iframe = filter_var($iframe, FILTER_VALIDATE_BOOLEAN);
140
+	}
141
+
142
+
143
+	/**
144
+	 * finds and sets the \EE_Event object for use throughout class
145
+	 *
146
+	 * @param mixed $event
147
+	 * @return bool
148
+	 * @throws EE_Error
149
+	 * @throws InvalidDataTypeException
150
+	 * @throws InvalidInterfaceException
151
+	 * @throws InvalidArgumentException
152
+	 */
153
+	protected function setEvent($event = null): bool
154
+	{
155
+		if ($event === null) {
156
+			global $post;
157
+			$event = $post;
158
+		}
159
+		if ($event instanceof EE_Event) {
160
+			$this->event = $event;
161
+		} elseif ($event instanceof WP_Post) {
162
+			if (isset($event->EE_Event) && $event->EE_Event instanceof EE_Event) {
163
+				$this->event = $event->EE_Event;
164
+			} elseif ($event->post_type === 'espresso_events') {
165
+				$event->EE_Event = EEM_Event::instance()->instantiate_class_from_post_object($event);
166
+				$this->event     = $event->EE_Event;
167
+			}
168
+		} else {
169
+			$user_msg = esc_html__('No Event object or an invalid Event object was supplied.', 'event_espresso');
170
+			$dev_msg  = $user_msg . esc_html__(
171
+				'In order to generate a ticket selector, please ensure you are passing either an EE_Event object or a WP_Post object of the post type "espresso_event" to the EE_Ticket_Selector class constructor.',
172
+				'event_espresso'
173
+			);
174
+			EE_Error::add_error($user_msg . '||' . $dev_msg, __FILE__, __FUNCTION__, __LINE__);
175
+			return false;
176
+		}
177
+		return true;
178
+	}
179
+
180
+
181
+	/**
182
+	 * @return int
183
+	 */
184
+	public function getMaxAttendees(): int
185
+	{
186
+		return $this->max_attendees;
187
+	}
188
+
189
+
190
+	/**
191
+	 * @param int $max_attendees
192
+	 */
193
+	public function setMaxAttendees(int $max_attendees)
194
+	{
195
+		$this->max_attendees = absint(
196
+			apply_filters(
197
+				'FHEE__EE_Ticket_Selector__display_ticket_selector__max_tickets',
198
+				$max_attendees
199
+			)
200
+		);
201
+	}
202
+
203
+
204
+	/**
205
+	 * Returns whether or not the full ticket selector should be shown or not.
206
+	 * Currently, it displays on the frontend (including ajax requests) but not the backend
207
+	 *
208
+	 * @return bool
209
+	 */
210
+	private function display_full_ui(): bool
211
+	{
212
+		if ($this->display_full_ui === null) {
213
+			$this->display_full_ui = ! is_admin() || (defined('DOING_AJAX') && DOING_AJAX);
214
+		}
215
+		return $this->display_full_ui;
216
+	}
217
+
218
+
219
+	/**
220
+	 * creates buttons for selecting number of attendees for an event
221
+	 *
222
+	 * @param WP_Post|int $event
223
+	 * @param bool        $view_details
224
+	 * @return string
225
+	 * @throws EE_Error
226
+	 * @throws InvalidArgumentException
227
+	 * @throws InvalidDataTypeException
228
+	 * @throws InvalidInterfaceException
229
+	 * @throws ReflectionException
230
+	 * @throws Exception
231
+	 */
232
+	public function display($event = null, bool $view_details = false)
233
+	{
234
+		// reset filter for displaying submit button
235
+		remove_filter('FHEE__EE_Ticket_Selector__display_ticket_selector_submit', '__return_true');
236
+		// poke and prod incoming event till it tells us what it is
237
+		if (! $this->setEvent($event)) {
238
+			return $this->handleMissingEvent();
239
+		}
240
+		// is the event expired ?
241
+		$template_args['event_is_expired'] = ! is_admin() && $this->event->is_expired();
242
+		if ($template_args['event_is_expired']) {
243
+			return is_single()
244
+				? $this->expiredEventMessage()
245
+				: $this->expiredEventMessage() . $this->displayViewDetailsButton();
246
+		}
247
+		// begin gathering template arguments by getting event status
248
+		$template_args = ['event_status' => $this->event->get_active_status()];
249
+		if (
250
+			$this->activeEventAndShowTicketSelector(
251
+				$event,
252
+				$template_args['event_status'],
253
+				$view_details
254
+			)
255
+		) {
256
+			return ! is_single() ? $this->displayViewDetailsButton() : '';
257
+		}
258
+		// filter the maximum qty that can appear in the Ticket Selector qty dropdowns
259
+		$this->setMaxAttendees($this->event->additional_limit());
260
+		if ($this->getMaxAttendees() < 1) {
261
+			return $this->ticketSalesClosedMessage();
262
+		}
263
+		// get all tickets for this event ordered by the datetime
264
+		$tickets = $this->getTickets();
265
+		if (count($tickets) < 1) {
266
+			return $this->noTicketAvailableMessage();
267
+		}
268
+		// redirecting to another site for registration ??
269
+		$external_url = (string) $this->event->external_url()
270
+						&& $this->event->external_url() !== get_the_permalink()
271
+			? $this->event->external_url()
272
+			: '';
273
+		// if redirecting to another site for registration, then we don't load the TS
274
+		$ticket_selector = $external_url
275
+			? $this->externalEventRegistration()
276
+			: $this->loadTicketSelector($tickets, $template_args);
277
+		// now set up the form (but not for the admin)
278
+		$ticket_selector = $this->display_full_ui()
279
+			? $this->formOpen($this->event->ID(), $external_url) . $ticket_selector
280
+			: $ticket_selector;
281
+		// submit button and form close tag
282
+		$ticket_selector .= $this->display_full_ui() ? $this->displaySubmitButton($external_url) : '';
283
+		return $ticket_selector;
284
+	}
285
+
286
+
287
+	/**
288
+	 * displayTicketSelector
289
+	 * examines the event properties and determines whether a Ticket Selector should be displayed
290
+	 *
291
+	 * @param WP_Post|int $event
292
+	 * @param string      $_event_active_status
293
+	 * @param bool        $view_details
294
+	 * @return bool
295
+	 * @throws EE_Error
296
+	 * @throws ReflectionException
297
+	 */
298
+	protected function activeEventAndShowTicketSelector($event, string $_event_active_status, bool $view_details): bool
299
+	{
300
+		$event_post = $this->event instanceof EE_Event ? $this->event->ID() : $event;
301
+		return $this->display_full_ui()
302
+			   && (
303
+				   ! $this->event->display_ticket_selector()
304
+				   || $view_details
305
+				   || post_password_required($event_post)
306
+				   || (
307
+					   $_event_active_status !== EE_Datetime::active
308
+					   && $_event_active_status !== EE_Datetime::upcoming
309
+					   && $_event_active_status !== EE_Datetime::sold_out
310
+					   && ! (
311
+						   $_event_active_status === EE_Datetime::inactive
312
+						   && is_user_logged_in()
313
+					   )
314
+				   )
315
+			   );
316
+	}
317
+
318
+
319
+	/**
320
+	 * noTicketAvailableMessage
321
+	 * notice displayed if event is expired
322
+	 *
323
+	 * @return string
324
+	 */
325
+	protected function expiredEventMessage(): string
326
+	{
327
+		return '<div class="ee-event-expired-notice"><span class="important-notice">'
328
+		   . esc_html__(
329
+			   'We\'re sorry, but all tickets sales have ended because the event is expired.',
330
+			   'event_espresso'
331
+		   )
332
+		   . '</span></div><!-- .ee-event-expired-notice -->';
333
+	}
334
+
335
+
336
+	/**
337
+	 * noTicketAvailableMessage
338
+	 * notice displayed if event has no more tickets available
339
+	 *
340
+	 * @return string
341
+	 * @throws EE_Error
342
+	 * @throws ReflectionException
343
+	 */
344
+	protected function noTicketAvailableMessage(): string
345
+	{
346
+		$no_ticket_available_msg = esc_html__('We\'re sorry, but all ticket sales have ended.', 'event_espresso');
347
+		if (current_user_can('edit_post', $this->event->ID())) {
348
+			$no_ticket_available_msg .= sprintf(
349
+				esc_html__(
350
+					'%1$sNote to Event Admin:%2$sNo tickets were found for this event. This effectively turns off ticket sales. Please ensure that at least one ticket is available for if you want people to be able to register.%3$s(click to edit this event)%4$s',
351
+					'event_espresso'
352
+				),
353
+				'<div class="ee-attention" style="text-align: left;"><b>',
354
+				'</b><br />',
355
+				'<span class="edit-link"><a class="post-edit-link" href="'
356
+				. get_edit_post_link($this->event->ID())
357
+				. '">',
358
+				'</a></span></div><!-- .ee-attention noTicketAvailableMessage -->'
359
+			);
360
+		}
361
+		return '
362 362
             <div class="ee-event-expired-notice">
363 363
                 <span class="important-notice">' . $no_ticket_available_msg . '</span>
364 364
             </div><!-- .ee-event-expired-notice -->';
365
-    }
366
-
367
-
368
-    /**
369
-     * ticketSalesClosed
370
-     * notice displayed if event ticket sales are turned off
371
-     *
372
-     * @return string
373
-     * @throws EE_Error
374
-     * @throws ReflectionException
375
-     */
376
-    protected function ticketSalesClosedMessage(): string
377
-    {
378
-        $sales_closed_msg = esc_html__(
379
-            'We\'re sorry, but ticket sales have been closed at this time. Please check back again later.',
380
-            'event_espresso'
381
-        );
382
-        if (current_user_can('edit_post', $this->event->ID())) {
383
-            $sales_closed_msg .= sprintf(
384
-                esc_html__(
385
-                    '%sNote to Event Admin:%sThe "Maximum number of tickets allowed per order for this event" in the Event Registration Options has been set to "0". This effectively turns off ticket sales. %s(click to edit this event)%s',
386
-                    'event_espresso'
387
-                ),
388
-                '<div class="ee-attention" style="text-align: left;"><b>',
389
-                '</b><br />',
390
-                '<span class="edit-link"><a class="post-edit-link" href="'
391
-                . get_edit_post_link($this->event->ID())
392
-                . '">',
393
-                '</a></span></div><!-- .ee-attention ticketSalesClosedMessage -->'
394
-            );
395
-        }
396
-        return '<p><span class="important-notice">' . $sales_closed_msg . '</span></p>';
397
-    }
398
-
399
-
400
-    /**
401
-     * getTickets
402
-     *
403
-     * @return EE_Base_Class[]|EE_Ticket[]
404
-     * @throws EE_Error
405
-     * @throws InvalidDataTypeException
406
-     * @throws InvalidInterfaceException
407
-     * @throws InvalidArgumentException
408
-     * @throws ReflectionException
409
-     */
410
-    protected function getTickets()
411
-    {
412
-        $show_expired_tickets = is_admin() || $this->config->show_expired_tickets;
413
-
414
-        $ticket_query_args = [
415
-            [
416
-                'Datetime.EVT_ID' => $this->event->ID(),
417
-                'TKT_visibility'  => ['>', EEM_Ticket::TICKET_VISIBILITY_NONE_VALUE],
418
-            ],
419
-            'order_by' => [
420
-                'TKT_order'              => 'ASC',
421
-                'TKT_required'           => 'DESC',
422
-                'TKT_start_date'         => 'ASC',
423
-                'TKT_end_date'           => 'ASC',
424
-                'Datetime.DTT_EVT_start' => 'DESC',
425
-            ],
426
-        ];
427
-
428
-        $datetime_id = $this->request->getRequestParam('datetime', 0, 'int');
429
-        if ($datetime_id) {
430
-            $ticket_query_args[0]['Datetime.DTT_ID'] = $datetime_id;
431
-        }
432
-
433
-        if (! $show_expired_tickets) {
434
-            // use the correct applicable time query depending on what version of core is being run.
435
-            $current_time                         = method_exists('EEM_Datetime', 'current_time_for_query')
436
-                ? time()
437
-                : current_time('timestamp');
438
-            $ticket_query_args[0]['TKT_end_date'] = ['>', $current_time];
439
-        }
440
-        /** @var EE_Ticket[] $tickets */
441
-        $tickets = EEM_Ticket::instance()->get_all($ticket_query_args);
442
-        // remove tickets based on their visibility and the current user's allowed access (crudely based on roles)
443
-        // and filter the returned results
444
-         $tickets = array_filter($tickets, [$this, 'ticketVisibilityFilter']);
445
-        return (array) apply_filters(
446
-            'FHEE__EventEspresso_modules_ticketSelector_DisplayTicketSelector__getTickets',
447
-            $tickets,
448
-            $ticket_query_args,
449
-            $this
450
-        );
451
-    }
452
-
453
-
454
-    /**
455
-     * returns true if any of the following is true:
456
-     *  - ticket visibility is PUBLIC
457
-     *  - ticket visibility is MEMBERS_ONLY and user is logged in
458
-     *  - ticket visibility is ADMINS_ONLY when user IS logged in as an admin
459
-     *  - ticket visibility is ADMIN_UI_ONLY when ticket selector is being viewed via an admin page UI
460
-     *
461
-     * @param EE_Ticket $ticket
462
-     * @return bool
463
-     * @throws EE_Error
464
-     * @throws ReflectionException
465
-     * @since   $VID:$
466
-     */
467
-    public function ticketVisibilityFilter(EE_Ticket $ticket): bool
468
-    {
469
-        return $ticket->isPublicOnly()
470
-               || ($ticket->isMembersOnly() && $this->current_user->isLoggedIn())
471
-               || ($ticket->isAdminsOnly() && $this->current_user->isEventManager())
472
-               || ($ticket->isAdminUiOnly() && is_admin());
473
-    }
474
-
475
-
476
-    /**
477
-     * loadTicketSelector
478
-     * begins to assemble template arguments
479
-     * and decides whether to load a "simple" ticket selector, or the standard
480
-     *
481
-     * @param EE_Ticket[] $tickets
482
-     * @param array       $template_args
483
-     * @return TicketSelectorSimple|TicketSelectorStandard
484
-     * @throws EE_Error
485
-     * @throws ReflectionException
486
-     */
487
-    protected function loadTicketSelector(array $tickets, array $template_args)
488
-    {
489
-        $template_args['event']            = $this->event;
490
-        $template_args['EVT_ID']           = $this->event->ID();
491
-        $template_args['event_is_expired'] = $this->event->is_expired();
492
-        $template_args['max_atndz']        = $this->getMaxAttendees();
493
-        $template_args['date_format']      = $this->date_format;
494
-        $template_args['time_format']      = $this->time_format;
495
-        /**
496
-         * Filters the anchor ID used when redirecting to the Ticket Selector if no quantity selected
497
-         *
498
-         * @param string  '#tkt-slctr-tbl-' . $EVT_ID The html ID to anchor to
499
-         * @param int $EVT_ID The Event ID
500
-         * @since 4.9.13
501
-         */
502
-        $template_args['anchor_id']    = apply_filters(
503
-            'FHEE__EE_Ticket_Selector__redirect_anchor_id',
504
-            '#tkt-slctr-tbl-' . $this->event->ID(),
505
-            $this->event->ID()
506
-        );
507
-        $template_args['tickets']      = $tickets;
508
-        $template_args['ticket_count'] = count($tickets);
509
-        $ticket_selector               = $this->simpleTicketSelector($tickets, $template_args);
510
-        if ($ticket_selector instanceof TicketSelectorSimple) {
511
-            return $ticket_selector;
512
-        }
513
-        return new TicketSelectorStandard(
514
-            $this->config,
515
-            $this->getTaxConfig(),
516
-            $this->event,
517
-            $tickets,
518
-            $this->getMaxAttendees(),
519
-            $template_args,
520
-            $this->date_format,
521
-            $this->time_format
522
-        );
523
-    }
524
-
525
-
526
-    /**
527
-     * simpleTicketSelector
528
-     * there's one ticket, and max attendees is set to one,
529
-     * so if the event is free, then this is a "simple" ticket selector
530
-     * a.k.a. "Dude Where's my Ticket Selector?"
531
-     *
532
-     * @param EE_Ticket[] $tickets
533
-     * @param array       $template_args
534
-     * @return string
535
-     * @throws EE_Error
536
-     * @throws ReflectionException
537
-     */
538
-    protected function simpleTicketSelector(array $tickets, array $template_args)
539
-    {
540
-        // if there is only ONE ticket with a max qty of ONE
541
-        if (count($tickets) > 1 || $this->getMaxAttendees() !== 1) {
542
-            return '';
543
-        }
544
-        /** @var EE_Ticket $ticket */
545
-        $ticket = reset($tickets);
546
-        // if the ticket is free... then not much need for the ticket selector
547
-        if (
548
-            apply_filters(
549
-                'FHEE__ticket_selector_chart_template__hide_ticket_selector',
550
-                $ticket->is_free(),
551
-                $this->event->ID()
552
-            )
553
-        ) {
554
-            return new TicketSelectorSimple(
555
-                $this->event,
556
-                $ticket,
557
-                $this->getMaxAttendees(),
558
-                $template_args
559
-            );
560
-        }
561
-        return '';
562
-    }
563
-
564
-
565
-    /**
566
-     * externalEventRegistration
567
-     *
568
-     * @return string
569
-     */
570
-    public function externalEventRegistration(): string
571
-    {
572
-        // if not we still need to trigger the display of the submit button
573
-        add_filter('FHEE__EE_Ticket_Selector__display_ticket_selector_submit', '__return_true');
574
-        // display notice to admin that registration is external
575
-        return $this->display_full_ui()
576
-            ? esc_html__(
577
-                'Registration is at an external URL for this event.',
578
-                'event_espresso'
579
-            )
580
-            : '';
581
-    }
582
-
583
-
584
-    /**
585
-     * formOpen
586
-     *
587
-     * @param int    $ID
588
-     * @param string $external_url
589
-     * @return        string
590
-     */
591
-    public function formOpen(int $ID = 0, string $external_url = ''): string
592
-    {
593
-        // if redirecting, we don't need any anything else
594
-        if ($external_url) {
595
-            $html = '<form method="GET" ';
596
-            $html .= 'action="' . EEH_URL::refactor_url($external_url) . '" ';
597
-            $html .= 'name="ticket-selector-form-' . $ID . '"';
598
-            // open link in new window ?
599
-            $html       .= apply_filters(
600
-                'FHEE__EventEspresso_modules_ticket_selector_DisplayTicketSelector__formOpen__external_url_target_blank',
601
-                $this->isIframe(),
602
-                $this
603
-            )
604
-                ? ' target="_blank"'
605
-                : '';
606
-            $html       .= '>';
607
-            $query_args = EEH_URL::get_query_string($external_url);
608
-            foreach ((array) $query_args as $query_arg => $value) {
609
-                $html .= '<input type="hidden" name="' . $query_arg . '" value="' . $value . '">';
610
-            }
611
-            return $html;
612
-        }
613
-        // if there is no submit button, then don't start building a form
614
-        // because the "View Details" button will build its own form
615
-        if (! apply_filters('FHEE__EE_Ticket_Selector__display_ticket_selector_submit', false)) {
616
-            return '';
617
-        }
618
-        $checkout_url = EEH_Event_View::event_link_url($ID);
619
-        if (! $checkout_url) {
620
-            EE_Error::add_error(
621
-                esc_html__('The URL for the Event Details page could not be retrieved.', 'event_espresso'),
622
-                __FILE__,
623
-                __FUNCTION__,
624
-                __LINE__
625
-            );
626
-        }
627
-        // set no cache headers and constants
628
-        EE_System::do_not_cache();
629
-        $html = '<form method="POST" ';
630
-        $html .= 'action="' . $checkout_url . '" ';
631
-        $html .= 'name="ticket-selector-form-' . $ID . '"';
632
-        $html .= $this->iframe ? ' target="_blank"' : '';
633
-        $html .= '>';
634
-        $html .= '<input type="hidden" name="ee" value="process_ticket_selections">';
635
-        return apply_filters('FHEE__EE_Ticket_Selector__ticket_selector_form_open__html', $html, $this->event);
636
-    }
637
-
638
-
639
-    /**
640
-     * displaySubmitButton
641
-     *
642
-     * @param string $external_url
643
-     * @return string
644
-     * @throws EE_Error
645
-     * @throws ReflectionException
646
-     */
647
-    public function displaySubmitButton(string $external_url = ''): string
648
-    {
649
-        $html = '';
650
-        if ($this->display_full_ui()) {
651
-            // standard TS displayed with submit button, ie: "Register Now"
652
-            if (apply_filters('FHEE__EE_Ticket_Selector__display_ticket_selector_submit', false)) {
653
-                $html .= $this->displayRegisterNowButton();
654
-                $html .= empty($external_url)
655
-                    ? $this->ticketSelectorEndDiv()
656
-                    : $this->clearTicketSelector();
657
-                $html .= '<br/>' . $this->formClose();
658
-            } elseif ($this->getMaxAttendees() === 1) {
659
-                // its a "Dude Where's my Ticket Selector?" (DWMTS) type event (ie: $_max_atndz === 1)
660
-                if ($this->event->is_sold_out()) {
661
-                    // then instead of a View Details or Submit button, just display a "Sold Out" message
662
-                    $html .= apply_filters(
663
-                        'FHEE__EE_Ticket_Selector__display_ticket_selector_submit__sold_out_msg',
664
-                        sprintf(
665
-                            esc_html__(
666
-                                '%1$s"%2$s" is currently sold out.%4$sPlease check back again later, as spots may become available.%3$s',
667
-                                'event_espresso'
668
-                            ),
669
-                            '<p class="no-ticket-selector-msg clear-float">',
670
-                            $this->event->name(),
671
-                            '</p>',
672
-                            '<br />'
673
-                        ),
674
-                        $this->event
675
-                    );
676
-                    if (
677
-                        apply_filters(
678
-                            'FHEE__EE_Ticket_Selector__display_ticket_selector_submit__no_tickets_but_display_register_now_button',
679
-                            false,
680
-                            $this->event
681
-                        )
682
-                    ) {
683
-                        $html .= $this->displayRegisterNowButton();
684
-                    }
685
-                    // sold out DWMTS event, no TS, no submit or view details button, but has additional content
686
-                    $html .= $this->ticketSelectorEndDiv();
687
-                } elseif (
688
-                    apply_filters('FHEE__EE_Ticket_Selector__hide_ticket_selector', false)
689
-                    && ! is_single()
690
-                ) {
691
-                    // this is a "Dude Where's my Ticket Selector?" (DWMTS) type event,
692
-                    // but no tickets are available, so display event's "View Details" button.
693
-                    // it is being viewed via somewhere other than a single post
694
-                    $html .= $this->displayViewDetailsButton(true);
695
-                } else {
696
-                    $html .= $this->ticketSelectorEndDiv();
697
-                }
698
-            } elseif (is_archive()) {
699
-                // event list, no tickets available so display event's "View Details" button
700
-                $html .= $this->ticketSelectorEndDiv();
701
-                $html .= $this->displayViewDetailsButton();
702
-            } else {
703
-                if (
704
-                    apply_filters(
705
-                        'FHEE__EE_Ticket_Selector__display_ticket_selector_submit__no_tickets_but_display_register_now_button',
706
-                        false,
707
-                        $this->event
708
-                    )
709
-                ) {
710
-                    $html .= $this->displayRegisterNowButton();
711
-                }
712
-                // no submit or view details button, and no additional content
713
-                $html .= $this->ticketSelectorEndDiv();
714
-            }
715
-            if (! $this->iframe && ! is_archive()) {
716
-                $html .= EEH_Template::powered_by_event_espresso('', '', ['utm_content' => 'ticket_selector']);
717
-            }
718
-        }
719
-        return apply_filters(
720
-            'FHEE__EventEspresso_modules_ticket_selector_DisplayTicketSelector__displaySubmitButton__html',
721
-            $html,
722
-            $this->event,
723
-            $this
724
-        );
725
-    }
726
-
727
-
728
-    /**
729
-     * @return string
730
-     * @throws EE_Error
731
-     * @throws ReflectionException
732
-     */
733
-    public function displayRegisterNowButton(): string
734
-    {
735
-        $btn_text     = apply_filters(
736
-            'FHEE__EE_Ticket_Selector__display_ticket_selector_submit__btn_text',
737
-            esc_html__('Register Now', 'event_espresso'),
738
-            $this->event
739
-        );
740
-        $external_url = (string) $this->event->external_url()
741
-                        && $this->event->external_url() !== get_the_permalink()
742
-            ? $this->event->external_url()
743
-            : '';
744
-        $html         = EEH_HTML::div(
745
-            '',
746
-            'ticket-selector-submit-' . $this->event->ID() . '-btn-wrap',
747
-            'ticket-selector-submit-btn-wrap'
748
-        );
749
-        $html         .= '<input id="ticket-selector-submit-' . $this->event->ID() . '-btn"';
750
-        $html         .= ' class="ticket-selector-submit-btn ';
751
-        $html         .= empty($external_url) ? 'ticket-selector-submit-ajax"' : '"';
752
-        $html         .= ' type="submit" value="' . $btn_text . '" data-ee-disable-after-recaptcha="true" />';
753
-        $html         .= EEH_HTML::divx() . '<!-- .ticket-selector-submit-btn-wrap -->';
754
-        $html         .= apply_filters(
755
-            'FHEE__EE_Ticket_Selector__after_ticket_selector_submit',
756
-            '',
757
-            $this->event,
758
-            $this->iframe
759
-        );
760
-        return $html;
761
-    }
762
-
763
-
764
-    /**
765
-     * displayViewDetailsButton
766
-     *
767
-     * @param bool $DWMTS indicates a "Dude Where's my Ticket Selector?" (DWMTS) type event
768
-     *                    (ie: $_max_atndz === 1) where there are no available tickets,
769
-     *                    either because they are sold out, expired, or not yet on sale.
770
-     *                    In this case, we need to close the form BEFORE adding any closing divs
771
-     * @return string
772
-     * @throws EE_Error
773
-     * @throws ReflectionException
774
-     */
775
-    public function displayViewDetailsButton(bool $DWMTS = false): string
776
-    {
777
-        if (! $this->event->get_permalink()) {
778
-            EE_Error::add_error(
779
-                esc_html__('The URL for the Event Details page could not be retrieved.', 'event_espresso'),
780
-                __FILE__,
781
-                __FUNCTION__,
782
-                __LINE__
783
-            );
784
-        }
785
-        $view_details_btn = '<form method="GET" action="';
786
-        $view_details_btn .= apply_filters(
787
-            'FHEE__EE_Ticket_Selector__display_view_details_btn__btn_url',
788
-            $this->event->get_permalink(),
789
-            $this->event
790
-        );
791
-        $view_details_btn .= '"';
792
-        // open link in new window ?
793
-        $view_details_btn .= apply_filters(
794
-            'FHEE__EventEspresso_modules_ticket_selector_DisplayTicketSelector__displayViewDetailsButton__url_target_blank',
795
-            $this->isIframe(),
796
-            $this
797
-        )
798
-            ? ' target="_blank"'
799
-            : '';
800
-        $view_details_btn .= '>';
801
-        $btn_text         = apply_filters(
802
-            'FHEE__EE_Ticket_Selector__display_view_details_btn__btn_text',
803
-            esc_html__('View Details', 'event_espresso'),
804
-            $this->event
805
-        );
806
-        $view_details_btn .= '<input id="ticket-selector-submit-'
807
-                             . $this->event->ID()
808
-                             . '-btn" class="ticket-selector-submit-btn view-details-btn" type="submit" value="'
809
-                             . $btn_text
810
-                             . '" />';
811
-        $view_details_btn .= apply_filters('FHEE__EE_Ticket_Selector__after_view_details_btn', '', $this->event);
812
-        if ($DWMTS) {
813
-            $view_details_btn .= $this->formClose();
814
-            $view_details_btn .= $this->ticketSelectorEndDiv();
815
-            $view_details_btn .= '<br/>';
816
-        } else {
817
-            $view_details_btn .= $this->clearTicketSelector();
818
-            $view_details_btn .= '<br/>';
819
-            $view_details_btn .= $this->formClose();
820
-        }
821
-        return $view_details_btn;
822
-    }
823
-
824
-
825
-    /**
826
-     * @return string
827
-     */
828
-    public function ticketSelectorEndDiv(): string
829
-    {
830
-        return $this->clearTicketSelector() . '</div><!-- ticketSelectorEndDiv -->';
831
-    }
832
-
833
-
834
-    /**
835
-     * @return string
836
-     */
837
-    public function clearTicketSelector(): string
838
-    {
839
-        // standard TS displayed, appears after a "Register Now" or "view Details" button
840
-        return '<div class="clear"></div><!-- clearTicketSelector -->';
841
-    }
842
-
843
-
844
-    /**
845
-     * @access        public
846
-     * @return        string
847
-     */
848
-    public function formClose(): string
849
-    {
850
-        return '</form>';
851
-    }
852
-
853
-
854
-    /**
855
-     * handleMissingEvent
856
-     * Returns either false or an error to display when no valid event is passed.
857
-     *
858
-     * @return string
859
-     * @throws ExceptionStackTraceDisplay
860
-     * @throws InvalidInterfaceException
861
-     * @throws Exception
862
-     */
863
-    protected function handleMissingEvent()
864
-    {
865
-        // If this is not an iFrame request, simply return false.
866
-        if (! $this->isIframe()) {
867
-            return '';
868
-        }
869
-        // This is an iFrame so return an error.
870
-        // Display stack trace if WP_DEBUG is enabled.
871
-        if (WP_DEBUG === true && current_user_can('edit_pages')) {
872
-            $event_id = $this->request->getRequestParam('event', 0, 'int');
873
-            new ExceptionStackTraceDisplay(
874
-                new InvalidArgumentException(
875
-                    sprintf(
876
-                        esc_html__(
877
-                            'A valid Event ID is required to display the ticket selector.%3$sAn Event with an ID of "%1$s" could not be found.%3$sPlease verify that the embed code added to this post\'s content includes an "%2$s" argument and that its value corresponds to a valid Event ID.',
878
-                            'event_espresso'
879
-                        ),
880
-                        $event_id,
881
-                        'event',
882
-                        '<br />'
883
-                    )
884
-                )
885
-            );
886
-            return '';
887
-        }
888
-        // If WP_DEBUG is not enabled, display a message stating the event could not be found.
889
-        return EEH_HTML::p(
890
-            esc_html__(
891
-                'A valid Event could not be found. Please contact the event administrator for assistance.',
892
-                'event_espresso'
893
-            )
894
-        );
895
-    }
896
-
897
-
898
-    /**
899
-     * @return EE_Tax_Config
900
-     * @since   4.10.14.p
901
-     */
902
-    protected function getTaxConfig()
903
-    {
904
-        return isset(EE_Registry::instance()->CFG->tax_settings)
905
-               && EE_Registry::instance()->CFG->tax_settings instanceof EE_Tax_Config
906
-            ? EE_Registry::instance()->CFG->tax_settings
907
-            : new EE_Tax_Config();
908
-    }
365
+	}
366
+
367
+
368
+	/**
369
+	 * ticketSalesClosed
370
+	 * notice displayed if event ticket sales are turned off
371
+	 *
372
+	 * @return string
373
+	 * @throws EE_Error
374
+	 * @throws ReflectionException
375
+	 */
376
+	protected function ticketSalesClosedMessage(): string
377
+	{
378
+		$sales_closed_msg = esc_html__(
379
+			'We\'re sorry, but ticket sales have been closed at this time. Please check back again later.',
380
+			'event_espresso'
381
+		);
382
+		if (current_user_can('edit_post', $this->event->ID())) {
383
+			$sales_closed_msg .= sprintf(
384
+				esc_html__(
385
+					'%sNote to Event Admin:%sThe "Maximum number of tickets allowed per order for this event" in the Event Registration Options has been set to "0". This effectively turns off ticket sales. %s(click to edit this event)%s',
386
+					'event_espresso'
387
+				),
388
+				'<div class="ee-attention" style="text-align: left;"><b>',
389
+				'</b><br />',
390
+				'<span class="edit-link"><a class="post-edit-link" href="'
391
+				. get_edit_post_link($this->event->ID())
392
+				. '">',
393
+				'</a></span></div><!-- .ee-attention ticketSalesClosedMessage -->'
394
+			);
395
+		}
396
+		return '<p><span class="important-notice">' . $sales_closed_msg . '</span></p>';
397
+	}
398
+
399
+
400
+	/**
401
+	 * getTickets
402
+	 *
403
+	 * @return EE_Base_Class[]|EE_Ticket[]
404
+	 * @throws EE_Error
405
+	 * @throws InvalidDataTypeException
406
+	 * @throws InvalidInterfaceException
407
+	 * @throws InvalidArgumentException
408
+	 * @throws ReflectionException
409
+	 */
410
+	protected function getTickets()
411
+	{
412
+		$show_expired_tickets = is_admin() || $this->config->show_expired_tickets;
413
+
414
+		$ticket_query_args = [
415
+			[
416
+				'Datetime.EVT_ID' => $this->event->ID(),
417
+				'TKT_visibility'  => ['>', EEM_Ticket::TICKET_VISIBILITY_NONE_VALUE],
418
+			],
419
+			'order_by' => [
420
+				'TKT_order'              => 'ASC',
421
+				'TKT_required'           => 'DESC',
422
+				'TKT_start_date'         => 'ASC',
423
+				'TKT_end_date'           => 'ASC',
424
+				'Datetime.DTT_EVT_start' => 'DESC',
425
+			],
426
+		];
427
+
428
+		$datetime_id = $this->request->getRequestParam('datetime', 0, 'int');
429
+		if ($datetime_id) {
430
+			$ticket_query_args[0]['Datetime.DTT_ID'] = $datetime_id;
431
+		}
432
+
433
+		if (! $show_expired_tickets) {
434
+			// use the correct applicable time query depending on what version of core is being run.
435
+			$current_time                         = method_exists('EEM_Datetime', 'current_time_for_query')
436
+				? time()
437
+				: current_time('timestamp');
438
+			$ticket_query_args[0]['TKT_end_date'] = ['>', $current_time];
439
+		}
440
+		/** @var EE_Ticket[] $tickets */
441
+		$tickets = EEM_Ticket::instance()->get_all($ticket_query_args);
442
+		// remove tickets based on their visibility and the current user's allowed access (crudely based on roles)
443
+		// and filter the returned results
444
+		 $tickets = array_filter($tickets, [$this, 'ticketVisibilityFilter']);
445
+		return (array) apply_filters(
446
+			'FHEE__EventEspresso_modules_ticketSelector_DisplayTicketSelector__getTickets',
447
+			$tickets,
448
+			$ticket_query_args,
449
+			$this
450
+		);
451
+	}
452
+
453
+
454
+	/**
455
+	 * returns true if any of the following is true:
456
+	 *  - ticket visibility is PUBLIC
457
+	 *  - ticket visibility is MEMBERS_ONLY and user is logged in
458
+	 *  - ticket visibility is ADMINS_ONLY when user IS logged in as an admin
459
+	 *  - ticket visibility is ADMIN_UI_ONLY when ticket selector is being viewed via an admin page UI
460
+	 *
461
+	 * @param EE_Ticket $ticket
462
+	 * @return bool
463
+	 * @throws EE_Error
464
+	 * @throws ReflectionException
465
+	 * @since   $VID:$
466
+	 */
467
+	public function ticketVisibilityFilter(EE_Ticket $ticket): bool
468
+	{
469
+		return $ticket->isPublicOnly()
470
+			   || ($ticket->isMembersOnly() && $this->current_user->isLoggedIn())
471
+			   || ($ticket->isAdminsOnly() && $this->current_user->isEventManager())
472
+			   || ($ticket->isAdminUiOnly() && is_admin());
473
+	}
474
+
475
+
476
+	/**
477
+	 * loadTicketSelector
478
+	 * begins to assemble template arguments
479
+	 * and decides whether to load a "simple" ticket selector, or the standard
480
+	 *
481
+	 * @param EE_Ticket[] $tickets
482
+	 * @param array       $template_args
483
+	 * @return TicketSelectorSimple|TicketSelectorStandard
484
+	 * @throws EE_Error
485
+	 * @throws ReflectionException
486
+	 */
487
+	protected function loadTicketSelector(array $tickets, array $template_args)
488
+	{
489
+		$template_args['event']            = $this->event;
490
+		$template_args['EVT_ID']           = $this->event->ID();
491
+		$template_args['event_is_expired'] = $this->event->is_expired();
492
+		$template_args['max_atndz']        = $this->getMaxAttendees();
493
+		$template_args['date_format']      = $this->date_format;
494
+		$template_args['time_format']      = $this->time_format;
495
+		/**
496
+		 * Filters the anchor ID used when redirecting to the Ticket Selector if no quantity selected
497
+		 *
498
+		 * @param string  '#tkt-slctr-tbl-' . $EVT_ID The html ID to anchor to
499
+		 * @param int $EVT_ID The Event ID
500
+		 * @since 4.9.13
501
+		 */
502
+		$template_args['anchor_id']    = apply_filters(
503
+			'FHEE__EE_Ticket_Selector__redirect_anchor_id',
504
+			'#tkt-slctr-tbl-' . $this->event->ID(),
505
+			$this->event->ID()
506
+		);
507
+		$template_args['tickets']      = $tickets;
508
+		$template_args['ticket_count'] = count($tickets);
509
+		$ticket_selector               = $this->simpleTicketSelector($tickets, $template_args);
510
+		if ($ticket_selector instanceof TicketSelectorSimple) {
511
+			return $ticket_selector;
512
+		}
513
+		return new TicketSelectorStandard(
514
+			$this->config,
515
+			$this->getTaxConfig(),
516
+			$this->event,
517
+			$tickets,
518
+			$this->getMaxAttendees(),
519
+			$template_args,
520
+			$this->date_format,
521
+			$this->time_format
522
+		);
523
+	}
524
+
525
+
526
+	/**
527
+	 * simpleTicketSelector
528
+	 * there's one ticket, and max attendees is set to one,
529
+	 * so if the event is free, then this is a "simple" ticket selector
530
+	 * a.k.a. "Dude Where's my Ticket Selector?"
531
+	 *
532
+	 * @param EE_Ticket[] $tickets
533
+	 * @param array       $template_args
534
+	 * @return string
535
+	 * @throws EE_Error
536
+	 * @throws ReflectionException
537
+	 */
538
+	protected function simpleTicketSelector(array $tickets, array $template_args)
539
+	{
540
+		// if there is only ONE ticket with a max qty of ONE
541
+		if (count($tickets) > 1 || $this->getMaxAttendees() !== 1) {
542
+			return '';
543
+		}
544
+		/** @var EE_Ticket $ticket */
545
+		$ticket = reset($tickets);
546
+		// if the ticket is free... then not much need for the ticket selector
547
+		if (
548
+			apply_filters(
549
+				'FHEE__ticket_selector_chart_template__hide_ticket_selector',
550
+				$ticket->is_free(),
551
+				$this->event->ID()
552
+			)
553
+		) {
554
+			return new TicketSelectorSimple(
555
+				$this->event,
556
+				$ticket,
557
+				$this->getMaxAttendees(),
558
+				$template_args
559
+			);
560
+		}
561
+		return '';
562
+	}
563
+
564
+
565
+	/**
566
+	 * externalEventRegistration
567
+	 *
568
+	 * @return string
569
+	 */
570
+	public function externalEventRegistration(): string
571
+	{
572
+		// if not we still need to trigger the display of the submit button
573
+		add_filter('FHEE__EE_Ticket_Selector__display_ticket_selector_submit', '__return_true');
574
+		// display notice to admin that registration is external
575
+		return $this->display_full_ui()
576
+			? esc_html__(
577
+				'Registration is at an external URL for this event.',
578
+				'event_espresso'
579
+			)
580
+			: '';
581
+	}
582
+
583
+
584
+	/**
585
+	 * formOpen
586
+	 *
587
+	 * @param int    $ID
588
+	 * @param string $external_url
589
+	 * @return        string
590
+	 */
591
+	public function formOpen(int $ID = 0, string $external_url = ''): string
592
+	{
593
+		// if redirecting, we don't need any anything else
594
+		if ($external_url) {
595
+			$html = '<form method="GET" ';
596
+			$html .= 'action="' . EEH_URL::refactor_url($external_url) . '" ';
597
+			$html .= 'name="ticket-selector-form-' . $ID . '"';
598
+			// open link in new window ?
599
+			$html       .= apply_filters(
600
+				'FHEE__EventEspresso_modules_ticket_selector_DisplayTicketSelector__formOpen__external_url_target_blank',
601
+				$this->isIframe(),
602
+				$this
603
+			)
604
+				? ' target="_blank"'
605
+				: '';
606
+			$html       .= '>';
607
+			$query_args = EEH_URL::get_query_string($external_url);
608
+			foreach ((array) $query_args as $query_arg => $value) {
609
+				$html .= '<input type="hidden" name="' . $query_arg . '" value="' . $value . '">';
610
+			}
611
+			return $html;
612
+		}
613
+		// if there is no submit button, then don't start building a form
614
+		// because the "View Details" button will build its own form
615
+		if (! apply_filters('FHEE__EE_Ticket_Selector__display_ticket_selector_submit', false)) {
616
+			return '';
617
+		}
618
+		$checkout_url = EEH_Event_View::event_link_url($ID);
619
+		if (! $checkout_url) {
620
+			EE_Error::add_error(
621
+				esc_html__('The URL for the Event Details page could not be retrieved.', 'event_espresso'),
622
+				__FILE__,
623
+				__FUNCTION__,
624
+				__LINE__
625
+			);
626
+		}
627
+		// set no cache headers and constants
628
+		EE_System::do_not_cache();
629
+		$html = '<form method="POST" ';
630
+		$html .= 'action="' . $checkout_url . '" ';
631
+		$html .= 'name="ticket-selector-form-' . $ID . '"';
632
+		$html .= $this->iframe ? ' target="_blank"' : '';
633
+		$html .= '>';
634
+		$html .= '<input type="hidden" name="ee" value="process_ticket_selections">';
635
+		return apply_filters('FHEE__EE_Ticket_Selector__ticket_selector_form_open__html', $html, $this->event);
636
+	}
637
+
638
+
639
+	/**
640
+	 * displaySubmitButton
641
+	 *
642
+	 * @param string $external_url
643
+	 * @return string
644
+	 * @throws EE_Error
645
+	 * @throws ReflectionException
646
+	 */
647
+	public function displaySubmitButton(string $external_url = ''): string
648
+	{
649
+		$html = '';
650
+		if ($this->display_full_ui()) {
651
+			// standard TS displayed with submit button, ie: "Register Now"
652
+			if (apply_filters('FHEE__EE_Ticket_Selector__display_ticket_selector_submit', false)) {
653
+				$html .= $this->displayRegisterNowButton();
654
+				$html .= empty($external_url)
655
+					? $this->ticketSelectorEndDiv()
656
+					: $this->clearTicketSelector();
657
+				$html .= '<br/>' . $this->formClose();
658
+			} elseif ($this->getMaxAttendees() === 1) {
659
+				// its a "Dude Where's my Ticket Selector?" (DWMTS) type event (ie: $_max_atndz === 1)
660
+				if ($this->event->is_sold_out()) {
661
+					// then instead of a View Details or Submit button, just display a "Sold Out" message
662
+					$html .= apply_filters(
663
+						'FHEE__EE_Ticket_Selector__display_ticket_selector_submit__sold_out_msg',
664
+						sprintf(
665
+							esc_html__(
666
+								'%1$s"%2$s" is currently sold out.%4$sPlease check back again later, as spots may become available.%3$s',
667
+								'event_espresso'
668
+							),
669
+							'<p class="no-ticket-selector-msg clear-float">',
670
+							$this->event->name(),
671
+							'</p>',
672
+							'<br />'
673
+						),
674
+						$this->event
675
+					);
676
+					if (
677
+						apply_filters(
678
+							'FHEE__EE_Ticket_Selector__display_ticket_selector_submit__no_tickets_but_display_register_now_button',
679
+							false,
680
+							$this->event
681
+						)
682
+					) {
683
+						$html .= $this->displayRegisterNowButton();
684
+					}
685
+					// sold out DWMTS event, no TS, no submit or view details button, but has additional content
686
+					$html .= $this->ticketSelectorEndDiv();
687
+				} elseif (
688
+					apply_filters('FHEE__EE_Ticket_Selector__hide_ticket_selector', false)
689
+					&& ! is_single()
690
+				) {
691
+					// this is a "Dude Where's my Ticket Selector?" (DWMTS) type event,
692
+					// but no tickets are available, so display event's "View Details" button.
693
+					// it is being viewed via somewhere other than a single post
694
+					$html .= $this->displayViewDetailsButton(true);
695
+				} else {
696
+					$html .= $this->ticketSelectorEndDiv();
697
+				}
698
+			} elseif (is_archive()) {
699
+				// event list, no tickets available so display event's "View Details" button
700
+				$html .= $this->ticketSelectorEndDiv();
701
+				$html .= $this->displayViewDetailsButton();
702
+			} else {
703
+				if (
704
+					apply_filters(
705
+						'FHEE__EE_Ticket_Selector__display_ticket_selector_submit__no_tickets_but_display_register_now_button',
706
+						false,
707
+						$this->event
708
+					)
709
+				) {
710
+					$html .= $this->displayRegisterNowButton();
711
+				}
712
+				// no submit or view details button, and no additional content
713
+				$html .= $this->ticketSelectorEndDiv();
714
+			}
715
+			if (! $this->iframe && ! is_archive()) {
716
+				$html .= EEH_Template::powered_by_event_espresso('', '', ['utm_content' => 'ticket_selector']);
717
+			}
718
+		}
719
+		return apply_filters(
720
+			'FHEE__EventEspresso_modules_ticket_selector_DisplayTicketSelector__displaySubmitButton__html',
721
+			$html,
722
+			$this->event,
723
+			$this
724
+		);
725
+	}
726
+
727
+
728
+	/**
729
+	 * @return string
730
+	 * @throws EE_Error
731
+	 * @throws ReflectionException
732
+	 */
733
+	public function displayRegisterNowButton(): string
734
+	{
735
+		$btn_text     = apply_filters(
736
+			'FHEE__EE_Ticket_Selector__display_ticket_selector_submit__btn_text',
737
+			esc_html__('Register Now', 'event_espresso'),
738
+			$this->event
739
+		);
740
+		$external_url = (string) $this->event->external_url()
741
+						&& $this->event->external_url() !== get_the_permalink()
742
+			? $this->event->external_url()
743
+			: '';
744
+		$html         = EEH_HTML::div(
745
+			'',
746
+			'ticket-selector-submit-' . $this->event->ID() . '-btn-wrap',
747
+			'ticket-selector-submit-btn-wrap'
748
+		);
749
+		$html         .= '<input id="ticket-selector-submit-' . $this->event->ID() . '-btn"';
750
+		$html         .= ' class="ticket-selector-submit-btn ';
751
+		$html         .= empty($external_url) ? 'ticket-selector-submit-ajax"' : '"';
752
+		$html         .= ' type="submit" value="' . $btn_text . '" data-ee-disable-after-recaptcha="true" />';
753
+		$html         .= EEH_HTML::divx() . '<!-- .ticket-selector-submit-btn-wrap -->';
754
+		$html         .= apply_filters(
755
+			'FHEE__EE_Ticket_Selector__after_ticket_selector_submit',
756
+			'',
757
+			$this->event,
758
+			$this->iframe
759
+		);
760
+		return $html;
761
+	}
762
+
763
+
764
+	/**
765
+	 * displayViewDetailsButton
766
+	 *
767
+	 * @param bool $DWMTS indicates a "Dude Where's my Ticket Selector?" (DWMTS) type event
768
+	 *                    (ie: $_max_atndz === 1) where there are no available tickets,
769
+	 *                    either because they are sold out, expired, or not yet on sale.
770
+	 *                    In this case, we need to close the form BEFORE adding any closing divs
771
+	 * @return string
772
+	 * @throws EE_Error
773
+	 * @throws ReflectionException
774
+	 */
775
+	public function displayViewDetailsButton(bool $DWMTS = false): string
776
+	{
777
+		if (! $this->event->get_permalink()) {
778
+			EE_Error::add_error(
779
+				esc_html__('The URL for the Event Details page could not be retrieved.', 'event_espresso'),
780
+				__FILE__,
781
+				__FUNCTION__,
782
+				__LINE__
783
+			);
784
+		}
785
+		$view_details_btn = '<form method="GET" action="';
786
+		$view_details_btn .= apply_filters(
787
+			'FHEE__EE_Ticket_Selector__display_view_details_btn__btn_url',
788
+			$this->event->get_permalink(),
789
+			$this->event
790
+		);
791
+		$view_details_btn .= '"';
792
+		// open link in new window ?
793
+		$view_details_btn .= apply_filters(
794
+			'FHEE__EventEspresso_modules_ticket_selector_DisplayTicketSelector__displayViewDetailsButton__url_target_blank',
795
+			$this->isIframe(),
796
+			$this
797
+		)
798
+			? ' target="_blank"'
799
+			: '';
800
+		$view_details_btn .= '>';
801
+		$btn_text         = apply_filters(
802
+			'FHEE__EE_Ticket_Selector__display_view_details_btn__btn_text',
803
+			esc_html__('View Details', 'event_espresso'),
804
+			$this->event
805
+		);
806
+		$view_details_btn .= '<input id="ticket-selector-submit-'
807
+							 . $this->event->ID()
808
+							 . '-btn" class="ticket-selector-submit-btn view-details-btn" type="submit" value="'
809
+							 . $btn_text
810
+							 . '" />';
811
+		$view_details_btn .= apply_filters('FHEE__EE_Ticket_Selector__after_view_details_btn', '', $this->event);
812
+		if ($DWMTS) {
813
+			$view_details_btn .= $this->formClose();
814
+			$view_details_btn .= $this->ticketSelectorEndDiv();
815
+			$view_details_btn .= '<br/>';
816
+		} else {
817
+			$view_details_btn .= $this->clearTicketSelector();
818
+			$view_details_btn .= '<br/>';
819
+			$view_details_btn .= $this->formClose();
820
+		}
821
+		return $view_details_btn;
822
+	}
823
+
824
+
825
+	/**
826
+	 * @return string
827
+	 */
828
+	public function ticketSelectorEndDiv(): string
829
+	{
830
+		return $this->clearTicketSelector() . '</div><!-- ticketSelectorEndDiv -->';
831
+	}
832
+
833
+
834
+	/**
835
+	 * @return string
836
+	 */
837
+	public function clearTicketSelector(): string
838
+	{
839
+		// standard TS displayed, appears after a "Register Now" or "view Details" button
840
+		return '<div class="clear"></div><!-- clearTicketSelector -->';
841
+	}
842
+
843
+
844
+	/**
845
+	 * @access        public
846
+	 * @return        string
847
+	 */
848
+	public function formClose(): string
849
+	{
850
+		return '</form>';
851
+	}
852
+
853
+
854
+	/**
855
+	 * handleMissingEvent
856
+	 * Returns either false or an error to display when no valid event is passed.
857
+	 *
858
+	 * @return string
859
+	 * @throws ExceptionStackTraceDisplay
860
+	 * @throws InvalidInterfaceException
861
+	 * @throws Exception
862
+	 */
863
+	protected function handleMissingEvent()
864
+	{
865
+		// If this is not an iFrame request, simply return false.
866
+		if (! $this->isIframe()) {
867
+			return '';
868
+		}
869
+		// This is an iFrame so return an error.
870
+		// Display stack trace if WP_DEBUG is enabled.
871
+		if (WP_DEBUG === true && current_user_can('edit_pages')) {
872
+			$event_id = $this->request->getRequestParam('event', 0, 'int');
873
+			new ExceptionStackTraceDisplay(
874
+				new InvalidArgumentException(
875
+					sprintf(
876
+						esc_html__(
877
+							'A valid Event ID is required to display the ticket selector.%3$sAn Event with an ID of "%1$s" could not be found.%3$sPlease verify that the embed code added to this post\'s content includes an "%2$s" argument and that its value corresponds to a valid Event ID.',
878
+							'event_espresso'
879
+						),
880
+						$event_id,
881
+						'event',
882
+						'<br />'
883
+					)
884
+				)
885
+			);
886
+			return '';
887
+		}
888
+		// If WP_DEBUG is not enabled, display a message stating the event could not be found.
889
+		return EEH_HTML::p(
890
+			esc_html__(
891
+				'A valid Event could not be found. Please contact the event administrator for assistance.',
892
+				'event_espresso'
893
+			)
894
+		);
895
+	}
896
+
897
+
898
+	/**
899
+	 * @return EE_Tax_Config
900
+	 * @since   4.10.14.p
901
+	 */
902
+	protected function getTaxConfig()
903
+	{
904
+		return isset(EE_Registry::instance()->CFG->tax_settings)
905
+			   && EE_Registry::instance()->CFG->tax_settings instanceof EE_Tax_Config
906
+			? EE_Registry::instance()->CFG->tax_settings
907
+			: new EE_Tax_Config();
908
+	}
909 909
 }
Please login to merge, or discard this patch.
core/EE_System.core.php 1 patch
Indentation   +1230 added lines, -1230 removed lines patch added patch discarded remove patch
@@ -24,1234 +24,1234 @@
 block discarded – undo
24 24
  */
25 25
 final class EE_System implements ResettableInterface
26 26
 {
27
-    /**
28
-     * indicates this is a 'normal' request. Ie, not activation, nor upgrade, nor activation.
29
-     * So examples of this would be a normal GET request on the frontend or backend, or a POST, etc
30
-     */
31
-    const req_type_normal = 0;
32
-
33
-    /**
34
-     * Indicates this is a brand new installation of EE so we should install
35
-     * tables and default data etc
36
-     */
37
-    const req_type_new_activation = 1;
38
-
39
-    /**
40
-     * we've detected that EE has been reactivated (or EE was activated during maintenance mode,
41
-     * and we just exited maintenance mode). We MUST check the database is setup properly
42
-     * and that default data is setup too
43
-     */
44
-    const req_type_reactivation = 2;
45
-
46
-    /**
47
-     * indicates that EE has been upgraded since its previous request.
48
-     * We may have data migration scripts to call and will want to trigger maintenance mode
49
-     */
50
-    const req_type_upgrade = 3;
51
-
52
-    /**
53
-     * TODO  will detect that EE has been DOWNGRADED. We probably don't want to run in this case...
54
-     */
55
-    const req_type_downgrade = 4;
56
-
57
-    /**
58
-     * @deprecated since version 4.6.0.dev.006
59
-     * Now whenever a new_activation is detected the request type is still just
60
-     * new_activation (same for reactivation, upgrade, downgrade etc), but if we're in maintenance mode
61
-     * EE_System::initialize_db_if_no_migrations_required and EE_Addon::initialize_db_if_no_migrations_required
62
-     * will instead enqueue that EE plugin's db initialization for when we're taken out of maintenance mode.
63
-     * (Specifically, when the migration manager indicates migrations are finished
64
-     * EE_Data_Migration_Manager::initialize_db_for_enqueued_ee_plugins() will be called)
65
-     */
66
-    const req_type_activation_but_not_installed = 5;
67
-
68
-    /**
69
-     * option prefix for recording the activation history (like core's "espresso_db_update") of addons
70
-     */
71
-    const addon_activation_history_option_prefix = 'ee_addon_activation_history_';
72
-
73
-    /**
74
-     * @var AddonManager $addon_manager
75
-     */
76
-    private $addon_manager;
77
-
78
-    /**
79
-     * @var EE_System $_instance
80
-     */
81
-    private static $_instance;
82
-
83
-    /**
84
-     * @var EE_Registry $registry
85
-     */
86
-    private $registry;
87
-
88
-    /**
89
-     * @var LoaderInterface $loader
90
-     */
91
-    private $loader;
92
-
93
-    /**
94
-     * @var EE_Capabilities $capabilities
95
-     */
96
-    private $capabilities;
97
-
98
-    /**
99
-     * @var EE_Maintenance_Mode $maintenance_mode
100
-     */
101
-    private $maintenance_mode;
102
-
103
-    /**
104
-     * @var RequestInterface $request
105
-     */
106
-    private $request;
107
-
108
-    /**
109
-     * Stores which type of request this is, options being one of the constants on EE_System starting with req_type_*.
110
-     * It can be a brand-new activation, a reactivation, an upgrade, a downgrade, or a normal request.
111
-     *
112
-     * @var int $_req_type
113
-     */
114
-    private $_req_type;
115
-
116
-    /**
117
-     * Whether or not there was a non-micro version change in EE core version during this request
118
-     *
119
-     * @var boolean $_major_version_change
120
-     */
121
-    private $_major_version_change = false;
122
-
123
-    /**
124
-     * @var Router $router
125
-     */
126
-    private $router;
127
-
128
-    /**
129
-     * @param EventEspresso\core\domain\services\custom_post_types\RegisterCustomPostTypes
130
-     */
131
-    private $register_custom_post_types;
132
-
133
-    /**
134
-     * @param EventEspresso\core\domain\services\custom_post_types\RegisterCustomTaxonomies
135
-     */
136
-    private $register_custom_taxonomies;
137
-
138
-    /**
139
-     * @param EventEspresso\core\domain\services\custom_post_types\RegisterCustomTaxonomyTerms
140
-     */
141
-    private $register_custom_taxonomy_terms;
142
-
143
-    /**
144
-     * @singleton method used to instantiate class object
145
-     * @param LoaderInterface|null     $loader
146
-     * @param EE_Maintenance_Mode|null $maintenance_mode
147
-     * @param EE_Registry|null         $registry
148
-     * @param RequestInterface|null    $request
149
-     * @param Router|null              $router
150
-     * @return EE_System
151
-     */
152
-    public static function instance(
153
-        LoaderInterface $loader = null,
154
-        EE_Maintenance_Mode $maintenance_mode = null,
155
-        EE_Registry $registry = null,
156
-        RequestInterface $request = null,
157
-        Router $router = null
158
-    ): EE_System {
159
-        // check if class object is instantiated
160
-        if (! self::$_instance instanceof EE_System) {
161
-            self::$_instance = new self($loader, $maintenance_mode, $registry, $request, $router);
162
-        }
163
-        return self::$_instance;
164
-    }
165
-
166
-
167
-    /**
168
-     * resets the instance and returns it
169
-     *
170
-     * @return EE_System
171
-     */
172
-    public static function reset(): EE_System
173
-    {
174
-        self::$_instance->_req_type = null;
175
-        // make sure none of the old hooks are left hanging around
176
-        remove_all_actions('AHEE__EE_System__perform_activations_upgrades_and_migrations');
177
-        // we need to reset the migration manager in order for it to detect DMSs properly
178
-        EE_Data_Migration_Manager::reset();
179
-        self::instance()->detect_activations_or_upgrades();
180
-        self::instance()->perform_activations_upgrades_and_migrations();
181
-        return self::instance();
182
-    }
183
-
184
-
185
-    /**
186
-     * sets hooks for running rest of system
187
-     * provides "AHEE__EE_System__construct__complete" hook for EE Addons to use as their starting point
188
-     * starting EE Addons from any other point may lead to problems
189
-     *
190
-     * @param LoaderInterface     $loader
191
-     * @param EE_Maintenance_Mode $maintenance_mode
192
-     * @param EE_Registry         $registry
193
-     * @param RequestInterface    $request
194
-     * @param Router              $router
195
-     */
196
-    private function __construct(
197
-        LoaderInterface $loader,
198
-        EE_Maintenance_Mode $maintenance_mode,
199
-        EE_Registry $registry,
200
-        RequestInterface $request,
201
-        Router $router
202
-    ) {
203
-        $this->registry         = $registry;
204
-        $this->loader           = $loader;
205
-        $this->request          = $request;
206
-        $this->router           = $router;
207
-        $this->maintenance_mode = $maintenance_mode;
208
-        do_action('AHEE__EE_System__construct__begin', $this);
209
-        add_action(
210
-            'AHEE__EE_Bootstrap__load_espresso_addons',
211
-            [$this, 'loadCapabilities'],
212
-            5
213
-        );
214
-        add_action(
215
-            'AHEE__EE_Bootstrap__load_espresso_addons',
216
-            [$this, 'loadCommandBus'],
217
-            7
218
-        );
219
-        add_action(
220
-            'AHEE__EE_Bootstrap__load_espresso_addons',
221
-            [$this, 'loadPluginApi'],
222
-            9
223
-        );
224
-        // give caff stuff a chance to play during the activation process too.
225
-        add_action(
226
-            'AHEE__EE_Bootstrap__load_espresso_addons',
227
-            [$this, 'brewCaffeinated'],
228
-            9
229
-        );
230
-        // allow addons to load first so that they can register autoloaders, set hooks for running DMS's, etc
231
-        add_action(
232
-            'AHEE__EE_Bootstrap__load_espresso_addons',
233
-            [$this, 'load_espresso_addons']
234
-        );
235
-        // when an ee addon is activated, we want to call the core hook(s) again
236
-        // because the newly-activated addon didn't get a chance to run at all
237
-        add_action('activate_plugin', [$this, 'load_espresso_addons'], 1);
238
-        // detect whether install or upgrade
239
-        add_action(
240
-            'AHEE__EE_Bootstrap__detect_activations_or_upgrades',
241
-            [$this, 'detect_activations_or_upgrades'],
242
-            3
243
-        );
244
-        // load EE_Config, EE_Textdomain, etc
245
-        add_action(
246
-            'AHEE__EE_Bootstrap__load_core_configuration',
247
-            [$this, 'load_core_configuration'],
248
-            5
249
-        );
250
-        // load specifications for matching routes to current request
251
-        add_action(
252
-            'AHEE__EE_Bootstrap__load_core_configuration',
253
-            [$this, 'loadRouteMatchSpecifications']
254
-        );
255
-        // load specifications for custom post types
256
-        add_action(
257
-            'AHEE__EE_Bootstrap__load_core_configuration',
258
-            array($this, 'loadCustomPostTypes')
259
-        );
260
-        // load specifications for custom post types
261
-        add_action(
262
-            'AHEE__EE_Bootstrap__load_core_configuration',
263
-            array($this, 'loadCustomPostTypes')
264
-        );
265
-        // load EE_Config, EE_Textdomain, etc
266
-        add_action(
267
-            'AHEE__EE_Bootstrap__register_shortcodes_modules_and_widgets',
268
-            [$this, 'register_shortcodes_modules_and_widgets'],
269
-            7
270
-        );
271
-        // you wanna get going? I wanna get going... let's get going!
272
-        add_action(
273
-            'AHEE__EE_Bootstrap__brew_espresso',
274
-            [$this, 'brew_espresso'],
275
-            9
276
-        );
277
-        // other housekeeping
278
-        // exclude EE critical pages from wp_list_pages
279
-        add_filter(
280
-            'wp_list_pages_excludes',
281
-            [$this, 'remove_pages_from_wp_list_pages'],
282
-            10
283
-        );
284
-        // ALL EE Addons should use the following hook point to attach their initial setup too
285
-        // it's extremely important for EE Addons to register any class autoloaders so that they can be available when the EE_Config loads
286
-        do_action('AHEE__EE_System__construct__complete', $this);
287
-    }
288
-
289
-
290
-    /**
291
-     * load and setup EE_Capabilities
292
-     *
293
-     * @return void
294
-     */
295
-    public function loadCapabilities()
296
-    {
297
-        $this->capabilities = $this->loader->getShared('EE_Capabilities');
298
-        add_action(
299
-            'AHEE__EE_Capabilities__init_caps__before_initialization',
300
-            function () {
301
-                LoaderFactory::getLoader()->getShared('EventEspresso\PaymentMethods\Manager');
302
-                LoaderFactory::getLoader()->getShared('EE_Payment_Method_Manager');
303
-            }
304
-        );
305
-    }
306
-
307
-
308
-    /**
309
-     * create and cache the CommandBus, and also add middleware
310
-     * The CapChecker middleware requires the use of EE_Capabilities
311
-     * which is why we need to load the CommandBus after Caps are set up
312
-     * CommandBus middleware operate FIFO - First In First Out
313
-     * so LocateMovedCommands will run first in order to return any new commands
314
-     *
315
-     * @return void
316
-     */
317
-    public function loadCommandBus()
318
-    {
319
-        $this->loader->getShared(
320
-            'CommandBusInterface',
321
-            [
322
-                null,
323
-                apply_filters(
324
-                    'FHEE__EE_Load_Espresso_Core__handle_request__CommandBus_middleware',
325
-                    [
326
-                        $this->loader->getShared('EventEspresso\core\services\commands\middleware\LocateMovedCommands'),
327
-                        $this->loader->getShared('EventEspresso\core\services\commands\middleware\CapChecker'),
328
-                        $this->loader->getShared('EventEspresso\core\services\commands\middleware\AddActionHook'),
329
-                    ]
330
-                ),
331
-            ]
332
-        );
333
-    }
334
-
335
-
336
-    /**
337
-     * @return void
338
-     * @throws Exception
339
-     */
340
-    public function loadPluginApi()
341
-    {
342
-        $this->addon_manager = $this->loader->getShared(AddonManager::class);
343
-        $this->addon_manager->initialize();
344
-        $this->loader->getShared('EE_Request_Handler');
345
-    }
346
-
347
-
348
-    /**
349
-     * The purpose of this method is to simply check for a file named "caffeinated/brewing_regular.php" for any hooks
350
-     * that need to be setup before our EE_System launches.
351
-     *
352
-     * @return void
353
-     * @throws DomainException
354
-     * @throws InvalidArgumentException
355
-     * @throws InvalidDataTypeException
356
-     * @throws InvalidInterfaceException
357
-     * @throws InvalidClassException
358
-     * @throws InvalidFilePathException
359
-     * @throws EE_Error
360
-     */
361
-    public function brewCaffeinated()
362
-    {
363
-        static $brew;
364
-        /** @var Domain $domain */
365
-        $domain = DomainFactory::getEventEspressoCoreDomain();
366
-        if ($domain->isCaffeinated() && ! $brew instanceof EE_Brewing_Regular) {
367
-            require_once EE_CAFF_PATH . 'brewing_regular.php';
368
-            /** @var EE_Brewing_Regular $brew */
369
-            $brew = LoaderFactory::getLoader()->getShared(EE_Brewing_Regular::class);
370
-            $brew->initializePUE();
371
-            add_action(
372
-                'AHEE__EE_System__load_core_configuration__begin',
373
-                [$brew, 'caffeinated']
374
-            );
375
-        }
376
-    }
377
-
378
-
379
-    /**
380
-     * load_espresso_addons
381
-     * allow addons to load first so that they can set hooks for running DMS's, etc
382
-     * this is hooked into both:
383
-     *    'AHEE__EE_Bootstrap__load_core_configuration'
384
-     *        which runs during the WP 'plugins_loaded' action at priority 5
385
-     *    and the WP 'activate_plugin' hook point
386
-     *
387
-     * @return void
388
-     * @throws Exception
389
-     */
390
-    public function load_espresso_addons()
391
-    {
392
-        // looking for hooks? they've been moved into the AddonManager to maintain compatibility
393
-        $this->addon_manager->loadAddons();
394
-    }
395
-
396
-
397
-    /**
398
-     * detect_activations_or_upgrades
399
-     * Checks for activation or upgrade of core first;
400
-     * then also checks if any registered addons have been activated or upgraded
401
-     * This is hooked into 'AHEE__EE_Bootstrap__detect_activations_or_upgrades'
402
-     * which runs during the WP 'plugins_loaded' action at priority 3
403
-     *
404
-     * @access public
405
-     * @return void
406
-     */
407
-    public function detect_activations_or_upgrades()
408
-    {
409
-        // first off: let's make sure to handle core
410
-        $this->detect_if_activation_or_upgrade();
411
-        foreach ($this->registry->addons as $addon) {
412
-            if ($addon instanceof EE_Addon) {
413
-                // detect teh request type for that addon
414
-                $addon->detect_req_type();
415
-            }
416
-        }
417
-    }
418
-
419
-
420
-    /**
421
-     * detect_if_activation_or_upgrade
422
-     * Takes care of detecting whether this is a brand new install or code upgrade,
423
-     * and either setting up the DB or setting up maintenance mode etc.
424
-     *
425
-     * @access public
426
-     * @return void
427
-     */
428
-    public function detect_if_activation_or_upgrade()
429
-    {
430
-        do_action('AHEE__EE_System___detect_if_activation_or_upgrade__begin');
431
-        // check if db has been updated, or if its a brand-new installation
432
-        $espresso_db_update = $this->fix_espresso_db_upgrade_option();
433
-        $request_type       = $this->detect_req_type($espresso_db_update);
434
-        // EEH_Debug_Tools::printr( $request_type, '$request_type', __FILE__, __LINE__ );
435
-        switch ($request_type) {
436
-            case EE_System::req_type_new_activation:
437
-                do_action('AHEE__EE_System__detect_if_activation_or_upgrade__new_activation');
438
-                $this->_handle_core_version_change($espresso_db_update);
439
-                break;
440
-            case EE_System::req_type_reactivation:
441
-                do_action('AHEE__EE_System__detect_if_activation_or_upgrade__reactivation');
442
-                $this->_handle_core_version_change($espresso_db_update);
443
-                break;
444
-            case EE_System::req_type_upgrade:
445
-                do_action('AHEE__EE_System__detect_if_activation_or_upgrade__upgrade');
446
-                // migrations may be required now that we've upgraded
447
-                $this->maintenance_mode->set_maintenance_mode_if_db_old();
448
-                $this->_handle_core_version_change($espresso_db_update);
449
-                break;
450
-            case EE_System::req_type_downgrade:
451
-                do_action('AHEE__EE_System__detect_if_activation_or_upgrade__downgrade');
452
-                // its possible migrations are no longer required
453
-                $this->maintenance_mode->set_maintenance_mode_if_db_old();
454
-                $this->_handle_core_version_change($espresso_db_update);
455
-                break;
456
-            case EE_System::req_type_normal:
457
-            default:
458
-                break;
459
-        }
460
-        do_action('AHEE__EE_System__detect_if_activation_or_upgrade__complete');
461
-    }
462
-
463
-
464
-    /**
465
-     * Updates the list of installed versions and sets hooks for
466
-     * initializing the database later during the request
467
-     *
468
-     * @param array $espresso_db_update
469
-     */
470
-    private function _handle_core_version_change(array $espresso_db_update)
471
-    {
472
-        $this->update_list_of_installed_versions($espresso_db_update);
473
-        // get ready to verify the DB is ok (provided we aren't in maintenance mode, of course)
474
-        add_action(
475
-            'AHEE__EE_System__perform_activations_upgrades_and_migrations',
476
-            [$this, 'initialize_db_if_no_migrations_required']
477
-        );
478
-    }
479
-
480
-
481
-    /**
482
-     * standardizes the wp option 'espresso_db_upgrade' which actually stores
483
-     * information about what versions of EE have been installed and activated,
484
-     * NOT necessarily the state of the database
485
-     *
486
-     * @param mixed $espresso_db_update           the value of the WordPress option.
487
-     *                                            If not supplied, fetches it from the options table
488
-     * @return array the correct value of 'espresso_db_upgrade', after saving it, if it needed correction
489
-     */
490
-    private function fix_espresso_db_upgrade_option($espresso_db_update = null): array
491
-    {
492
-        do_action('FHEE__EE_System__manage_fix_espresso_db_upgrade_option__begin', $espresso_db_update);
493
-        if (! $espresso_db_update) {
494
-            $espresso_db_update = get_option('espresso_db_update');
495
-        }
496
-        // check that option is an array
497
-        if (! is_array($espresso_db_update)) {
498
-            // if option is FALSE, then it never existed
499
-            if ($espresso_db_update === false) {
500
-                // make $espresso_db_update an array and save option with autoload OFF
501
-                $espresso_db_update = [];
502
-                add_option('espresso_db_update', $espresso_db_update, '', 'no');
503
-            } else {
504
-                // option is NOT FALSE but also is NOT an array, so make it an array and save it
505
-                $espresso_db_update = [$espresso_db_update => []];
506
-                update_option('espresso_db_update', $espresso_db_update);
507
-            }
508
-        } else {
509
-            $corrected_db_update = [];
510
-            // if IS an array, but is it an array where KEYS are version numbers, and values are arrays?
511
-            foreach ($espresso_db_update as $should_be_version_string => $should_be_array) {
512
-                if (is_int($should_be_version_string) && ! is_array($should_be_array)) {
513
-                    // the key is an int, and the value IS NOT an array
514
-                    // so it must be numerically-indexed, where values are versions installed...
515
-                    // fix it!
516
-                    $version_string                         = $should_be_array;
517
-                    $corrected_db_update[ $version_string ] = ['unknown-date'];
518
-                } else {
519
-                    // ok it checks out
520
-                    $corrected_db_update[ $should_be_version_string ] = $should_be_array;
521
-                }
522
-            }
523
-            $espresso_db_update = $corrected_db_update;
524
-            update_option('espresso_db_update', $espresso_db_update);
525
-        }
526
-        do_action('FHEE__EE_System__manage_fix_espresso_db_upgrade_option__complete', $espresso_db_update);
527
-        return ! empty($espresso_db_update) ? $espresso_db_update : [];
528
-    }
529
-
530
-
531
-    /**
532
-     * Does the traditional work of setting up the plugin's database and adding default data.
533
-     * If migration script/process did not exist, this is what would happen on every activation/reactivation/upgrade.
534
-     * NOTE: if we're in maintenance mode (which would be the case if we detect there are data
535
-     * migration scripts that need to be run and a version change happens), enqueues core for database initialization,
536
-     * so that it will be done when migrations are finished
537
-     *
538
-     * @param boolean $initialize_addons_too if true, we double-check addons' database tables etc too;
539
-     * @param boolean $verify_schema         if true will re-check the database tables have the correct schema.
540
-     *                                       This is a resource-intensive job
541
-     *                                       so we prefer to only do it when necessary
542
-     * @return void
543
-     * @throws EE_Error
544
-     * @throws ReflectionException
545
-     */
546
-    public function initialize_db_if_no_migrations_required($initialize_addons_too = false, $verify_schema = true)
547
-    {
548
-        $request_type = $this->detect_req_type();
549
-        // only initialize system if we're not in maintenance mode.
550
-        if ($this->maintenance_mode->level() !== EE_Maintenance_Mode::level_2_complete_maintenance) {
551
-            /** @var EventEspresso\core\domain\services\custom_post_types\RewriteRules $rewrite_rules */
552
-            $rewrite_rules = $this->loader->getShared(
553
-                'EventEspresso\core\domain\services\custom_post_types\RewriteRules'
554
-            );
555
-            $rewrite_rules->flush();
556
-            if ($verify_schema) {
557
-                EEH_Activation::initialize_db_and_folders();
558
-            }
559
-            EEH_Activation::initialize_db_content();
560
-            EEH_Activation::system_initialization();
561
-            if ($initialize_addons_too) {
562
-                $this->initialize_addons();
563
-            }
564
-        } else {
565
-            EE_Data_Migration_Manager::instance()->enqueue_db_initialization_for('Core');
566
-        }
567
-        if (
568
-            $request_type === EE_System::req_type_new_activation
569
-            || $request_type === EE_System::req_type_reactivation
570
-            || (
571
-                $request_type === EE_System::req_type_upgrade
572
-                && $this->is_major_version_change()
573
-            )
574
-        ) {
575
-            add_action('AHEE__EE_System__initialize_last', [$this, 'redirect_to_about_ee'], 9);
576
-        }
577
-    }
578
-
579
-
580
-    /**
581
-     * Initializes the db for all registered addons
582
-     *
583
-     * @throws EE_Error
584
-     * @throws ReflectionException
585
-     */
586
-    public function initialize_addons()
587
-    {
588
-        // foreach registered addon, make sure its db is up-to-date too
589
-        foreach ($this->registry->addons as $addon) {
590
-            if ($addon instanceof EE_Addon) {
591
-                $addon->initialize_db_if_no_migrations_required();
592
-            }
593
-        }
594
-    }
595
-
596
-
597
-    /**
598
-     * Adds the current code version to the saved wp option which stores a list of all ee versions ever installed.
599
-     *
600
-     * @param array  $version_history
601
-     * @param string $current_version_to_add version to be added to the version history
602
-     * @return    boolean success as to whether or not this option was changed
603
-     */
604
-    public function update_list_of_installed_versions($version_history = null, $current_version_to_add = null): bool
605
-    {
606
-        if (! $version_history) {
607
-            $version_history = $this->fix_espresso_db_upgrade_option($version_history);
608
-        }
609
-        if ($current_version_to_add === null) {
610
-            $current_version_to_add = espresso_version();
611
-        }
612
-        $version_history[ $current_version_to_add ][] = date('Y-m-d H:i:s', time());
613
-        // re-save
614
-        return update_option('espresso_db_update', $version_history);
615
-    }
616
-
617
-
618
-    /**
619
-     * Detects if the current version indicated in the has existed in the list of
620
-     * previously-installed versions of EE (espresso_db_update). Does NOT modify it (ie, no side-effect)
621
-     *
622
-     * @param array $espresso_db_update array from the wp option stored under the name 'espresso_db_update'.
623
-     *                                  If not supplied, fetches it from the options table.
624
-     *                                  Also, caches its result so later parts of the code can also know whether
625
-     *                                  there's been an update or not. This way we can add the current version to
626
-     *                                  espresso_db_update, but still know if this is a new install or not
627
-     * @return int one of the constants on EE_System::req_type_
628
-     */
629
-    public function detect_req_type($espresso_db_update = null): int
630
-    {
631
-        if ($this->_req_type === null) {
632
-            $espresso_db_update          = ! empty($espresso_db_update)
633
-                ? $espresso_db_update
634
-                : $this->fix_espresso_db_upgrade_option();
635
-            $this->_req_type             = EE_System::detect_req_type_given_activation_history(
636
-                $espresso_db_update,
637
-                'ee_espresso_activation',
638
-                espresso_version()
639
-            );
640
-            $this->_major_version_change = $this->_detect_major_version_change($espresso_db_update);
641
-            $this->request->setIsActivation($this->_req_type !== EE_System::req_type_normal);
642
-        }
643
-        return $this->_req_type;
644
-    }
645
-
646
-
647
-    /**
648
-     * Returns whether or not there was a non-micro version change (ie, change in either
649
-     * the first or second number in the version. Eg 4.9.0.rc.001 to 4.10.0.rc.000,
650
-     * but not 4.9.0.rc.0001 to 4.9.1.rc.0001
651
-     *
652
-     * @param $activation_history
653
-     * @return bool
654
-     */
655
-    private function _detect_major_version_change($activation_history): bool
656
-    {
657
-        $previous_version       = EE_System::getMostRecentlyActiveVersion($activation_history);
658
-        $previous_version_parts = explode('.', $previous_version);
659
-        $current_version_parts  = explode('.', espresso_version());
660
-        return isset(
661
-            $previous_version_parts[0],
662
-            $previous_version_parts[1],
663
-            $current_version_parts[0],
664
-            $current_version_parts[1]
665
-        ) && (
666
-            $previous_version_parts[0] !== $current_version_parts[0]
667
-            || $previous_version_parts[1] !== $current_version_parts[1]
668
-        );
669
-    }
670
-
671
-
672
-    /**
673
-     * Returns true if either the major or minor version of EE changed during this request.
674
-     * Eg 4.9.0.rc.001 to 4.10.0.rc.000, but not 4.9.0.rc.0001 to 4.9.1.rc.0001
675
-     *
676
-     * @return bool
677
-     */
678
-    public function is_major_version_change(): bool
679
-    {
680
-        return $this->_major_version_change;
681
-    }
682
-
683
-
684
-    /**
685
-     * Determines the request type for any ee addon, given three piece of info: the current array of activation
686
-     * histories (for core that' 'espresso_db_update' wp option); the name of the WordPress option which is temporarily
687
-     * set upon activation of the plugin (for core it's 'ee_espresso_activation'); and the version that this plugin was
688
-     * just activated to (for core that will always be espresso_version())
689
-     *
690
-     * @param array|null $activation_history             the option's value which stores the activation history for
691
-     *                                                 this
692
-     *                                                 ee plugin. for core that's 'espresso_db_update'
693
-     * @param string $activation_indicator_option_name the name of the WordPress option that is temporarily set to
694
-     *                                                 indicate that this plugin was just activated
695
-     * @param string $current_version                  the version that was just upgraded to (for core that will be
696
-     *                                                 espresso_version())
697
-     * @return int one of the constants on EE_System::req_type_
698
-     */
699
-    public static function detect_req_type_given_activation_history(
700
-        array $activation_history,
701
-        string $activation_indicator_option_name,
702
-        string $current_version
703
-    ): int {
704
-        $version_change = self::compareVersionWithPrevious($activation_history, $current_version);
705
-        $is_activation  = get_option($activation_indicator_option_name, false);
706
-        $req_type       = self::getRequestType($activation_history, $version_change, $is_activation);
707
-        if ($is_activation) {
708
-            // cleanup in aisle 6
709
-            delete_option($activation_indicator_option_name);
710
-        }
711
-        return $req_type;
712
-    }
713
-
714
-
715
-    /**
716
-     * @param array  $activation_history
717
-     * @param int    $version_change
718
-     * @param bool   $is_activation
719
-     * @return int
720
-     * @since $VID:$
721
-     */
722
-    private static function getRequestType(array $activation_history, int $version_change, bool $is_activation): int
723
-    {
724
-        // if no previous activation history exists, then this is a brand new install
725
-        if (empty($activation_history)) {
726
-            return EE_System::req_type_new_activation;
727
-        }
728
-        // current version is higher than previous version, so it's an upgrade
729
-        if ($version_change === 1) {
730
-            return EE_System::req_type_upgrade;
731
-        }
732
-        // current version is lower than previous version, so it's a downgrade
733
-        if ($version_change === -1) {
734
-            return EE_System::req_type_downgrade;
735
-        }
736
-        // version hasn't changed since last version so check if the activation indicator is set
737
-        // to determine if it's a reactivation, or just a normal request
738
-        return $is_activation
739
-            ? EE_System::req_type_reactivation
740
-            : EE_System::req_type_normal;
741
-    }
742
-
743
-
744
-    /**
745
-     * Detects if the $version_to_upgrade_to is higher than the most recent version in
746
-     * the $activation_history_for_addon
747
-     *
748
-     * @param array  $activation_history    array where keys are versions,
749
-     *                                      values are arrays of times activated (sometimes 'unknown-date')
750
-     * @param string $current_version
751
-     * @return int results of version_compare( $version_to_upgrade_to, $most_recently_active_version ).
752
-     *                                      -1 if $version_to_upgrade_to is LOWER (downgrade);
753
-     *                                      0 if $version_to_upgrade_to MATCHES (reactivation or normal request);
754
-     *                                      1 if $version_to_upgrade_to is HIGHER (upgrade) ;
755
-     */
756
-    private static function compareVersionWithPrevious(array $activation_history, string $current_version): int
757
-    {
758
-        // find the most recently-activated version
759
-        $most_recently_active_version = EE_System::getMostRecentlyActiveVersion($activation_history);
760
-        return version_compare($current_version, $most_recently_active_version);
761
-    }
762
-
763
-
764
-    /**
765
-     * Gets the most recently active version listed in the activation history,
766
-     * and if none are found (ie, it's a brand new install) returns '0.0.0.dev.000'.
767
-     *
768
-     * @param array $activation_history  (keys are versions, values are arrays of times activated,
769
-     *                                   sometimes containing 'unknown-date'
770
-     * @return string
771
-     */
772
-    private static function getMostRecentlyActiveVersion(array $activation_history): string
773
-    {
774
-        $most_recent_activation_date  = '1970-01-01 00:00:00';
775
-        $most_recently_active_version = '0.0.0.dev.000';
776
-        if (is_array($activation_history)) {
777
-            foreach ($activation_history as $version => $activation_dates) {
778
-                // check there is a record of when this version was activated.
779
-                // Otherwise, mark it as unknown
780
-                if (! $activation_dates) {
781
-                    $activation_dates = ['unknown-date'];
782
-                }
783
-                $activation_dates = is_string($activation_dates) ? [$activation_dates] : $activation_dates;
784
-                foreach ($activation_dates as $activation_date) {
785
-                    if ($activation_date !== 'unknown-date' && $activation_date > $most_recent_activation_date) {
786
-                        $most_recently_active_version = $version;
787
-                        $most_recent_activation_date  = $activation_date;
788
-                    }
789
-                }
790
-            }
791
-        }
792
-        return $most_recently_active_version;
793
-    }
794
-
795
-
796
-    /**
797
-     * This redirects to the about EE page after activation
798
-     *
799
-     * @return void
800
-     */
801
-    public function redirect_to_about_ee()
802
-    {
803
-        $notices = EE_Error::get_notices(false);
804
-        // if current user is an admin and it's not an ajax or rest request
805
-        if (
806
-            ! isset($notices['errors'])
807
-            && $this->request->isAdmin()
808
-            && apply_filters(
809
-                'FHEE__EE_System__redirect_to_about_ee__do_redirect',
810
-                $this->capabilities->current_user_can('manage_options', 'espresso_about_default')
811
-            )
812
-        ) {
813
-            $query_params = ['page' => 'espresso_about'];
814
-            if (EE_System::instance()->detect_req_type() === EE_System::req_type_new_activation) {
815
-                $query_params['new_activation'] = true;
816
-            }
817
-            if (EE_System::instance()->detect_req_type() === EE_System::req_type_reactivation) {
818
-                $query_params['reactivation'] = true;
819
-            }
820
-            $url = add_query_arg($query_params, admin_url('admin.php'));
821
-            EEH_URL::safeRedirectAndExit($url);
822
-        }
823
-    }
824
-
825
-
826
-    /**
827
-     * load_core_configuration
828
-     * this is hooked into 'AHEE__EE_Bootstrap__load_core_configuration'
829
-     * which runs during the WP 'plugins_loaded' action at priority 5
830
-     *
831
-     * @return void
832
-     * @throws ReflectionException
833
-     * @throws Exception
834
-     */
835
-    public function load_core_configuration()
836
-    {
837
-        do_action('AHEE__EE_System__load_core_configuration__begin', $this);
838
-        $this->loader->getShared('EE_Load_Textdomain');
839
-        // load textdomain
840
-        EE_Load_Textdomain::load_textdomain();
841
-        // load and setup EE_Config and EE_Network_Config
842
-        $config = $this->loader->getShared('EE_Config');
843
-        $this->loader->getShared('EE_Network_Config');
844
-        // setup autoloaders
845
-        // enable logging?
846
-        $this->loader->getShared('EventEspresso\core\services\orm\TrashLogger');
847
-        if ($config->admin->use_remote_logging) {
848
-            $this->loader->getShared('EE_Log');
849
-        }
850
-        // check for activation errors
851
-        $activation_errors = get_option('ee_plugin_activation_errors', false);
852
-        if ($activation_errors) {
853
-            EE_Error::add_error($activation_errors, __FILE__, __FUNCTION__, __LINE__);
854
-            update_option('ee_plugin_activation_errors', false);
855
-        }
856
-        // get model names
857
-        $this->_parse_model_names();
858
-        // configure custom post type definitions
859
-        $this->loader->getShared('EventEspresso\core\domain\entities\custom_post_types\CustomTaxonomyDefinitions');
860
-        $this->loader->getShared('EventEspresso\core\domain\entities\custom_post_types\CustomPostTypeDefinitions');
861
-        do_action('AHEE__EE_System__load_core_configuration__complete', $this);
862
-    }
863
-
864
-
865
-    /**
866
-     * cycles through all of the models/*.model.php files, and assembles an array of model names
867
-     *
868
-     * @return void
869
-     * @throws ReflectionException
870
-     */
871
-    private function _parse_model_names()
872
-    {
873
-        // get all the files in the EE_MODELS folder that end in .model.php
874
-        $models                 = glob(EE_MODELS . '*.model.php');
875
-        $model_names            = [];
876
-        $non_abstract_db_models = [];
877
-        foreach ($models as $model) {
878
-            // get model classname
879
-            $classname       = EEH_File::get_classname_from_filepath_with_standard_filename($model);
880
-            $short_name      = str_replace('EEM_', '', $classname);
881
-            $reflectionClass = new ReflectionClass($classname);
882
-            if ($reflectionClass->isSubclassOf('EEM_Base') && ! $reflectionClass->isAbstract()) {
883
-                $non_abstract_db_models[ $short_name ] = $classname;
884
-            }
885
-            $model_names[ $short_name ] = $classname;
886
-        }
887
-        $this->registry->models                 = apply_filters('FHEE__EE_System__parse_model_names', $model_names);
888
-        $this->registry->non_abstract_db_models = apply_filters(
889
-            'FHEE__EE_System__parse_implemented_model_names',
890
-            $non_abstract_db_models
891
-        );
892
-    }
893
-
894
-
895
-    /**
896
-     * @throws Exception
897
-     * @since 4.9.71.p
898
-     */
899
-    public function loadRouteMatchSpecifications()
900
-    {
901
-        try {
902
-            $this->loader->getShared('EventEspresso\core\services\routing\RouteMatchSpecificationManager');
903
-            $this->loader->getShared('EventEspresso\core\services\routing\RouteCollection');
904
-            $this->router->loadPrimaryRoutes();
905
-        } catch (Exception $exception) {
906
-            new ExceptionStackTraceDisplay($exception);
907
-        }
908
-        do_action('AHEE__EE_System__loadRouteMatchSpecifications');
909
-    }
910
-
911
-
912
-    /**
913
-     * loading CPT related classes earlier so that their definitions are available
914
-     * but not performing any actual registration with WP core until load_CPTs_and_session() is called
915
-     *
916
-     * @since   4.10.21.p
917
-     */
918
-    public function loadCustomPostTypes()
919
-    {
920
-        $this->register_custom_taxonomies = $this->loader->getShared(
921
-            'EventEspresso\core\domain\services\custom_post_types\RegisterCustomTaxonomies'
922
-        );
923
-        $this->register_custom_post_types = $this->loader->getShared(
924
-            'EventEspresso\core\domain\services\custom_post_types\RegisterCustomPostTypes'
925
-        );
926
-        $this->register_custom_taxonomy_terms = $this->loader->getShared(
927
-            'EventEspresso\core\domain\services\custom_post_types\RegisterCustomTaxonomyTerms'
928
-        );
929
-        // integrate WP_Query with the EE models
930
-        $this->loader->getShared('EE_CPT_Strategy');
931
-        // load legacy EE_Request_Handler in case add-ons still need it
932
-        $this->loader->getShared('EE_Request_Handler');
933
-    }
934
-
935
-
936
-    /**
937
-     * register_shortcodes_modules_and_widgets
938
-     * generate lists of shortcodes and modules, then verify paths and classes
939
-     * This is hooked into 'AHEE__EE_Bootstrap__register_shortcodes_modules_and_widgets'
940
-     * which runs during the WP 'plugins_loaded' action at priority 7
941
-     *
942
-     * @access public
943
-     * @return void
944
-     * @throws Exception
945
-     */
946
-    public function register_shortcodes_modules_and_widgets()
947
-    {
948
-        $this->router->registerShortcodesModulesAndWidgets();
949
-        do_action('AHEE__EE_System__register_shortcodes_modules_and_widgets');
950
-        // check for addons using old hook point
951
-        if (has_action('AHEE__EE_System__register_shortcodes_modules_and_addons')) {
952
-            $this->_incompatible_addon_error();
953
-        }
954
-    }
955
-
956
-
957
-    /**
958
-     * _incompatible_addon_error
959
-     *
960
-     * @access public
961
-     * @return void
962
-     */
963
-    private function _incompatible_addon_error()
964
-    {
965
-        // get array of classes hooking into here
966
-        $class_names = EEH_Class_Tools::get_class_names_for_all_callbacks_on_hook(
967
-            'AHEE__EE_System__register_shortcodes_modules_and_addons'
968
-        );
969
-        if (! empty($class_names)) {
970
-            $msg = esc_html__(
971
-                'The following plugins, addons, or modules appear to be incompatible with this version of Event Espresso and were automatically deactivated to avoid fatal errors:',
972
-                'event_espresso'
973
-            );
974
-            $msg .= '<ul>';
975
-            foreach ($class_names as $class_name) {
976
-                $msg .= '<li><b>Event Espresso - '
977
-                        . str_replace(
978
-                            ['EE_', 'EEM_', 'EED_', 'EES_', 'EEW_'],
979
-                            '',
980
-                            $class_name
981
-                        ) . '</b></li>';
982
-            }
983
-            $msg .= '</ul>';
984
-            $msg .= esc_html__(
985
-                'Compatibility issues can be avoided and/or resolved by keeping addons and plugins updated to the latest version.',
986
-                'event_espresso'
987
-            );
988
-            // save list of incompatible addons to wp-options for later use
989
-            add_option('ee_incompatible_addons', $class_names, '', 'no');
990
-            if (is_admin()) {
991
-                EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
992
-            }
993
-        }
994
-    }
995
-
996
-
997
-    /**
998
-     * brew_espresso
999
-     * begins the process of setting hooks for initializing EE in the correct order
1000
-     * This is happening on the 'AHEE__EE_Bootstrap__brew_espresso' hook point
1001
-     * which runs during the WP 'plugins_loaded' action at priority 9
1002
-     *
1003
-     * @return void
1004
-     * @throws Exception
1005
-     */
1006
-    public function brew_espresso()
1007
-    {
1008
-        do_action('AHEE__EE_System__brew_espresso__begin', $this);
1009
-        // load some final core systems
1010
-        add_action('init', [$this, 'set_hooks_for_core'], 1);
1011
-        add_action('init', [$this, 'perform_activations_upgrades_and_migrations'], 3);
1012
-        add_action('init', [$this, 'load_CPTs_and_session'], 5);
1013
-        add_action('init', [$this, 'load_controllers'], 7);
1014
-        add_action('init', [$this, 'core_loaded_and_ready'], 9);
1015
-        add_action('init', [$this, 'initialize'], 10);
1016
-        add_action('init', [$this, 'initialize_last'], 100);
1017
-        $this->router->brewEspresso();
1018
-        do_action('AHEE__EE_System__brew_espresso__complete', $this);
1019
-    }
1020
-
1021
-
1022
-    /**
1023
-     *    set_hooks_for_core
1024
-     *
1025
-     * @access public
1026
-     * @return    void
1027
-     * @throws EE_Error
1028
-     */
1029
-    public function set_hooks_for_core()
1030
-    {
1031
-        $this->_deactivate_incompatible_addons();
1032
-        do_action('AHEE__EE_System__set_hooks_for_core');
1033
-        $this->loader->getShared('EventEspresso\core\domain\values\session\SessionLifespan');
1034
-        // caps need to be initialized on every request so that capability maps are set.
1035
-        // @see https://events.codebasehq.com/projects/event-espresso/tickets/8674
1036
-        $this->registry->CAP->init_caps();
1037
-    }
1038
-
1039
-
1040
-    /**
1041
-     * Using the information gathered in EE_System::_incompatible_addon_error,
1042
-     * deactivates any addons considered incompatible with the current version of EE
1043
-     */
1044
-    private function _deactivate_incompatible_addons()
1045
-    {
1046
-        $incompatible_addons = get_option('ee_incompatible_addons', []);
1047
-        if (! empty($incompatible_addons)) {
1048
-            $active_plugins = get_option('active_plugins', []);
1049
-            foreach ($active_plugins as $active_plugin) {
1050
-                foreach ($incompatible_addons as $incompatible_addon) {
1051
-                    if (strpos($active_plugin, $incompatible_addon) !== false) {
1052
-                        $this->request->unSetRequestParams(['activate'], true);
1053
-                        espresso_deactivate_plugin($active_plugin);
1054
-                    }
1055
-                }
1056
-            }
1057
-        }
1058
-    }
1059
-
1060
-
1061
-    /**
1062
-     *    perform_activations_upgrades_and_migrations
1063
-     *
1064
-     * @access public
1065
-     * @return    void
1066
-     */
1067
-    public function perform_activations_upgrades_and_migrations()
1068
-    {
1069
-        do_action('AHEE__EE_System__perform_activations_upgrades_and_migrations');
1070
-    }
1071
-
1072
-
1073
-    /**
1074
-     * @return void
1075
-     * @throws DomainException
1076
-     */
1077
-    public function load_CPTs_and_session()
1078
-    {
1079
-        do_action('AHEE__EE_System__load_CPTs_and_session__start');
1080
-        $this->register_custom_taxonomies->registerCustomTaxonomies();
1081
-        $this->register_custom_post_types->registerCustomPostTypes();
1082
-        $this->register_custom_taxonomy_terms->registerCustomTaxonomyTerms();
1083
-        // load legacy Custom Post Types and Taxonomies
1084
-        $this->loader->getShared('EE_Register_CPTs');
1085
-        do_action('AHEE__EE_System__load_CPTs_and_session__complete');
1086
-    }
1087
-
1088
-
1089
-    /**
1090
-     * load_controllers
1091
-     * this is the best place to load any additional controllers that needs access to EE core.
1092
-     * it is expected that all basic core EE systems, that are not dependant on the current request are loaded at this
1093
-     * time
1094
-     *
1095
-     * @access public
1096
-     * @return void
1097
-     * @throws Exception
1098
-     */
1099
-    public function load_controllers()
1100
-    {
1101
-        do_action('AHEE__EE_System__load_controllers__start');
1102
-        $this->router->loadControllers();
1103
-        do_action('AHEE__EE_System__load_controllers__complete');
1104
-    }
1105
-
1106
-
1107
-    /**
1108
-     * core_loaded_and_ready
1109
-     * all of the basic EE core should be loaded at this point and available regardless of M-Mode
1110
-     *
1111
-     * @access public
1112
-     * @return void
1113
-     * @throws Exception
1114
-     */
1115
-    public function core_loaded_and_ready()
1116
-    {
1117
-        $this->router->coreLoadedAndReady();
1118
-        do_action('AHEE__EE_System__core_loaded_and_ready');
1119
-        // always load template tags, because it's faster than checking if it's a front-end request, and many page
1120
-        // builders require these even on the front-end
1121
-        require_once EE_PUBLIC . 'template_tags.php';
1122
-        do_action('AHEE__EE_System__set_hooks_for_shortcodes_modules_and_addons');
1123
-    }
1124
-
1125
-
1126
-    /**
1127
-     * initialize
1128
-     * this is the best place to begin initializing client code
1129
-     *
1130
-     * @access public
1131
-     * @return void
1132
-     */
1133
-    public function initialize()
1134
-    {
1135
-        do_action('AHEE__EE_System__initialize');
1136
-        add_filter(
1137
-            'safe_style_css',
1138
-            function ($styles) {
1139
-                $styles[] = 'display';
1140
-                $styles[] = 'visibility';
1141
-                $styles[] = 'position';
1142
-                $styles[] = 'top';
1143
-                $styles[] = 'right';
1144
-                $styles[] = 'bottom';
1145
-                $styles[] = 'left';
1146
-                $styles[] = 'resize';
1147
-                $styles[] = 'max-width';
1148
-                $styles[] = 'max-height';
1149
-                return $styles;
1150
-            }
1151
-        );
1152
-    }
1153
-
1154
-
1155
-    /**
1156
-     * initialize_last
1157
-     * this is run really late during the WP init hook point, and ensures that mostly everything else that needs to
1158
-     * initialize has done so
1159
-     *
1160
-     * @access public
1161
-     * @return void
1162
-     * @throws Exception
1163
-     */
1164
-    public function initialize_last()
1165
-    {
1166
-        $this->router->initializeLast();
1167
-        do_action('AHEE__EE_System__initialize_last');
1168
-        /** @var EventEspresso\core\domain\services\custom_post_types\RewriteRules $rewrite_rules */
1169
-        $rewrite_rules = $this->loader->getShared(
1170
-            'EventEspresso\core\domain\services\custom_post_types\RewriteRules'
1171
-        );
1172
-        $rewrite_rules->flushRewriteRules();
1173
-        add_action('admin_bar_init', [$this, 'addEspressoToolbar']);
1174
-    }
1175
-
1176
-
1177
-    /**
1178
-     * @return void
1179
-     */
1180
-    public function addEspressoToolbar()
1181
-    {
1182
-        $this->loader->getShared(
1183
-            'EventEspresso\core\domain\services\admin\AdminToolBar',
1184
-            [$this->registry->CAP]
1185
-        );
1186
-    }
1187
-
1188
-
1189
-    /**
1190
-     * do_not_cache
1191
-     * sets no cache headers and defines no cache constants for WP plugins
1192
-     *
1193
-     * @access public
1194
-     * @return void
1195
-     */
1196
-    public static function do_not_cache()
1197
-    {
1198
-        // set no cache constants
1199
-        if (! defined('DONOTCACHEPAGE')) {
1200
-            define('DONOTCACHEPAGE', true);
1201
-        }
1202
-        if (! defined('DONOTCACHCEOBJECT')) {
1203
-            define('DONOTCACHCEOBJECT', true);
1204
-        }
1205
-        if (! defined('DONOTCACHEDB')) {
1206
-            define('DONOTCACHEDB', true);
1207
-        }
1208
-        // add no cache headers
1209
-        add_action('send_headers', ['EE_System', 'nocache_headers'], 10);
1210
-        // plus a little extra for nginx and Google Chrome
1211
-        add_filter('nocache_headers', ['EE_System', 'extra_nocache_headers'], 10, 1);
1212
-        // prevent browsers from prefetching of the rel='next' link, because it may contain content that interferes with the registration process
1213
-        remove_action('wp_head', 'adjacent_posts_rel_link_wp_head');
1214
-    }
1215
-
1216
-
1217
-    /**
1218
-     *    extra_nocache_headers
1219
-     *
1220
-     * @access    public
1221
-     * @param $headers
1222
-     * @return    array
1223
-     */
1224
-    public static function extra_nocache_headers($headers): array
1225
-    {
1226
-        // for NGINX
1227
-        $headers['X-Accel-Expires'] = 0;
1228
-        // plus extra for Google Chrome since it doesn't seem to respect "no-cache", but WILL respect "no-store"
1229
-        $headers['Cache-Control'] = 'no-store, no-cache, must-revalidate, max-age=0';
1230
-        return $headers;
1231
-    }
1232
-
1233
-
1234
-    /**
1235
-     *    nocache_headers
1236
-     *
1237
-     * @access    public
1238
-     * @return    void
1239
-     */
1240
-    public static function nocache_headers()
1241
-    {
1242
-        nocache_headers();
1243
-    }
1244
-
1245
-
1246
-    /**
1247
-     * simply hooks into "wp_list_pages_exclude" filter (for wp_list_pages method) and makes sure EE critical pages are
1248
-     * never returned with the function.
1249
-     *
1250
-     * @param array $exclude_array any existing pages being excluded are in this array.
1251
-     * @return array
1252
-     */
1253
-    public function remove_pages_from_wp_list_pages(array $exclude_array): array
1254
-    {
1255
-        return array_merge($exclude_array, $this->registry->CFG->core->get_critical_pages_array());
1256
-    }
27
+	/**
28
+	 * indicates this is a 'normal' request. Ie, not activation, nor upgrade, nor activation.
29
+	 * So examples of this would be a normal GET request on the frontend or backend, or a POST, etc
30
+	 */
31
+	const req_type_normal = 0;
32
+
33
+	/**
34
+	 * Indicates this is a brand new installation of EE so we should install
35
+	 * tables and default data etc
36
+	 */
37
+	const req_type_new_activation = 1;
38
+
39
+	/**
40
+	 * we've detected that EE has been reactivated (or EE was activated during maintenance mode,
41
+	 * and we just exited maintenance mode). We MUST check the database is setup properly
42
+	 * and that default data is setup too
43
+	 */
44
+	const req_type_reactivation = 2;
45
+
46
+	/**
47
+	 * indicates that EE has been upgraded since its previous request.
48
+	 * We may have data migration scripts to call and will want to trigger maintenance mode
49
+	 */
50
+	const req_type_upgrade = 3;
51
+
52
+	/**
53
+	 * TODO  will detect that EE has been DOWNGRADED. We probably don't want to run in this case...
54
+	 */
55
+	const req_type_downgrade = 4;
56
+
57
+	/**
58
+	 * @deprecated since version 4.6.0.dev.006
59
+	 * Now whenever a new_activation is detected the request type is still just
60
+	 * new_activation (same for reactivation, upgrade, downgrade etc), but if we're in maintenance mode
61
+	 * EE_System::initialize_db_if_no_migrations_required and EE_Addon::initialize_db_if_no_migrations_required
62
+	 * will instead enqueue that EE plugin's db initialization for when we're taken out of maintenance mode.
63
+	 * (Specifically, when the migration manager indicates migrations are finished
64
+	 * EE_Data_Migration_Manager::initialize_db_for_enqueued_ee_plugins() will be called)
65
+	 */
66
+	const req_type_activation_but_not_installed = 5;
67
+
68
+	/**
69
+	 * option prefix for recording the activation history (like core's "espresso_db_update") of addons
70
+	 */
71
+	const addon_activation_history_option_prefix = 'ee_addon_activation_history_';
72
+
73
+	/**
74
+	 * @var AddonManager $addon_manager
75
+	 */
76
+	private $addon_manager;
77
+
78
+	/**
79
+	 * @var EE_System $_instance
80
+	 */
81
+	private static $_instance;
82
+
83
+	/**
84
+	 * @var EE_Registry $registry
85
+	 */
86
+	private $registry;
87
+
88
+	/**
89
+	 * @var LoaderInterface $loader
90
+	 */
91
+	private $loader;
92
+
93
+	/**
94
+	 * @var EE_Capabilities $capabilities
95
+	 */
96
+	private $capabilities;
97
+
98
+	/**
99
+	 * @var EE_Maintenance_Mode $maintenance_mode
100
+	 */
101
+	private $maintenance_mode;
102
+
103
+	/**
104
+	 * @var RequestInterface $request
105
+	 */
106
+	private $request;
107
+
108
+	/**
109
+	 * Stores which type of request this is, options being one of the constants on EE_System starting with req_type_*.
110
+	 * It can be a brand-new activation, a reactivation, an upgrade, a downgrade, or a normal request.
111
+	 *
112
+	 * @var int $_req_type
113
+	 */
114
+	private $_req_type;
115
+
116
+	/**
117
+	 * Whether or not there was a non-micro version change in EE core version during this request
118
+	 *
119
+	 * @var boolean $_major_version_change
120
+	 */
121
+	private $_major_version_change = false;
122
+
123
+	/**
124
+	 * @var Router $router
125
+	 */
126
+	private $router;
127
+
128
+	/**
129
+	 * @param EventEspresso\core\domain\services\custom_post_types\RegisterCustomPostTypes
130
+	 */
131
+	private $register_custom_post_types;
132
+
133
+	/**
134
+	 * @param EventEspresso\core\domain\services\custom_post_types\RegisterCustomTaxonomies
135
+	 */
136
+	private $register_custom_taxonomies;
137
+
138
+	/**
139
+	 * @param EventEspresso\core\domain\services\custom_post_types\RegisterCustomTaxonomyTerms
140
+	 */
141
+	private $register_custom_taxonomy_terms;
142
+
143
+	/**
144
+	 * @singleton method used to instantiate class object
145
+	 * @param LoaderInterface|null     $loader
146
+	 * @param EE_Maintenance_Mode|null $maintenance_mode
147
+	 * @param EE_Registry|null         $registry
148
+	 * @param RequestInterface|null    $request
149
+	 * @param Router|null              $router
150
+	 * @return EE_System
151
+	 */
152
+	public static function instance(
153
+		LoaderInterface $loader = null,
154
+		EE_Maintenance_Mode $maintenance_mode = null,
155
+		EE_Registry $registry = null,
156
+		RequestInterface $request = null,
157
+		Router $router = null
158
+	): EE_System {
159
+		// check if class object is instantiated
160
+		if (! self::$_instance instanceof EE_System) {
161
+			self::$_instance = new self($loader, $maintenance_mode, $registry, $request, $router);
162
+		}
163
+		return self::$_instance;
164
+	}
165
+
166
+
167
+	/**
168
+	 * resets the instance and returns it
169
+	 *
170
+	 * @return EE_System
171
+	 */
172
+	public static function reset(): EE_System
173
+	{
174
+		self::$_instance->_req_type = null;
175
+		// make sure none of the old hooks are left hanging around
176
+		remove_all_actions('AHEE__EE_System__perform_activations_upgrades_and_migrations');
177
+		// we need to reset the migration manager in order for it to detect DMSs properly
178
+		EE_Data_Migration_Manager::reset();
179
+		self::instance()->detect_activations_or_upgrades();
180
+		self::instance()->perform_activations_upgrades_and_migrations();
181
+		return self::instance();
182
+	}
183
+
184
+
185
+	/**
186
+	 * sets hooks for running rest of system
187
+	 * provides "AHEE__EE_System__construct__complete" hook for EE Addons to use as their starting point
188
+	 * starting EE Addons from any other point may lead to problems
189
+	 *
190
+	 * @param LoaderInterface     $loader
191
+	 * @param EE_Maintenance_Mode $maintenance_mode
192
+	 * @param EE_Registry         $registry
193
+	 * @param RequestInterface    $request
194
+	 * @param Router              $router
195
+	 */
196
+	private function __construct(
197
+		LoaderInterface $loader,
198
+		EE_Maintenance_Mode $maintenance_mode,
199
+		EE_Registry $registry,
200
+		RequestInterface $request,
201
+		Router $router
202
+	) {
203
+		$this->registry         = $registry;
204
+		$this->loader           = $loader;
205
+		$this->request          = $request;
206
+		$this->router           = $router;
207
+		$this->maintenance_mode = $maintenance_mode;
208
+		do_action('AHEE__EE_System__construct__begin', $this);
209
+		add_action(
210
+			'AHEE__EE_Bootstrap__load_espresso_addons',
211
+			[$this, 'loadCapabilities'],
212
+			5
213
+		);
214
+		add_action(
215
+			'AHEE__EE_Bootstrap__load_espresso_addons',
216
+			[$this, 'loadCommandBus'],
217
+			7
218
+		);
219
+		add_action(
220
+			'AHEE__EE_Bootstrap__load_espresso_addons',
221
+			[$this, 'loadPluginApi'],
222
+			9
223
+		);
224
+		// give caff stuff a chance to play during the activation process too.
225
+		add_action(
226
+			'AHEE__EE_Bootstrap__load_espresso_addons',
227
+			[$this, 'brewCaffeinated'],
228
+			9
229
+		);
230
+		// allow addons to load first so that they can register autoloaders, set hooks for running DMS's, etc
231
+		add_action(
232
+			'AHEE__EE_Bootstrap__load_espresso_addons',
233
+			[$this, 'load_espresso_addons']
234
+		);
235
+		// when an ee addon is activated, we want to call the core hook(s) again
236
+		// because the newly-activated addon didn't get a chance to run at all
237
+		add_action('activate_plugin', [$this, 'load_espresso_addons'], 1);
238
+		// detect whether install or upgrade
239
+		add_action(
240
+			'AHEE__EE_Bootstrap__detect_activations_or_upgrades',
241
+			[$this, 'detect_activations_or_upgrades'],
242
+			3
243
+		);
244
+		// load EE_Config, EE_Textdomain, etc
245
+		add_action(
246
+			'AHEE__EE_Bootstrap__load_core_configuration',
247
+			[$this, 'load_core_configuration'],
248
+			5
249
+		);
250
+		// load specifications for matching routes to current request
251
+		add_action(
252
+			'AHEE__EE_Bootstrap__load_core_configuration',
253
+			[$this, 'loadRouteMatchSpecifications']
254
+		);
255
+		// load specifications for custom post types
256
+		add_action(
257
+			'AHEE__EE_Bootstrap__load_core_configuration',
258
+			array($this, 'loadCustomPostTypes')
259
+		);
260
+		// load specifications for custom post types
261
+		add_action(
262
+			'AHEE__EE_Bootstrap__load_core_configuration',
263
+			array($this, 'loadCustomPostTypes')
264
+		);
265
+		// load EE_Config, EE_Textdomain, etc
266
+		add_action(
267
+			'AHEE__EE_Bootstrap__register_shortcodes_modules_and_widgets',
268
+			[$this, 'register_shortcodes_modules_and_widgets'],
269
+			7
270
+		);
271
+		// you wanna get going? I wanna get going... let's get going!
272
+		add_action(
273
+			'AHEE__EE_Bootstrap__brew_espresso',
274
+			[$this, 'brew_espresso'],
275
+			9
276
+		);
277
+		// other housekeeping
278
+		// exclude EE critical pages from wp_list_pages
279
+		add_filter(
280
+			'wp_list_pages_excludes',
281
+			[$this, 'remove_pages_from_wp_list_pages'],
282
+			10
283
+		);
284
+		// ALL EE Addons should use the following hook point to attach their initial setup too
285
+		// it's extremely important for EE Addons to register any class autoloaders so that they can be available when the EE_Config loads
286
+		do_action('AHEE__EE_System__construct__complete', $this);
287
+	}
288
+
289
+
290
+	/**
291
+	 * load and setup EE_Capabilities
292
+	 *
293
+	 * @return void
294
+	 */
295
+	public function loadCapabilities()
296
+	{
297
+		$this->capabilities = $this->loader->getShared('EE_Capabilities');
298
+		add_action(
299
+			'AHEE__EE_Capabilities__init_caps__before_initialization',
300
+			function () {
301
+				LoaderFactory::getLoader()->getShared('EventEspresso\PaymentMethods\Manager');
302
+				LoaderFactory::getLoader()->getShared('EE_Payment_Method_Manager');
303
+			}
304
+		);
305
+	}
306
+
307
+
308
+	/**
309
+	 * create and cache the CommandBus, and also add middleware
310
+	 * The CapChecker middleware requires the use of EE_Capabilities
311
+	 * which is why we need to load the CommandBus after Caps are set up
312
+	 * CommandBus middleware operate FIFO - First In First Out
313
+	 * so LocateMovedCommands will run first in order to return any new commands
314
+	 *
315
+	 * @return void
316
+	 */
317
+	public function loadCommandBus()
318
+	{
319
+		$this->loader->getShared(
320
+			'CommandBusInterface',
321
+			[
322
+				null,
323
+				apply_filters(
324
+					'FHEE__EE_Load_Espresso_Core__handle_request__CommandBus_middleware',
325
+					[
326
+						$this->loader->getShared('EventEspresso\core\services\commands\middleware\LocateMovedCommands'),
327
+						$this->loader->getShared('EventEspresso\core\services\commands\middleware\CapChecker'),
328
+						$this->loader->getShared('EventEspresso\core\services\commands\middleware\AddActionHook'),
329
+					]
330
+				),
331
+			]
332
+		);
333
+	}
334
+
335
+
336
+	/**
337
+	 * @return void
338
+	 * @throws Exception
339
+	 */
340
+	public function loadPluginApi()
341
+	{
342
+		$this->addon_manager = $this->loader->getShared(AddonManager::class);
343
+		$this->addon_manager->initialize();
344
+		$this->loader->getShared('EE_Request_Handler');
345
+	}
346
+
347
+
348
+	/**
349
+	 * The purpose of this method is to simply check for a file named "caffeinated/brewing_regular.php" for any hooks
350
+	 * that need to be setup before our EE_System launches.
351
+	 *
352
+	 * @return void
353
+	 * @throws DomainException
354
+	 * @throws InvalidArgumentException
355
+	 * @throws InvalidDataTypeException
356
+	 * @throws InvalidInterfaceException
357
+	 * @throws InvalidClassException
358
+	 * @throws InvalidFilePathException
359
+	 * @throws EE_Error
360
+	 */
361
+	public function brewCaffeinated()
362
+	{
363
+		static $brew;
364
+		/** @var Domain $domain */
365
+		$domain = DomainFactory::getEventEspressoCoreDomain();
366
+		if ($domain->isCaffeinated() && ! $brew instanceof EE_Brewing_Regular) {
367
+			require_once EE_CAFF_PATH . 'brewing_regular.php';
368
+			/** @var EE_Brewing_Regular $brew */
369
+			$brew = LoaderFactory::getLoader()->getShared(EE_Brewing_Regular::class);
370
+			$brew->initializePUE();
371
+			add_action(
372
+				'AHEE__EE_System__load_core_configuration__begin',
373
+				[$brew, 'caffeinated']
374
+			);
375
+		}
376
+	}
377
+
378
+
379
+	/**
380
+	 * load_espresso_addons
381
+	 * allow addons to load first so that they can set hooks for running DMS's, etc
382
+	 * this is hooked into both:
383
+	 *    'AHEE__EE_Bootstrap__load_core_configuration'
384
+	 *        which runs during the WP 'plugins_loaded' action at priority 5
385
+	 *    and the WP 'activate_plugin' hook point
386
+	 *
387
+	 * @return void
388
+	 * @throws Exception
389
+	 */
390
+	public function load_espresso_addons()
391
+	{
392
+		// looking for hooks? they've been moved into the AddonManager to maintain compatibility
393
+		$this->addon_manager->loadAddons();
394
+	}
395
+
396
+
397
+	/**
398
+	 * detect_activations_or_upgrades
399
+	 * Checks for activation or upgrade of core first;
400
+	 * then also checks if any registered addons have been activated or upgraded
401
+	 * This is hooked into 'AHEE__EE_Bootstrap__detect_activations_or_upgrades'
402
+	 * which runs during the WP 'plugins_loaded' action at priority 3
403
+	 *
404
+	 * @access public
405
+	 * @return void
406
+	 */
407
+	public function detect_activations_or_upgrades()
408
+	{
409
+		// first off: let's make sure to handle core
410
+		$this->detect_if_activation_or_upgrade();
411
+		foreach ($this->registry->addons as $addon) {
412
+			if ($addon instanceof EE_Addon) {
413
+				// detect teh request type for that addon
414
+				$addon->detect_req_type();
415
+			}
416
+		}
417
+	}
418
+
419
+
420
+	/**
421
+	 * detect_if_activation_or_upgrade
422
+	 * Takes care of detecting whether this is a brand new install or code upgrade,
423
+	 * and either setting up the DB or setting up maintenance mode etc.
424
+	 *
425
+	 * @access public
426
+	 * @return void
427
+	 */
428
+	public function detect_if_activation_or_upgrade()
429
+	{
430
+		do_action('AHEE__EE_System___detect_if_activation_or_upgrade__begin');
431
+		// check if db has been updated, or if its a brand-new installation
432
+		$espresso_db_update = $this->fix_espresso_db_upgrade_option();
433
+		$request_type       = $this->detect_req_type($espresso_db_update);
434
+		// EEH_Debug_Tools::printr( $request_type, '$request_type', __FILE__, __LINE__ );
435
+		switch ($request_type) {
436
+			case EE_System::req_type_new_activation:
437
+				do_action('AHEE__EE_System__detect_if_activation_or_upgrade__new_activation');
438
+				$this->_handle_core_version_change($espresso_db_update);
439
+				break;
440
+			case EE_System::req_type_reactivation:
441
+				do_action('AHEE__EE_System__detect_if_activation_or_upgrade__reactivation');
442
+				$this->_handle_core_version_change($espresso_db_update);
443
+				break;
444
+			case EE_System::req_type_upgrade:
445
+				do_action('AHEE__EE_System__detect_if_activation_or_upgrade__upgrade');
446
+				// migrations may be required now that we've upgraded
447
+				$this->maintenance_mode->set_maintenance_mode_if_db_old();
448
+				$this->_handle_core_version_change($espresso_db_update);
449
+				break;
450
+			case EE_System::req_type_downgrade:
451
+				do_action('AHEE__EE_System__detect_if_activation_or_upgrade__downgrade');
452
+				// its possible migrations are no longer required
453
+				$this->maintenance_mode->set_maintenance_mode_if_db_old();
454
+				$this->_handle_core_version_change($espresso_db_update);
455
+				break;
456
+			case EE_System::req_type_normal:
457
+			default:
458
+				break;
459
+		}
460
+		do_action('AHEE__EE_System__detect_if_activation_or_upgrade__complete');
461
+	}
462
+
463
+
464
+	/**
465
+	 * Updates the list of installed versions and sets hooks for
466
+	 * initializing the database later during the request
467
+	 *
468
+	 * @param array $espresso_db_update
469
+	 */
470
+	private function _handle_core_version_change(array $espresso_db_update)
471
+	{
472
+		$this->update_list_of_installed_versions($espresso_db_update);
473
+		// get ready to verify the DB is ok (provided we aren't in maintenance mode, of course)
474
+		add_action(
475
+			'AHEE__EE_System__perform_activations_upgrades_and_migrations',
476
+			[$this, 'initialize_db_if_no_migrations_required']
477
+		);
478
+	}
479
+
480
+
481
+	/**
482
+	 * standardizes the wp option 'espresso_db_upgrade' which actually stores
483
+	 * information about what versions of EE have been installed and activated,
484
+	 * NOT necessarily the state of the database
485
+	 *
486
+	 * @param mixed $espresso_db_update           the value of the WordPress option.
487
+	 *                                            If not supplied, fetches it from the options table
488
+	 * @return array the correct value of 'espresso_db_upgrade', after saving it, if it needed correction
489
+	 */
490
+	private function fix_espresso_db_upgrade_option($espresso_db_update = null): array
491
+	{
492
+		do_action('FHEE__EE_System__manage_fix_espresso_db_upgrade_option__begin', $espresso_db_update);
493
+		if (! $espresso_db_update) {
494
+			$espresso_db_update = get_option('espresso_db_update');
495
+		}
496
+		// check that option is an array
497
+		if (! is_array($espresso_db_update)) {
498
+			// if option is FALSE, then it never existed
499
+			if ($espresso_db_update === false) {
500
+				// make $espresso_db_update an array and save option with autoload OFF
501
+				$espresso_db_update = [];
502
+				add_option('espresso_db_update', $espresso_db_update, '', 'no');
503
+			} else {
504
+				// option is NOT FALSE but also is NOT an array, so make it an array and save it
505
+				$espresso_db_update = [$espresso_db_update => []];
506
+				update_option('espresso_db_update', $espresso_db_update);
507
+			}
508
+		} else {
509
+			$corrected_db_update = [];
510
+			// if IS an array, but is it an array where KEYS are version numbers, and values are arrays?
511
+			foreach ($espresso_db_update as $should_be_version_string => $should_be_array) {
512
+				if (is_int($should_be_version_string) && ! is_array($should_be_array)) {
513
+					// the key is an int, and the value IS NOT an array
514
+					// so it must be numerically-indexed, where values are versions installed...
515
+					// fix it!
516
+					$version_string                         = $should_be_array;
517
+					$corrected_db_update[ $version_string ] = ['unknown-date'];
518
+				} else {
519
+					// ok it checks out
520
+					$corrected_db_update[ $should_be_version_string ] = $should_be_array;
521
+				}
522
+			}
523
+			$espresso_db_update = $corrected_db_update;
524
+			update_option('espresso_db_update', $espresso_db_update);
525
+		}
526
+		do_action('FHEE__EE_System__manage_fix_espresso_db_upgrade_option__complete', $espresso_db_update);
527
+		return ! empty($espresso_db_update) ? $espresso_db_update : [];
528
+	}
529
+
530
+
531
+	/**
532
+	 * Does the traditional work of setting up the plugin's database and adding default data.
533
+	 * If migration script/process did not exist, this is what would happen on every activation/reactivation/upgrade.
534
+	 * NOTE: if we're in maintenance mode (which would be the case if we detect there are data
535
+	 * migration scripts that need to be run and a version change happens), enqueues core for database initialization,
536
+	 * so that it will be done when migrations are finished
537
+	 *
538
+	 * @param boolean $initialize_addons_too if true, we double-check addons' database tables etc too;
539
+	 * @param boolean $verify_schema         if true will re-check the database tables have the correct schema.
540
+	 *                                       This is a resource-intensive job
541
+	 *                                       so we prefer to only do it when necessary
542
+	 * @return void
543
+	 * @throws EE_Error
544
+	 * @throws ReflectionException
545
+	 */
546
+	public function initialize_db_if_no_migrations_required($initialize_addons_too = false, $verify_schema = true)
547
+	{
548
+		$request_type = $this->detect_req_type();
549
+		// only initialize system if we're not in maintenance mode.
550
+		if ($this->maintenance_mode->level() !== EE_Maintenance_Mode::level_2_complete_maintenance) {
551
+			/** @var EventEspresso\core\domain\services\custom_post_types\RewriteRules $rewrite_rules */
552
+			$rewrite_rules = $this->loader->getShared(
553
+				'EventEspresso\core\domain\services\custom_post_types\RewriteRules'
554
+			);
555
+			$rewrite_rules->flush();
556
+			if ($verify_schema) {
557
+				EEH_Activation::initialize_db_and_folders();
558
+			}
559
+			EEH_Activation::initialize_db_content();
560
+			EEH_Activation::system_initialization();
561
+			if ($initialize_addons_too) {
562
+				$this->initialize_addons();
563
+			}
564
+		} else {
565
+			EE_Data_Migration_Manager::instance()->enqueue_db_initialization_for('Core');
566
+		}
567
+		if (
568
+			$request_type === EE_System::req_type_new_activation
569
+			|| $request_type === EE_System::req_type_reactivation
570
+			|| (
571
+				$request_type === EE_System::req_type_upgrade
572
+				&& $this->is_major_version_change()
573
+			)
574
+		) {
575
+			add_action('AHEE__EE_System__initialize_last', [$this, 'redirect_to_about_ee'], 9);
576
+		}
577
+	}
578
+
579
+
580
+	/**
581
+	 * Initializes the db for all registered addons
582
+	 *
583
+	 * @throws EE_Error
584
+	 * @throws ReflectionException
585
+	 */
586
+	public function initialize_addons()
587
+	{
588
+		// foreach registered addon, make sure its db is up-to-date too
589
+		foreach ($this->registry->addons as $addon) {
590
+			if ($addon instanceof EE_Addon) {
591
+				$addon->initialize_db_if_no_migrations_required();
592
+			}
593
+		}
594
+	}
595
+
596
+
597
+	/**
598
+	 * Adds the current code version to the saved wp option which stores a list of all ee versions ever installed.
599
+	 *
600
+	 * @param array  $version_history
601
+	 * @param string $current_version_to_add version to be added to the version history
602
+	 * @return    boolean success as to whether or not this option was changed
603
+	 */
604
+	public function update_list_of_installed_versions($version_history = null, $current_version_to_add = null): bool
605
+	{
606
+		if (! $version_history) {
607
+			$version_history = $this->fix_espresso_db_upgrade_option($version_history);
608
+		}
609
+		if ($current_version_to_add === null) {
610
+			$current_version_to_add = espresso_version();
611
+		}
612
+		$version_history[ $current_version_to_add ][] = date('Y-m-d H:i:s', time());
613
+		// re-save
614
+		return update_option('espresso_db_update', $version_history);
615
+	}
616
+
617
+
618
+	/**
619
+	 * Detects if the current version indicated in the has existed in the list of
620
+	 * previously-installed versions of EE (espresso_db_update). Does NOT modify it (ie, no side-effect)
621
+	 *
622
+	 * @param array $espresso_db_update array from the wp option stored under the name 'espresso_db_update'.
623
+	 *                                  If not supplied, fetches it from the options table.
624
+	 *                                  Also, caches its result so later parts of the code can also know whether
625
+	 *                                  there's been an update or not. This way we can add the current version to
626
+	 *                                  espresso_db_update, but still know if this is a new install or not
627
+	 * @return int one of the constants on EE_System::req_type_
628
+	 */
629
+	public function detect_req_type($espresso_db_update = null): int
630
+	{
631
+		if ($this->_req_type === null) {
632
+			$espresso_db_update          = ! empty($espresso_db_update)
633
+				? $espresso_db_update
634
+				: $this->fix_espresso_db_upgrade_option();
635
+			$this->_req_type             = EE_System::detect_req_type_given_activation_history(
636
+				$espresso_db_update,
637
+				'ee_espresso_activation',
638
+				espresso_version()
639
+			);
640
+			$this->_major_version_change = $this->_detect_major_version_change($espresso_db_update);
641
+			$this->request->setIsActivation($this->_req_type !== EE_System::req_type_normal);
642
+		}
643
+		return $this->_req_type;
644
+	}
645
+
646
+
647
+	/**
648
+	 * Returns whether or not there was a non-micro version change (ie, change in either
649
+	 * the first or second number in the version. Eg 4.9.0.rc.001 to 4.10.0.rc.000,
650
+	 * but not 4.9.0.rc.0001 to 4.9.1.rc.0001
651
+	 *
652
+	 * @param $activation_history
653
+	 * @return bool
654
+	 */
655
+	private function _detect_major_version_change($activation_history): bool
656
+	{
657
+		$previous_version       = EE_System::getMostRecentlyActiveVersion($activation_history);
658
+		$previous_version_parts = explode('.', $previous_version);
659
+		$current_version_parts  = explode('.', espresso_version());
660
+		return isset(
661
+			$previous_version_parts[0],
662
+			$previous_version_parts[1],
663
+			$current_version_parts[0],
664
+			$current_version_parts[1]
665
+		) && (
666
+			$previous_version_parts[0] !== $current_version_parts[0]
667
+			|| $previous_version_parts[1] !== $current_version_parts[1]
668
+		);
669
+	}
670
+
671
+
672
+	/**
673
+	 * Returns true if either the major or minor version of EE changed during this request.
674
+	 * Eg 4.9.0.rc.001 to 4.10.0.rc.000, but not 4.9.0.rc.0001 to 4.9.1.rc.0001
675
+	 *
676
+	 * @return bool
677
+	 */
678
+	public function is_major_version_change(): bool
679
+	{
680
+		return $this->_major_version_change;
681
+	}
682
+
683
+
684
+	/**
685
+	 * Determines the request type for any ee addon, given three piece of info: the current array of activation
686
+	 * histories (for core that' 'espresso_db_update' wp option); the name of the WordPress option which is temporarily
687
+	 * set upon activation of the plugin (for core it's 'ee_espresso_activation'); and the version that this plugin was
688
+	 * just activated to (for core that will always be espresso_version())
689
+	 *
690
+	 * @param array|null $activation_history             the option's value which stores the activation history for
691
+	 *                                                 this
692
+	 *                                                 ee plugin. for core that's 'espresso_db_update'
693
+	 * @param string $activation_indicator_option_name the name of the WordPress option that is temporarily set to
694
+	 *                                                 indicate that this plugin was just activated
695
+	 * @param string $current_version                  the version that was just upgraded to (for core that will be
696
+	 *                                                 espresso_version())
697
+	 * @return int one of the constants on EE_System::req_type_
698
+	 */
699
+	public static function detect_req_type_given_activation_history(
700
+		array $activation_history,
701
+		string $activation_indicator_option_name,
702
+		string $current_version
703
+	): int {
704
+		$version_change = self::compareVersionWithPrevious($activation_history, $current_version);
705
+		$is_activation  = get_option($activation_indicator_option_name, false);
706
+		$req_type       = self::getRequestType($activation_history, $version_change, $is_activation);
707
+		if ($is_activation) {
708
+			// cleanup in aisle 6
709
+			delete_option($activation_indicator_option_name);
710
+		}
711
+		return $req_type;
712
+	}
713
+
714
+
715
+	/**
716
+	 * @param array  $activation_history
717
+	 * @param int    $version_change
718
+	 * @param bool   $is_activation
719
+	 * @return int
720
+	 * @since $VID:$
721
+	 */
722
+	private static function getRequestType(array $activation_history, int $version_change, bool $is_activation): int
723
+	{
724
+		// if no previous activation history exists, then this is a brand new install
725
+		if (empty($activation_history)) {
726
+			return EE_System::req_type_new_activation;
727
+		}
728
+		// current version is higher than previous version, so it's an upgrade
729
+		if ($version_change === 1) {
730
+			return EE_System::req_type_upgrade;
731
+		}
732
+		// current version is lower than previous version, so it's a downgrade
733
+		if ($version_change === -1) {
734
+			return EE_System::req_type_downgrade;
735
+		}
736
+		// version hasn't changed since last version so check if the activation indicator is set
737
+		// to determine if it's a reactivation, or just a normal request
738
+		return $is_activation
739
+			? EE_System::req_type_reactivation
740
+			: EE_System::req_type_normal;
741
+	}
742
+
743
+
744
+	/**
745
+	 * Detects if the $version_to_upgrade_to is higher than the most recent version in
746
+	 * the $activation_history_for_addon
747
+	 *
748
+	 * @param array  $activation_history    array where keys are versions,
749
+	 *                                      values are arrays of times activated (sometimes 'unknown-date')
750
+	 * @param string $current_version
751
+	 * @return int results of version_compare( $version_to_upgrade_to, $most_recently_active_version ).
752
+	 *                                      -1 if $version_to_upgrade_to is LOWER (downgrade);
753
+	 *                                      0 if $version_to_upgrade_to MATCHES (reactivation or normal request);
754
+	 *                                      1 if $version_to_upgrade_to is HIGHER (upgrade) ;
755
+	 */
756
+	private static function compareVersionWithPrevious(array $activation_history, string $current_version): int
757
+	{
758
+		// find the most recently-activated version
759
+		$most_recently_active_version = EE_System::getMostRecentlyActiveVersion($activation_history);
760
+		return version_compare($current_version, $most_recently_active_version);
761
+	}
762
+
763
+
764
+	/**
765
+	 * Gets the most recently active version listed in the activation history,
766
+	 * and if none are found (ie, it's a brand new install) returns '0.0.0.dev.000'.
767
+	 *
768
+	 * @param array $activation_history  (keys are versions, values are arrays of times activated,
769
+	 *                                   sometimes containing 'unknown-date'
770
+	 * @return string
771
+	 */
772
+	private static function getMostRecentlyActiveVersion(array $activation_history): string
773
+	{
774
+		$most_recent_activation_date  = '1970-01-01 00:00:00';
775
+		$most_recently_active_version = '0.0.0.dev.000';
776
+		if (is_array($activation_history)) {
777
+			foreach ($activation_history as $version => $activation_dates) {
778
+				// check there is a record of when this version was activated.
779
+				// Otherwise, mark it as unknown
780
+				if (! $activation_dates) {
781
+					$activation_dates = ['unknown-date'];
782
+				}
783
+				$activation_dates = is_string($activation_dates) ? [$activation_dates] : $activation_dates;
784
+				foreach ($activation_dates as $activation_date) {
785
+					if ($activation_date !== 'unknown-date' && $activation_date > $most_recent_activation_date) {
786
+						$most_recently_active_version = $version;
787
+						$most_recent_activation_date  = $activation_date;
788
+					}
789
+				}
790
+			}
791
+		}
792
+		return $most_recently_active_version;
793
+	}
794
+
795
+
796
+	/**
797
+	 * This redirects to the about EE page after activation
798
+	 *
799
+	 * @return void
800
+	 */
801
+	public function redirect_to_about_ee()
802
+	{
803
+		$notices = EE_Error::get_notices(false);
804
+		// if current user is an admin and it's not an ajax or rest request
805
+		if (
806
+			! isset($notices['errors'])
807
+			&& $this->request->isAdmin()
808
+			&& apply_filters(
809
+				'FHEE__EE_System__redirect_to_about_ee__do_redirect',
810
+				$this->capabilities->current_user_can('manage_options', 'espresso_about_default')
811
+			)
812
+		) {
813
+			$query_params = ['page' => 'espresso_about'];
814
+			if (EE_System::instance()->detect_req_type() === EE_System::req_type_new_activation) {
815
+				$query_params['new_activation'] = true;
816
+			}
817
+			if (EE_System::instance()->detect_req_type() === EE_System::req_type_reactivation) {
818
+				$query_params['reactivation'] = true;
819
+			}
820
+			$url = add_query_arg($query_params, admin_url('admin.php'));
821
+			EEH_URL::safeRedirectAndExit($url);
822
+		}
823
+	}
824
+
825
+
826
+	/**
827
+	 * load_core_configuration
828
+	 * this is hooked into 'AHEE__EE_Bootstrap__load_core_configuration'
829
+	 * which runs during the WP 'plugins_loaded' action at priority 5
830
+	 *
831
+	 * @return void
832
+	 * @throws ReflectionException
833
+	 * @throws Exception
834
+	 */
835
+	public function load_core_configuration()
836
+	{
837
+		do_action('AHEE__EE_System__load_core_configuration__begin', $this);
838
+		$this->loader->getShared('EE_Load_Textdomain');
839
+		// load textdomain
840
+		EE_Load_Textdomain::load_textdomain();
841
+		// load and setup EE_Config and EE_Network_Config
842
+		$config = $this->loader->getShared('EE_Config');
843
+		$this->loader->getShared('EE_Network_Config');
844
+		// setup autoloaders
845
+		// enable logging?
846
+		$this->loader->getShared('EventEspresso\core\services\orm\TrashLogger');
847
+		if ($config->admin->use_remote_logging) {
848
+			$this->loader->getShared('EE_Log');
849
+		}
850
+		// check for activation errors
851
+		$activation_errors = get_option('ee_plugin_activation_errors', false);
852
+		if ($activation_errors) {
853
+			EE_Error::add_error($activation_errors, __FILE__, __FUNCTION__, __LINE__);
854
+			update_option('ee_plugin_activation_errors', false);
855
+		}
856
+		// get model names
857
+		$this->_parse_model_names();
858
+		// configure custom post type definitions
859
+		$this->loader->getShared('EventEspresso\core\domain\entities\custom_post_types\CustomTaxonomyDefinitions');
860
+		$this->loader->getShared('EventEspresso\core\domain\entities\custom_post_types\CustomPostTypeDefinitions');
861
+		do_action('AHEE__EE_System__load_core_configuration__complete', $this);
862
+	}
863
+
864
+
865
+	/**
866
+	 * cycles through all of the models/*.model.php files, and assembles an array of model names
867
+	 *
868
+	 * @return void
869
+	 * @throws ReflectionException
870
+	 */
871
+	private function _parse_model_names()
872
+	{
873
+		// get all the files in the EE_MODELS folder that end in .model.php
874
+		$models                 = glob(EE_MODELS . '*.model.php');
875
+		$model_names            = [];
876
+		$non_abstract_db_models = [];
877
+		foreach ($models as $model) {
878
+			// get model classname
879
+			$classname       = EEH_File::get_classname_from_filepath_with_standard_filename($model);
880
+			$short_name      = str_replace('EEM_', '', $classname);
881
+			$reflectionClass = new ReflectionClass($classname);
882
+			if ($reflectionClass->isSubclassOf('EEM_Base') && ! $reflectionClass->isAbstract()) {
883
+				$non_abstract_db_models[ $short_name ] = $classname;
884
+			}
885
+			$model_names[ $short_name ] = $classname;
886
+		}
887
+		$this->registry->models                 = apply_filters('FHEE__EE_System__parse_model_names', $model_names);
888
+		$this->registry->non_abstract_db_models = apply_filters(
889
+			'FHEE__EE_System__parse_implemented_model_names',
890
+			$non_abstract_db_models
891
+		);
892
+	}
893
+
894
+
895
+	/**
896
+	 * @throws Exception
897
+	 * @since 4.9.71.p
898
+	 */
899
+	public function loadRouteMatchSpecifications()
900
+	{
901
+		try {
902
+			$this->loader->getShared('EventEspresso\core\services\routing\RouteMatchSpecificationManager');
903
+			$this->loader->getShared('EventEspresso\core\services\routing\RouteCollection');
904
+			$this->router->loadPrimaryRoutes();
905
+		} catch (Exception $exception) {
906
+			new ExceptionStackTraceDisplay($exception);
907
+		}
908
+		do_action('AHEE__EE_System__loadRouteMatchSpecifications');
909
+	}
910
+
911
+
912
+	/**
913
+	 * loading CPT related classes earlier so that their definitions are available
914
+	 * but not performing any actual registration with WP core until load_CPTs_and_session() is called
915
+	 *
916
+	 * @since   4.10.21.p
917
+	 */
918
+	public function loadCustomPostTypes()
919
+	{
920
+		$this->register_custom_taxonomies = $this->loader->getShared(
921
+			'EventEspresso\core\domain\services\custom_post_types\RegisterCustomTaxonomies'
922
+		);
923
+		$this->register_custom_post_types = $this->loader->getShared(
924
+			'EventEspresso\core\domain\services\custom_post_types\RegisterCustomPostTypes'
925
+		);
926
+		$this->register_custom_taxonomy_terms = $this->loader->getShared(
927
+			'EventEspresso\core\domain\services\custom_post_types\RegisterCustomTaxonomyTerms'
928
+		);
929
+		// integrate WP_Query with the EE models
930
+		$this->loader->getShared('EE_CPT_Strategy');
931
+		// load legacy EE_Request_Handler in case add-ons still need it
932
+		$this->loader->getShared('EE_Request_Handler');
933
+	}
934
+
935
+
936
+	/**
937
+	 * register_shortcodes_modules_and_widgets
938
+	 * generate lists of shortcodes and modules, then verify paths and classes
939
+	 * This is hooked into 'AHEE__EE_Bootstrap__register_shortcodes_modules_and_widgets'
940
+	 * which runs during the WP 'plugins_loaded' action at priority 7
941
+	 *
942
+	 * @access public
943
+	 * @return void
944
+	 * @throws Exception
945
+	 */
946
+	public function register_shortcodes_modules_and_widgets()
947
+	{
948
+		$this->router->registerShortcodesModulesAndWidgets();
949
+		do_action('AHEE__EE_System__register_shortcodes_modules_and_widgets');
950
+		// check for addons using old hook point
951
+		if (has_action('AHEE__EE_System__register_shortcodes_modules_and_addons')) {
952
+			$this->_incompatible_addon_error();
953
+		}
954
+	}
955
+
956
+
957
+	/**
958
+	 * _incompatible_addon_error
959
+	 *
960
+	 * @access public
961
+	 * @return void
962
+	 */
963
+	private function _incompatible_addon_error()
964
+	{
965
+		// get array of classes hooking into here
966
+		$class_names = EEH_Class_Tools::get_class_names_for_all_callbacks_on_hook(
967
+			'AHEE__EE_System__register_shortcodes_modules_and_addons'
968
+		);
969
+		if (! empty($class_names)) {
970
+			$msg = esc_html__(
971
+				'The following plugins, addons, or modules appear to be incompatible with this version of Event Espresso and were automatically deactivated to avoid fatal errors:',
972
+				'event_espresso'
973
+			);
974
+			$msg .= '<ul>';
975
+			foreach ($class_names as $class_name) {
976
+				$msg .= '<li><b>Event Espresso - '
977
+						. str_replace(
978
+							['EE_', 'EEM_', 'EED_', 'EES_', 'EEW_'],
979
+							'',
980
+							$class_name
981
+						) . '</b></li>';
982
+			}
983
+			$msg .= '</ul>';
984
+			$msg .= esc_html__(
985
+				'Compatibility issues can be avoided and/or resolved by keeping addons and plugins updated to the latest version.',
986
+				'event_espresso'
987
+			);
988
+			// save list of incompatible addons to wp-options for later use
989
+			add_option('ee_incompatible_addons', $class_names, '', 'no');
990
+			if (is_admin()) {
991
+				EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
992
+			}
993
+		}
994
+	}
995
+
996
+
997
+	/**
998
+	 * brew_espresso
999
+	 * begins the process of setting hooks for initializing EE in the correct order
1000
+	 * This is happening on the 'AHEE__EE_Bootstrap__brew_espresso' hook point
1001
+	 * which runs during the WP 'plugins_loaded' action at priority 9
1002
+	 *
1003
+	 * @return void
1004
+	 * @throws Exception
1005
+	 */
1006
+	public function brew_espresso()
1007
+	{
1008
+		do_action('AHEE__EE_System__brew_espresso__begin', $this);
1009
+		// load some final core systems
1010
+		add_action('init', [$this, 'set_hooks_for_core'], 1);
1011
+		add_action('init', [$this, 'perform_activations_upgrades_and_migrations'], 3);
1012
+		add_action('init', [$this, 'load_CPTs_and_session'], 5);
1013
+		add_action('init', [$this, 'load_controllers'], 7);
1014
+		add_action('init', [$this, 'core_loaded_and_ready'], 9);
1015
+		add_action('init', [$this, 'initialize'], 10);
1016
+		add_action('init', [$this, 'initialize_last'], 100);
1017
+		$this->router->brewEspresso();
1018
+		do_action('AHEE__EE_System__brew_espresso__complete', $this);
1019
+	}
1020
+
1021
+
1022
+	/**
1023
+	 *    set_hooks_for_core
1024
+	 *
1025
+	 * @access public
1026
+	 * @return    void
1027
+	 * @throws EE_Error
1028
+	 */
1029
+	public function set_hooks_for_core()
1030
+	{
1031
+		$this->_deactivate_incompatible_addons();
1032
+		do_action('AHEE__EE_System__set_hooks_for_core');
1033
+		$this->loader->getShared('EventEspresso\core\domain\values\session\SessionLifespan');
1034
+		// caps need to be initialized on every request so that capability maps are set.
1035
+		// @see https://events.codebasehq.com/projects/event-espresso/tickets/8674
1036
+		$this->registry->CAP->init_caps();
1037
+	}
1038
+
1039
+
1040
+	/**
1041
+	 * Using the information gathered in EE_System::_incompatible_addon_error,
1042
+	 * deactivates any addons considered incompatible with the current version of EE
1043
+	 */
1044
+	private function _deactivate_incompatible_addons()
1045
+	{
1046
+		$incompatible_addons = get_option('ee_incompatible_addons', []);
1047
+		if (! empty($incompatible_addons)) {
1048
+			$active_plugins = get_option('active_plugins', []);
1049
+			foreach ($active_plugins as $active_plugin) {
1050
+				foreach ($incompatible_addons as $incompatible_addon) {
1051
+					if (strpos($active_plugin, $incompatible_addon) !== false) {
1052
+						$this->request->unSetRequestParams(['activate'], true);
1053
+						espresso_deactivate_plugin($active_plugin);
1054
+					}
1055
+				}
1056
+			}
1057
+		}
1058
+	}
1059
+
1060
+
1061
+	/**
1062
+	 *    perform_activations_upgrades_and_migrations
1063
+	 *
1064
+	 * @access public
1065
+	 * @return    void
1066
+	 */
1067
+	public function perform_activations_upgrades_and_migrations()
1068
+	{
1069
+		do_action('AHEE__EE_System__perform_activations_upgrades_and_migrations');
1070
+	}
1071
+
1072
+
1073
+	/**
1074
+	 * @return void
1075
+	 * @throws DomainException
1076
+	 */
1077
+	public function load_CPTs_and_session()
1078
+	{
1079
+		do_action('AHEE__EE_System__load_CPTs_and_session__start');
1080
+		$this->register_custom_taxonomies->registerCustomTaxonomies();
1081
+		$this->register_custom_post_types->registerCustomPostTypes();
1082
+		$this->register_custom_taxonomy_terms->registerCustomTaxonomyTerms();
1083
+		// load legacy Custom Post Types and Taxonomies
1084
+		$this->loader->getShared('EE_Register_CPTs');
1085
+		do_action('AHEE__EE_System__load_CPTs_and_session__complete');
1086
+	}
1087
+
1088
+
1089
+	/**
1090
+	 * load_controllers
1091
+	 * this is the best place to load any additional controllers that needs access to EE core.
1092
+	 * it is expected that all basic core EE systems, that are not dependant on the current request are loaded at this
1093
+	 * time
1094
+	 *
1095
+	 * @access public
1096
+	 * @return void
1097
+	 * @throws Exception
1098
+	 */
1099
+	public function load_controllers()
1100
+	{
1101
+		do_action('AHEE__EE_System__load_controllers__start');
1102
+		$this->router->loadControllers();
1103
+		do_action('AHEE__EE_System__load_controllers__complete');
1104
+	}
1105
+
1106
+
1107
+	/**
1108
+	 * core_loaded_and_ready
1109
+	 * all of the basic EE core should be loaded at this point and available regardless of M-Mode
1110
+	 *
1111
+	 * @access public
1112
+	 * @return void
1113
+	 * @throws Exception
1114
+	 */
1115
+	public function core_loaded_and_ready()
1116
+	{
1117
+		$this->router->coreLoadedAndReady();
1118
+		do_action('AHEE__EE_System__core_loaded_and_ready');
1119
+		// always load template tags, because it's faster than checking if it's a front-end request, and many page
1120
+		// builders require these even on the front-end
1121
+		require_once EE_PUBLIC . 'template_tags.php';
1122
+		do_action('AHEE__EE_System__set_hooks_for_shortcodes_modules_and_addons');
1123
+	}
1124
+
1125
+
1126
+	/**
1127
+	 * initialize
1128
+	 * this is the best place to begin initializing client code
1129
+	 *
1130
+	 * @access public
1131
+	 * @return void
1132
+	 */
1133
+	public function initialize()
1134
+	{
1135
+		do_action('AHEE__EE_System__initialize');
1136
+		add_filter(
1137
+			'safe_style_css',
1138
+			function ($styles) {
1139
+				$styles[] = 'display';
1140
+				$styles[] = 'visibility';
1141
+				$styles[] = 'position';
1142
+				$styles[] = 'top';
1143
+				$styles[] = 'right';
1144
+				$styles[] = 'bottom';
1145
+				$styles[] = 'left';
1146
+				$styles[] = 'resize';
1147
+				$styles[] = 'max-width';
1148
+				$styles[] = 'max-height';
1149
+				return $styles;
1150
+			}
1151
+		);
1152
+	}
1153
+
1154
+
1155
+	/**
1156
+	 * initialize_last
1157
+	 * this is run really late during the WP init hook point, and ensures that mostly everything else that needs to
1158
+	 * initialize has done so
1159
+	 *
1160
+	 * @access public
1161
+	 * @return void
1162
+	 * @throws Exception
1163
+	 */
1164
+	public function initialize_last()
1165
+	{
1166
+		$this->router->initializeLast();
1167
+		do_action('AHEE__EE_System__initialize_last');
1168
+		/** @var EventEspresso\core\domain\services\custom_post_types\RewriteRules $rewrite_rules */
1169
+		$rewrite_rules = $this->loader->getShared(
1170
+			'EventEspresso\core\domain\services\custom_post_types\RewriteRules'
1171
+		);
1172
+		$rewrite_rules->flushRewriteRules();
1173
+		add_action('admin_bar_init', [$this, 'addEspressoToolbar']);
1174
+	}
1175
+
1176
+
1177
+	/**
1178
+	 * @return void
1179
+	 */
1180
+	public function addEspressoToolbar()
1181
+	{
1182
+		$this->loader->getShared(
1183
+			'EventEspresso\core\domain\services\admin\AdminToolBar',
1184
+			[$this->registry->CAP]
1185
+		);
1186
+	}
1187
+
1188
+
1189
+	/**
1190
+	 * do_not_cache
1191
+	 * sets no cache headers and defines no cache constants for WP plugins
1192
+	 *
1193
+	 * @access public
1194
+	 * @return void
1195
+	 */
1196
+	public static function do_not_cache()
1197
+	{
1198
+		// set no cache constants
1199
+		if (! defined('DONOTCACHEPAGE')) {
1200
+			define('DONOTCACHEPAGE', true);
1201
+		}
1202
+		if (! defined('DONOTCACHCEOBJECT')) {
1203
+			define('DONOTCACHCEOBJECT', true);
1204
+		}
1205
+		if (! defined('DONOTCACHEDB')) {
1206
+			define('DONOTCACHEDB', true);
1207
+		}
1208
+		// add no cache headers
1209
+		add_action('send_headers', ['EE_System', 'nocache_headers'], 10);
1210
+		// plus a little extra for nginx and Google Chrome
1211
+		add_filter('nocache_headers', ['EE_System', 'extra_nocache_headers'], 10, 1);
1212
+		// prevent browsers from prefetching of the rel='next' link, because it may contain content that interferes with the registration process
1213
+		remove_action('wp_head', 'adjacent_posts_rel_link_wp_head');
1214
+	}
1215
+
1216
+
1217
+	/**
1218
+	 *    extra_nocache_headers
1219
+	 *
1220
+	 * @access    public
1221
+	 * @param $headers
1222
+	 * @return    array
1223
+	 */
1224
+	public static function extra_nocache_headers($headers): array
1225
+	{
1226
+		// for NGINX
1227
+		$headers['X-Accel-Expires'] = 0;
1228
+		// plus extra for Google Chrome since it doesn't seem to respect "no-cache", but WILL respect "no-store"
1229
+		$headers['Cache-Control'] = 'no-store, no-cache, must-revalidate, max-age=0';
1230
+		return $headers;
1231
+	}
1232
+
1233
+
1234
+	/**
1235
+	 *    nocache_headers
1236
+	 *
1237
+	 * @access    public
1238
+	 * @return    void
1239
+	 */
1240
+	public static function nocache_headers()
1241
+	{
1242
+		nocache_headers();
1243
+	}
1244
+
1245
+
1246
+	/**
1247
+	 * simply hooks into "wp_list_pages_exclude" filter (for wp_list_pages method) and makes sure EE critical pages are
1248
+	 * never returned with the function.
1249
+	 *
1250
+	 * @param array $exclude_array any existing pages being excluded are in this array.
1251
+	 * @return array
1252
+	 */
1253
+	public function remove_pages_from_wp_list_pages(array $exclude_array): array
1254
+	{
1255
+		return array_merge($exclude_array, $this->registry->CFG->core->get_critical_pages_array());
1256
+	}
1257 1257
 }
Please login to merge, or discard this patch.
core/admin/EE_Admin_Page_CPT.core.php 1 patch
Indentation   +1421 added lines, -1421 removed lines patch added patch discarded remove patch
@@ -31,455 +31,455 @@  discard block
 block discarded – undo
31 31
  */
32 32
 abstract class EE_Admin_Page_CPT extends EE_Admin_Page
33 33
 {
34
-    /**
35
-     * This gets set in _setup_cpt
36
-     * It will contain the object for the custom post type.
37
-     *
38
-     * @var EE_CPT_Base
39
-     */
40
-    protected $_cpt_object;
41
-
42
-
43
-    /**
44
-     * a boolean flag to set whether the current route is a cpt route or not.
45
-     *
46
-     * @var bool
47
-     */
48
-    protected $_cpt_route = false;
49
-
50
-
51
-    /**
52
-     * This property allows cpt classes to define multiple routes as cpt routes.
53
-     * //in this array we define what the custom post type for this route is.
54
-     * array(
55
-     * 'route_name' => 'custom_post_type_slug'
56
-     * )
57
-     *
58
-     * @var array
59
-     */
60
-    protected $_cpt_routes = [];
61
-
62
-
63
-    /**
64
-     * This simply defines what the corresponding routes WP will be redirected to after completing a post save/update.
65
-     * in this format:
66
-     * array(
67
-     * 'post_type_slug' => 'edit_route'
68
-     * )
69
-     *
70
-     * @var array
71
-     */
72
-    protected $_cpt_edit_routes = [];
73
-
74
-
75
-    /**
76
-     * If child classes set the name of their main model via the $_cpt_obj_models property, EE_Admin_Page_CPT will
77
-     * attempt to retrieve the related object model for the edit pages and assign it to _cpt_page_object. the
78
-     * _cpt_model_names property should be in the following format: array(
79
-     * 'route_defined_by_action_param' => 'Model_Name')
80
-     *
81
-     * @var array $_cpt_model_names
82
-     */
83
-    protected $_cpt_model_names = [];
84
-
85
-
86
-    /**
87
-     * @var EE_CPT_Base
88
-     */
89
-    protected $_cpt_model_obj = false;
90
-
91
-
92
-    /**
93
-     * This will hold an array of autosave containers that will be used to obtain input values and hook into the WP
94
-     * autosave so we can save our inputs on the save_post hook!  Children classes should add to this array by using
95
-     * the _register_autosave_containers() method so that we don't override any other containers already registered.
96
-     * Registration of containers should be done before load_page_dependencies() is run.
97
-     *
98
-     * @var array()
99
-     */
100
-    protected $_autosave_containers = [];
101
-
102
-    protected $_autosave_fields     = [];
103
-
104
-    /**
105
-     * Array mapping from admin actions to their equivalent wp core pages for custom post types. So when a user visits
106
-     * a page for an action, it will appear as if they were visiting the wp core page for that custom post type
107
-     *
108
-     * @var array
109
-     */
110
-    protected $_pagenow_map;
111
-
112
-
113
-    /**
114
-     * This is hooked into the WordPress do_action('save_post') hook and runs after the custom post type has been
115
-     * saved.  Child classes are required to declare this method.  Typically you would use this to save any additional
116
-     * data. Keep in mind also that "save_post" runs on EVERY post update to the database. ALSO very important.  When a
117
-     * post transitions from scheduled to published, the save_post action is fired but you will NOT have any _POST data
118
-     * containing any extra info you may have from other meta saves.  So MAKE sure that you handle this accordingly.
119
-     *
120
-     * @abstract
121
-     * @param string  $post_id The ID of the cpt that was saved (so you can link relationally)
122
-     * @param WP_Post $post    The post object of the cpt that was saved.
123
-     * @return void
124
-     */
125
-    abstract protected function _insert_update_cpt_item($post_id, $post);
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
-     * @param string $post_id The ID of the cpt that was trashed
133
-     * @return void
134
-     */
135
-    abstract public function trash_cpt_item($post_id);
136
-
137
-
138
-    /**
139
-     * This is hooked into the WordPress do_action('untrashed_post') hook and runs after a cpt has been untrashed
140
-     *
141
-     * @param string $post_id theID of the cpt that was untrashed
142
-     * @return void
143
-     */
144
-    abstract public function restore_cpt_item($post_id);
145
-
146
-
147
-    /**
148
-     * This is hooked into the WordPress do_action('delete_cpt_item') hook and runs after a cpt has been fully deleted
149
-     * from the db
150
-     *
151
-     * @param string $post_id the ID of the cpt that was deleted
152
-     * @return void
153
-     */
154
-    abstract public function delete_cpt_item($post_id);
155
-
156
-
157
-    /**
158
-     * @return LoaderInterface
159
-     * @throws InvalidArgumentException
160
-     * @throws InvalidDataTypeException
161
-     * @throws InvalidInterfaceException
162
-     */
163
-    protected function getLoader(): LoaderInterface
164
-    {
165
-        if (! $this->loader instanceof LoaderInterface) {
166
-            $this->loader = LoaderFactory::getLoader();
167
-        }
168
-        return $this->loader;
169
-    }
170
-
171
-
172
-    /**
173
-     * Just utilizing the method EE_Admin exposes for doing things before page setup.
174
-     *
175
-     * @return void
176
-     */
177
-    protected function _before_page_setup()
178
-    {
179
-        $this->raw_req_action = $this->request->getRequestParam('action');
180
-        $this->raw_req_page   = $this->request->getRequestParam('page');
181
-        $this->_cpt_routes    = array_merge(
182
-            [
183
-                'create_new' => $this->page_slug,
184
-                'edit'       => $this->page_slug,
185
-                'trash'      => $this->page_slug,
186
-            ],
187
-            $this->_cpt_routes
188
-        );
189
-        $cpt_route_action     = $this->_cpt_routes[ $this->raw_req_action ] ?? null;
190
-        // let's see if the current route has a value for cpt_object_slug. if it does, we use that instead of the page
191
-        $page              = $this->raw_req_page ?: $this->page_slug;
192
-        $page              = $cpt_route_action ?: $page;
193
-        $this->_cpt_object = get_post_type_object($page);
194
-        // tweak pagenow for page loading.
195
-        if (! $this->_pagenow_map) {
196
-            $this->_pagenow_map = [
197
-                'create_new' => 'post-new.php',
198
-                'edit'       => 'post.php',
199
-                'trash'      => 'post.php',
200
-            ];
201
-        }
202
-        add_action('current_screen', [$this, 'modify_pagenow']);
203
-        // TODO the below will need to be reworked to account for the cpt routes that are NOT based off of page but action param.
204
-        // get current page from autosave
205
-        $current_page        = $this->request->getRequestParam('ee_autosave_data[ee-cpt-hidden-inputs][current_page]');
206
-        $this->_current_page = $this->request->getRequestParam('current_page', $current_page);
207
-    }
208
-
209
-
210
-    /**
211
-     * Simply ensure that we simulate the correct post route for cpt screens
212
-     *
213
-     * @param WP_Screen|null $current_screen
214
-     * @return void
215
-     */
216
-    public function modify_pagenow(?WP_Screen $current_screen)
217
-    {
218
-        // possibly reset pagenow.
219
-        if (
220
-            $this->page_slug === $this->raw_req_page
221
-            && isset($this->_pagenow_map[ $this->raw_req_action ])
222
-        ) {
223
-            global $pagenow, $hook_suffix;
224
-            $pagenow     = $this->_pagenow_map[ $this->raw_req_action ];
225
-            $hook_suffix = $pagenow;
226
-        }
227
-    }
228
-
229
-
230
-    /**
231
-     * This method is used to register additional autosave containers to the _autosave_containers property.
232
-     *
233
-     * @param array $ids  an array of ids for containers that hold form inputs we want autosave to pickup.  Typically
234
-     *                    you would send along the id of a metabox container.
235
-     * @return void
236
-     * @todo We should automate this at some point by creating a wrapper for add_post_metabox and in our wrapper we
237
-     *                    automatically register the id for the post metabox as a container.
238
-     */
239
-    protected function _register_autosave_containers($ids)
240
-    {
241
-        $this->_autosave_containers = array_merge($this->_autosave_fields, (array) $ids);
242
-    }
243
-
244
-
245
-    /**
246
-     * Something nifty.  We're going to loop through all the registered metaboxes and if the CALLBACK is an instance of
247
-     * EE_Admin_Page OR EE_Admin_Hooks, then we'll add the id to our _autosave_containers array.
248
-     */
249
-    protected function _set_autosave_containers()
250
-    {
251
-        global $wp_meta_boxes;
252
-        $containers = [];
253
-        if (empty($wp_meta_boxes)) {
254
-            return;
255
-        }
256
-        $current_metaboxes = $wp_meta_boxes[ $this->page_slug ] ?? [];
257
-        foreach ($current_metaboxes as $box_context) {
258
-            foreach ($box_context as $box_details) {
259
-                foreach ($box_details as $box) {
260
-                    if (
261
-                        is_array($box) && is_array($box['callback'])
262
-                        && (
263
-                            $box['callback'][0] instanceof EE_Admin_Page
264
-                            || $box['callback'][0] instanceof EE_Admin_Hooks
265
-                        )
266
-                    ) {
267
-                        $containers[] = $box['id'];
268
-                    }
269
-                }
270
-            }
271
-        }
272
-        $this->_autosave_containers = array_merge($this->_autosave_containers, $containers);
273
-        // add hidden inputs container
274
-        $this->_autosave_containers[] = 'ee-cpt-hidden-inputs';
275
-    }
276
-
277
-
278
-    protected function _load_autosave_scripts_styles()
279
-    {
280
-        /*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 );
34
+	/**
35
+	 * This gets set in _setup_cpt
36
+	 * It will contain the object for the custom post type.
37
+	 *
38
+	 * @var EE_CPT_Base
39
+	 */
40
+	protected $_cpt_object;
41
+
42
+
43
+	/**
44
+	 * a boolean flag to set whether the current route is a cpt route or not.
45
+	 *
46
+	 * @var bool
47
+	 */
48
+	protected $_cpt_route = false;
49
+
50
+
51
+	/**
52
+	 * This property allows cpt classes to define multiple routes as cpt routes.
53
+	 * //in this array we define what the custom post type for this route is.
54
+	 * array(
55
+	 * 'route_name' => 'custom_post_type_slug'
56
+	 * )
57
+	 *
58
+	 * @var array
59
+	 */
60
+	protected $_cpt_routes = [];
61
+
62
+
63
+	/**
64
+	 * This simply defines what the corresponding routes WP will be redirected to after completing a post save/update.
65
+	 * in this format:
66
+	 * array(
67
+	 * 'post_type_slug' => 'edit_route'
68
+	 * )
69
+	 *
70
+	 * @var array
71
+	 */
72
+	protected $_cpt_edit_routes = [];
73
+
74
+
75
+	/**
76
+	 * If child classes set the name of their main model via the $_cpt_obj_models property, EE_Admin_Page_CPT will
77
+	 * attempt to retrieve the related object model for the edit pages and assign it to _cpt_page_object. the
78
+	 * _cpt_model_names property should be in the following format: array(
79
+	 * 'route_defined_by_action_param' => 'Model_Name')
80
+	 *
81
+	 * @var array $_cpt_model_names
82
+	 */
83
+	protected $_cpt_model_names = [];
84
+
85
+
86
+	/**
87
+	 * @var EE_CPT_Base
88
+	 */
89
+	protected $_cpt_model_obj = false;
90
+
91
+
92
+	/**
93
+	 * This will hold an array of autosave containers that will be used to obtain input values and hook into the WP
94
+	 * autosave so we can save our inputs on the save_post hook!  Children classes should add to this array by using
95
+	 * the _register_autosave_containers() method so that we don't override any other containers already registered.
96
+	 * Registration of containers should be done before load_page_dependencies() is run.
97
+	 *
98
+	 * @var array()
99
+	 */
100
+	protected $_autosave_containers = [];
101
+
102
+	protected $_autosave_fields     = [];
103
+
104
+	/**
105
+	 * Array mapping from admin actions to their equivalent wp core pages for custom post types. So when a user visits
106
+	 * a page for an action, it will appear as if they were visiting the wp core page for that custom post type
107
+	 *
108
+	 * @var array
109
+	 */
110
+	protected $_pagenow_map;
111
+
112
+
113
+	/**
114
+	 * This is hooked into the WordPress do_action('save_post') hook and runs after the custom post type has been
115
+	 * saved.  Child classes are required to declare this method.  Typically you would use this to save any additional
116
+	 * data. Keep in mind also that "save_post" runs on EVERY post update to the database. ALSO very important.  When a
117
+	 * post transitions from scheduled to published, the save_post action is fired but you will NOT have any _POST data
118
+	 * containing any extra info you may have from other meta saves.  So MAKE sure that you handle this accordingly.
119
+	 *
120
+	 * @abstract
121
+	 * @param string  $post_id The ID of the cpt that was saved (so you can link relationally)
122
+	 * @param WP_Post $post    The post object of the cpt that was saved.
123
+	 * @return void
124
+	 */
125
+	abstract protected function _insert_update_cpt_item($post_id, $post);
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
+	 * @param string $post_id The ID of the cpt that was trashed
133
+	 * @return void
134
+	 */
135
+	abstract public function trash_cpt_item($post_id);
136
+
137
+
138
+	/**
139
+	 * This is hooked into the WordPress do_action('untrashed_post') hook and runs after a cpt has been untrashed
140
+	 *
141
+	 * @param string $post_id theID of the cpt that was untrashed
142
+	 * @return void
143
+	 */
144
+	abstract public function restore_cpt_item($post_id);
145
+
146
+
147
+	/**
148
+	 * This is hooked into the WordPress do_action('delete_cpt_item') hook and runs after a cpt has been fully deleted
149
+	 * from the db
150
+	 *
151
+	 * @param string $post_id the ID of the cpt that was deleted
152
+	 * @return void
153
+	 */
154
+	abstract public function delete_cpt_item($post_id);
155
+
156
+
157
+	/**
158
+	 * @return LoaderInterface
159
+	 * @throws InvalidArgumentException
160
+	 * @throws InvalidDataTypeException
161
+	 * @throws InvalidInterfaceException
162
+	 */
163
+	protected function getLoader(): LoaderInterface
164
+	{
165
+		if (! $this->loader instanceof LoaderInterface) {
166
+			$this->loader = LoaderFactory::getLoader();
167
+		}
168
+		return $this->loader;
169
+	}
170
+
171
+
172
+	/**
173
+	 * Just utilizing the method EE_Admin exposes for doing things before page setup.
174
+	 *
175
+	 * @return void
176
+	 */
177
+	protected function _before_page_setup()
178
+	{
179
+		$this->raw_req_action = $this->request->getRequestParam('action');
180
+		$this->raw_req_page   = $this->request->getRequestParam('page');
181
+		$this->_cpt_routes    = array_merge(
182
+			[
183
+				'create_new' => $this->page_slug,
184
+				'edit'       => $this->page_slug,
185
+				'trash'      => $this->page_slug,
186
+			],
187
+			$this->_cpt_routes
188
+		);
189
+		$cpt_route_action     = $this->_cpt_routes[ $this->raw_req_action ] ?? null;
190
+		// let's see if the current route has a value for cpt_object_slug. if it does, we use that instead of the page
191
+		$page              = $this->raw_req_page ?: $this->page_slug;
192
+		$page              = $cpt_route_action ?: $page;
193
+		$this->_cpt_object = get_post_type_object($page);
194
+		// tweak pagenow for page loading.
195
+		if (! $this->_pagenow_map) {
196
+			$this->_pagenow_map = [
197
+				'create_new' => 'post-new.php',
198
+				'edit'       => 'post.php',
199
+				'trash'      => 'post.php',
200
+			];
201
+		}
202
+		add_action('current_screen', [$this, 'modify_pagenow']);
203
+		// TODO the below will need to be reworked to account for the cpt routes that are NOT based off of page but action param.
204
+		// get current page from autosave
205
+		$current_page        = $this->request->getRequestParam('ee_autosave_data[ee-cpt-hidden-inputs][current_page]');
206
+		$this->_current_page = $this->request->getRequestParam('current_page', $current_page);
207
+	}
208
+
209
+
210
+	/**
211
+	 * Simply ensure that we simulate the correct post route for cpt screens
212
+	 *
213
+	 * @param WP_Screen|null $current_screen
214
+	 * @return void
215
+	 */
216
+	public function modify_pagenow(?WP_Screen $current_screen)
217
+	{
218
+		// possibly reset pagenow.
219
+		if (
220
+			$this->page_slug === $this->raw_req_page
221
+			&& isset($this->_pagenow_map[ $this->raw_req_action ])
222
+		) {
223
+			global $pagenow, $hook_suffix;
224
+			$pagenow     = $this->_pagenow_map[ $this->raw_req_action ];
225
+			$hook_suffix = $pagenow;
226
+		}
227
+	}
228
+
229
+
230
+	/**
231
+	 * This method is used to register additional autosave containers to the _autosave_containers property.
232
+	 *
233
+	 * @param array $ids  an array of ids for containers that hold form inputs we want autosave to pickup.  Typically
234
+	 *                    you would send along the id of a metabox container.
235
+	 * @return void
236
+	 * @todo We should automate this at some point by creating a wrapper for add_post_metabox and in our wrapper we
237
+	 *                    automatically register the id for the post metabox as a container.
238
+	 */
239
+	protected function _register_autosave_containers($ids)
240
+	{
241
+		$this->_autosave_containers = array_merge($this->_autosave_fields, (array) $ids);
242
+	}
243
+
244
+
245
+	/**
246
+	 * Something nifty.  We're going to loop through all the registered metaboxes and if the CALLBACK is an instance of
247
+	 * EE_Admin_Page OR EE_Admin_Hooks, then we'll add the id to our _autosave_containers array.
248
+	 */
249
+	protected function _set_autosave_containers()
250
+	{
251
+		global $wp_meta_boxes;
252
+		$containers = [];
253
+		if (empty($wp_meta_boxes)) {
254
+			return;
255
+		}
256
+		$current_metaboxes = $wp_meta_boxes[ $this->page_slug ] ?? [];
257
+		foreach ($current_metaboxes as $box_context) {
258
+			foreach ($box_context as $box_details) {
259
+				foreach ($box_details as $box) {
260
+					if (
261
+						is_array($box) && is_array($box['callback'])
262
+						&& (
263
+							$box['callback'][0] instanceof EE_Admin_Page
264
+							|| $box['callback'][0] instanceof EE_Admin_Hooks
265
+						)
266
+					) {
267
+						$containers[] = $box['id'];
268
+					}
269
+				}
270
+			}
271
+		}
272
+		$this->_autosave_containers = array_merge($this->_autosave_containers, $containers);
273
+		// add hidden inputs container
274
+		$this->_autosave_containers[] = 'ee-cpt-hidden-inputs';
275
+	}
276
+
277
+
278
+	protected function _load_autosave_scripts_styles()
279
+	{
280
+		/*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 );
281 281
         wp_enqueue_script('cpt-autosave');/**/ // todo re-enable when we start doing autosave again in 4.2
282 282
 
283
-        // filter _autosave_containers
284
-        $containers = apply_filters(
285
-            'FHEE__EE_Admin_Page_CPT___load_autosave_scripts_styles__containers',
286
-            $this->_autosave_containers,
287
-            $this
288
-        );
289
-        $containers = apply_filters(
290
-            'FHEE__EE_Admin_Page_CPT__' . get_class($this) . '___load_autosave_scripts_styles__containers',
291
-            $containers,
292
-            $this
293
-        );
294
-
295
-        wp_localize_script(
296
-            'event_editor_js',
297
-            'EE_AUTOSAVE_IDS',
298
-            $containers
299
-        ); // todo once we enable autosaves, this needs to be switched to localize with "cpt-autosave"
300
-
301
-        $unsaved_data_msg = [
302
-            'eventmsg'     => sprintf(
303
-                wp_strip_all_tags(
304
-                    __(
305
-                        "The changes you made to this %s will be lost if you navigate away from this page.",
306
-                        'event_espresso'
307
-                    )
308
-                ),
309
-                $this->_cpt_object->labels->singular_name
310
-            ),
311
-            'inputChanged' => 0,
312
-        ];
313
-        wp_localize_script('event_editor_js', 'UNSAVED_DATA_MSG', $unsaved_data_msg);
314
-    }
315
-
316
-
317
-    /**
318
-     * overloading the EE_Admin_Page parent load_page_dependencies so we can get the cpt stuff added in appropriately
319
-     *
320
-     * @return void
321
-     * @throws EE_Error
322
-     * @throws ReflectionException
323
-     */
324
-    protected function _load_page_dependencies()
325
-    {
326
-        // we only add stuff if this is a cpt_route!
327
-        if (! $this->_cpt_route) {
328
-            parent::_load_page_dependencies();
329
-            return;
330
-        }
331
-        // now let's do some automatic filters into the wp_system
332
-        // and we'll check to make sure the CHILD class
333
-        // automatically has the required methods in place.
334
-        // the following filters are for setting all the redirects
335
-        // on DEFAULT WP custom post type actions
336
-        // let's add a hidden input to the post-edit form
337
-        // so we know when we have to trigger our custom redirects!
338
-        // Otherwise the redirects will happen on ALL post saves which wouldn't be good of course!
339
-        add_action('edit_form_after_title', [$this, 'cpt_post_form_hidden_input']);
340
-        // inject our Admin page nav tabs...
341
-        // let's make sure the nav tabs are set if they aren't already
342
-        // if ( empty( $this->_nav_tabs ) ) $this->_set_nav_tabs();
343
-        add_action('edit_form_top', [$this, 'inject_nav_tabs']);
344
-        // modify the post_updated messages array
345
-        add_action('post_updated_messages', [$this, 'post_update_messages'], 10);
346
-        // This basically allows us to change the title of the "publish" metabox area
347
-        // on CPT pages by setting a 'publishbox' value in the $_labels property array in the child class.
348
-        $screen = $this->_cpt_routes[ $this->_req_action ];
349
-        if (! empty($this->_labels['publishbox'])) {
350
-            $this->addMetaBox(
351
-                'submitdiv',
352
-                $this->getPublishBoxTitle(),
353
-                'post_submit_meta_box',
354
-                $screen,
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
-            $this->addMetaBox(
362
-                'page_templates',
363
-                esc_html__('Page Template', 'event_espresso'),
364
-                [$this, 'page_template_meta_box'],
365
-                $screen,
366
-                'side'
367
-            );
368
-        }
369
-        // add preview button
370
-        add_filter('get_sample_permalink_html', [PreviewButton::class, 'addButton'], 5, 2);
371
-        // add shortlink button to cpt edit screens.
372
-        //  We can do this as a universal thing BECAUSE, cpts use the same format for shortlinks as posts!
373
-        add_filter('get_sample_permalink_html', [EventShortlinkButton::class, 'addButton'], 10, 2);
374
-        // this is a filter that allows the addition of extra html after the permalink field on the wp post edit-form
375
-        add_filter('get_sample_permalink_html', [TicketSelectorShortcodeButton::class, 'addButton'], 12, 4);
376
-        // insert our own post_stati dropdown
377
-        add_action('post_submitbox_misc_actions', [$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', [$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', [$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', [$this, 'switch_core_wp_urls_with_ours'], 10);
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
-        add_action('load-' . $pagenow, [$this, 'modify_current_screen'], 20);
398
-        do_action('load-' . $pagenow);
399
-        add_action('admin_enqueue_scripts', [$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
-     * Since we don't want users going to default core wp routes, this will check any wp urls run through the
411
-     * esc_url() method and if we see a url matching a pattern for our routes, we'll modify it to point to OUR
412
-     * route instead.
413
-     *
414
-     * @param string $good_protocol_url The escaped url.
415
-     * @return string possibly a new url for our route.
416
-     */
417
-    public function switch_core_wp_urls_with_ours(string $good_protocol_url): string
418
-    {
419
-        $routes_to_match = [
420
-            0 => [
421
-                'edit.php?post_type=espresso_attendees',
422
-                'admin.php?page=espresso_registrations&action=contact_list',
423
-            ],
424
-            1 => [
425
-                'edit.php?post_type=' . $this->_cpt_object->name,
426
-                'admin.php?page=' . $this->_cpt_object->name,
427
-            ],
428
-        ];
429
-        foreach ($routes_to_match as $route_matches) {
430
-            if (strpos($good_protocol_url, $route_matches[0]) !== false) {
431
-                return str_replace($route_matches[0], $route_matches[1], $good_protocol_url);
432
-            }
433
-        }
434
-        return $good_protocol_url;
435
-    }
436
-
437
-
438
-    /**
439
-     * Determine whether the current cpt supports page templates or not.
440
-     *
441
-     * @param string $cpt_name The cpt slug we're checking on.
442
-     * @return bool True supported, false not.
443
-     * @throws InvalidArgumentException
444
-     * @throws InvalidDataTypeException
445
-     * @throws InvalidInterfaceException
446
-     * @since %VER%
447
-     */
448
-    private function _supports_page_templates(string $cpt_name): bool
449
-    {
450
-        /** @var EventEspresso\core\domain\entities\custom_post_types\CustomPostTypeDefinitions $custom_post_types */
451
-        $custom_post_types = $this->loader->getShared(
452
-            'EventEspresso\core\domain\entities\custom_post_types\CustomPostTypeDefinitions'
453
-        );
454
-        $cpt_args          = $custom_post_types->getDefinitions();
455
-        $cpt_args          = isset($cpt_args[ $cpt_name ]) ? $cpt_args[ $cpt_name ]['args'] : [];
456
-        $cpt_has_support   = ! empty($cpt_args['page_templates']);
457
-
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
-        return ! isset($post_templates[ $cpt_name ]) ? $cpt_has_support : false;
463
-    }
464
-
465
-
466
-    /**
467
-     * Callback for the page_templates metabox selector.
468
-     *
469
-     * @return void
470
-     * @since %VER%
471
-     */
472
-    public function page_template_meta_box()
473
-    {
474
-        global $post;
475
-        $template = '';
476
-
477
-        $page_template_count = count(get_page_templates());
478
-        if ($page_template_count) {
479
-            $page_template = get_post_meta($post->ID, '_wp_page_template', true);
480
-            $template      = ! empty($page_template) ? $page_template : '';
481
-        }
482
-        ?>
283
+		// filter _autosave_containers
284
+		$containers = apply_filters(
285
+			'FHEE__EE_Admin_Page_CPT___load_autosave_scripts_styles__containers',
286
+			$this->_autosave_containers,
287
+			$this
288
+		);
289
+		$containers = apply_filters(
290
+			'FHEE__EE_Admin_Page_CPT__' . get_class($this) . '___load_autosave_scripts_styles__containers',
291
+			$containers,
292
+			$this
293
+		);
294
+
295
+		wp_localize_script(
296
+			'event_editor_js',
297
+			'EE_AUTOSAVE_IDS',
298
+			$containers
299
+		); // todo once we enable autosaves, this needs to be switched to localize with "cpt-autosave"
300
+
301
+		$unsaved_data_msg = [
302
+			'eventmsg'     => sprintf(
303
+				wp_strip_all_tags(
304
+					__(
305
+						"The changes you made to this %s will be lost if you navigate away from this page.",
306
+						'event_espresso'
307
+					)
308
+				),
309
+				$this->_cpt_object->labels->singular_name
310
+			),
311
+			'inputChanged' => 0,
312
+		];
313
+		wp_localize_script('event_editor_js', 'UNSAVED_DATA_MSG', $unsaved_data_msg);
314
+	}
315
+
316
+
317
+	/**
318
+	 * overloading the EE_Admin_Page parent load_page_dependencies so we can get the cpt stuff added in appropriately
319
+	 *
320
+	 * @return void
321
+	 * @throws EE_Error
322
+	 * @throws ReflectionException
323
+	 */
324
+	protected function _load_page_dependencies()
325
+	{
326
+		// we only add stuff if this is a cpt_route!
327
+		if (! $this->_cpt_route) {
328
+			parent::_load_page_dependencies();
329
+			return;
330
+		}
331
+		// now let's do some automatic filters into the wp_system
332
+		// and we'll check to make sure the CHILD class
333
+		// automatically has the required methods in place.
334
+		// the following filters are for setting all the redirects
335
+		// on DEFAULT WP custom post type actions
336
+		// let's add a hidden input to the post-edit form
337
+		// so we know when we have to trigger our custom redirects!
338
+		// Otherwise the redirects will happen on ALL post saves which wouldn't be good of course!
339
+		add_action('edit_form_after_title', [$this, 'cpt_post_form_hidden_input']);
340
+		// inject our Admin page nav tabs...
341
+		// let's make sure the nav tabs are set if they aren't already
342
+		// if ( empty( $this->_nav_tabs ) ) $this->_set_nav_tabs();
343
+		add_action('edit_form_top', [$this, 'inject_nav_tabs']);
344
+		// modify the post_updated messages array
345
+		add_action('post_updated_messages', [$this, 'post_update_messages'], 10);
346
+		// This basically allows us to change the title of the "publish" metabox area
347
+		// on CPT pages by setting a 'publishbox' value in the $_labels property array in the child class.
348
+		$screen = $this->_cpt_routes[ $this->_req_action ];
349
+		if (! empty($this->_labels['publishbox'])) {
350
+			$this->addMetaBox(
351
+				'submitdiv',
352
+				$this->getPublishBoxTitle(),
353
+				'post_submit_meta_box',
354
+				$screen,
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
+			$this->addMetaBox(
362
+				'page_templates',
363
+				esc_html__('Page Template', 'event_espresso'),
364
+				[$this, 'page_template_meta_box'],
365
+				$screen,
366
+				'side'
367
+			);
368
+		}
369
+		// add preview button
370
+		add_filter('get_sample_permalink_html', [PreviewButton::class, 'addButton'], 5, 2);
371
+		// add shortlink button to cpt edit screens.
372
+		//  We can do this as a universal thing BECAUSE, cpts use the same format for shortlinks as posts!
373
+		add_filter('get_sample_permalink_html', [EventShortlinkButton::class, 'addButton'], 10, 2);
374
+		// this is a filter that allows the addition of extra html after the permalink field on the wp post edit-form
375
+		add_filter('get_sample_permalink_html', [TicketSelectorShortcodeButton::class, 'addButton'], 12, 4);
376
+		// insert our own post_stati dropdown
377
+		add_action('post_submitbox_misc_actions', [$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', [$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', [$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', [$this, 'switch_core_wp_urls_with_ours'], 10);
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
+		add_action('load-' . $pagenow, [$this, 'modify_current_screen'], 20);
398
+		do_action('load-' . $pagenow);
399
+		add_action('admin_enqueue_scripts', [$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
+	 * Since we don't want users going to default core wp routes, this will check any wp urls run through the
411
+	 * esc_url() method and if we see a url matching a pattern for our routes, we'll modify it to point to OUR
412
+	 * route instead.
413
+	 *
414
+	 * @param string $good_protocol_url The escaped url.
415
+	 * @return string possibly a new url for our route.
416
+	 */
417
+	public function switch_core_wp_urls_with_ours(string $good_protocol_url): string
418
+	{
419
+		$routes_to_match = [
420
+			0 => [
421
+				'edit.php?post_type=espresso_attendees',
422
+				'admin.php?page=espresso_registrations&action=contact_list',
423
+			],
424
+			1 => [
425
+				'edit.php?post_type=' . $this->_cpt_object->name,
426
+				'admin.php?page=' . $this->_cpt_object->name,
427
+			],
428
+		];
429
+		foreach ($routes_to_match as $route_matches) {
430
+			if (strpos($good_protocol_url, $route_matches[0]) !== false) {
431
+				return str_replace($route_matches[0], $route_matches[1], $good_protocol_url);
432
+			}
433
+		}
434
+		return $good_protocol_url;
435
+	}
436
+
437
+
438
+	/**
439
+	 * Determine whether the current cpt supports page templates or not.
440
+	 *
441
+	 * @param string $cpt_name The cpt slug we're checking on.
442
+	 * @return bool True supported, false not.
443
+	 * @throws InvalidArgumentException
444
+	 * @throws InvalidDataTypeException
445
+	 * @throws InvalidInterfaceException
446
+	 * @since %VER%
447
+	 */
448
+	private function _supports_page_templates(string $cpt_name): bool
449
+	{
450
+		/** @var EventEspresso\core\domain\entities\custom_post_types\CustomPostTypeDefinitions $custom_post_types */
451
+		$custom_post_types = $this->loader->getShared(
452
+			'EventEspresso\core\domain\entities\custom_post_types\CustomPostTypeDefinitions'
453
+		);
454
+		$cpt_args          = $custom_post_types->getDefinitions();
455
+		$cpt_args          = isset($cpt_args[ $cpt_name ]) ? $cpt_args[ $cpt_name ]['args'] : [];
456
+		$cpt_has_support   = ! empty($cpt_args['page_templates']);
457
+
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
+		return ! isset($post_templates[ $cpt_name ]) ? $cpt_has_support : false;
463
+	}
464
+
465
+
466
+	/**
467
+	 * Callback for the page_templates metabox selector.
468
+	 *
469
+	 * @return void
470
+	 * @since %VER%
471
+	 */
472
+	public function page_template_meta_box()
473
+	{
474
+		global $post;
475
+		$template = '';
476
+
477
+		$page_template_count = count(get_page_templates());
478
+		if ($page_template_count) {
479
+			$page_template = get_post_meta($post->ID, '_wp_page_template', true);
480
+			$template      = ! empty($page_template) ? $page_template : '';
481
+		}
482
+		?>
483 483
         <p><strong><?php esc_html_e('Template', 'event_espresso') ?></strong></p>
484 484
         <label class="screen-reader-text" for="page_template">
485 485
             <?php esc_html_e('Page Template', 'event_espresso') ?>
@@ -489,457 +489,457 @@  discard block
 block discarded – undo
489 489
             <?php page_template_dropdown($template); ?>
490 490
         </select>
491 491
         <?php
492
-    }
493
-
494
-
495
-    /**
496
-     * if this post is a draft or scheduled post then we provide a preview button for user to click
497
-     * Method is called from parent and is hooked into the wp 'get_sample_permalink_html' filter.
498
-     *
499
-     * @param string $return    the current html
500
-     * @param int    $id        the post id for the page
501
-     * @return string            The new html string for the permalink area
502
-     * @deprecated $VID:$
503
-     * @see PreviewButton::addButton()
504
-     */
505
-    public function preview_button_html(string $return, int $id): string
506
-    {
507
-        return PreviewButton::addButton($return, $id);
508
-    }
509
-
510
-
511
-    /**
512
-     * add our custom post status dropdown on the wp post page for this cpt
513
-     *
514
-     * @return void
515
-     */
516
-    public function custom_post_stati_dropdown()
517
-    {
518
-        $statuses         = $this->_cpt_model_obj->get_custom_post_statuses();
519
-        $cur_status_label = array_key_exists($this->_cpt_model_obj->status(), $statuses)
520
-            ? $statuses[ $this->_cpt_model_obj->status() ]
521
-            : '';
522
-        $template_args    = [
523
-            'cur_status'            => $this->_cpt_model_obj->status(),
524
-            'statuses'              => $statuses,
525
-            'cur_status_label'      => $cur_status_label,
526
-            'localized_status_save' => sprintf(esc_html__('Save %s', 'event_espresso'), $cur_status_label),
527
-        ];
528
-        // we'll add a trash post status (WP doesn't add one for some reason)
529
-        if ($this->_cpt_model_obj->status() === 'trash') {
530
-            $template_args['cur_status_label'] = esc_html__('Trashed', 'event_espresso');
531
-            $statuses['trash']                 = esc_html__('Trashed', 'event_espresso');
532
-            $template_args['statuses']         = $statuses;
533
-        }
534
-
535
-        $template = EE_ADMIN_TEMPLATE . 'status_dropdown.template.php';
536
-        EEH_Template::display_template($template, $template_args);
537
-    }
538
-
539
-
540
-    public function setup_autosave_hooks()
541
-    {
542
-        $this->_set_autosave_containers();
543
-        $this->_load_autosave_scripts_styles();
544
-    }
545
-
546
-
547
-    /**
548
-     * This is run on all WordPress autosaves AFTER the autosave is complete and sends along a post object (available
549
-     * in request data) containing: post_ID of the saved post autosavenonce for the saved post We'll do the check
550
-     * for the nonce in here, but then this method looks for two things:
551
-     * 1. Execute a method (if exists) matching 'ee_autosave_' and appended with the given route. OR
552
-     * 2. do_actions() for global or class specific actions that have been registered (for plugins/addons not in an
553
-     * EE_Admin_Page class. PLEASE NOTE: Data will be returned using the _return_json() object and so the
554
-     * $_template_args property should be used to hold the $data array.  We're expecting the following things set in
555
-     * template args.
556
-     *    1. $template_args['error'] = IF there is an error you can add the message in here.
557
-     *    2. $template_args['data']['items'] = an array of items that are setup in key index pairs of 'where_values_go'
558
-     *    => 'values_to_add'.  In other words, for the datetime metabox we'll have something like
559
-     *    $this->_template_args['data']['items'] = array(
560
-     *        'event-datetime-ids' => '1,2,3';
561
-     *    );
562
-     *    Keep in mind the following things:
563
-     *    - "where" index is for the input with the id as that string.
564
-     *    - "what" index is what will be used for the value of that input.
565
-     *
566
-     * @return void
567
-     * @throws EE_Error
568
-     */
569
-    public function do_extra_autosave_stuff()
570
-    {
571
-        // next let's check for the autosave nonce (we'll use _verify_nonce )
572
-        $nonce = $this->request->getRequestParam('autosavenonce');
573
-        $this->_verify_nonce($nonce, 'autosave');
574
-        // make sure we define doing autosave (cause WP isn't triggering this we want to make sure we define it)
575
-        if (! defined('DOING_AUTOSAVE')) {
576
-            define('DOING_AUTOSAVE', true);
577
-        }
578
-        // if we made it here then the nonce checked out.  Let's run our methods and actions
579
-        $autosave = "_ee_autosave_$this->_current_view";
580
-        if (method_exists($this, $autosave)) {
581
-            $this->$autosave();
582
-        } else {
583
-            $this->_template_args['success'] = true;
584
-        }
585
-        do_action('AHEE__EE_Admin_Page_CPT__do_extra_autosave_stuff__global_after', $this);
586
-        do_action('AHEE__EE_Admin_Page_CPT__do_extra_autosave_stuff__after_' . get_class($this), $this);
587
-        // now let's return json
588
-        $this->_return_json();
589
-    }
590
-
591
-
592
-    /**
593
-     * This takes care of setting up default routes and pages that utilize the core WP admin pages.
594
-     * Child classes can override the defaults (in cases for adding metaboxes etc.)
595
-     * but take care that you include the defaults here otherwise your core WP admin pages for the cpt won't work!
596
-     *
597
-     * @return void
598
-     * @throws EE_Error
599
-     * @throws ReflectionException
600
-     */
601
-    protected function _extend_page_config_for_cpt()
602
-    {
603
-        // before doing anything we need to make sure this runs ONLY when the loaded page matches the set page_slug
604
-        if ($this->raw_req_page !== $this->page_slug) {
605
-            return;
606
-        }
607
-        // set page routes and page config but ONLY if we're not viewing a custom setup cpt route as defined in _cpt_routes
608
-        if (! empty($this->_cpt_object)) {
609
-            $this->_page_routes = array_merge(
610
-                [
611
-                    'create_new' => [$this, '_create_new_cpt_item'],
612
-                    'edit'       => [$this, '_edit_cpt_item'],
613
-                ],
614
-                $this->_page_routes
615
-            );
616
-            $this->_page_config = array_merge(
617
-                [
618
-                    'create_new' => [
619
-                        'nav'           => [
620
-                            'label' => $this->_cpt_object->labels->add_new_item,
621
-                            'order' => 5,
622
-                        ],
623
-                        'require_nonce' => false,
624
-                    ],
625
-                    'edit'       => [
626
-                        'nav'           => [
627
-                            'label'      => $this->_cpt_object->labels->edit_item,
628
-                            'order'      => 5,
629
-                            'persistent' => false,
630
-                            'url'        => '',
631
-                        ],
632
-                        'require_nonce' => false,
633
-                    ],
634
-                ],
635
-                $this->_page_config
636
-            );
637
-        }
638
-        // load the next section only if this is a matching cpt route as set in the cpt routes array.
639
-        if (! isset($this->_cpt_routes[ $this->_req_action ])) {
640
-            return;
641
-        }
642
-        $this->_cpt_route = true;
643
-        // $this->_cpt_route = isset($this->_cpt_routes[ $this->_req_action ]);
644
-        // add_action('FHEE__EE_Admin_Page___load_page_dependencies__after_load', array( $this, 'modify_current_screen') );
645
-        if (empty($this->_cpt_object)) {
646
-            $msg = sprintf(
647
-                esc_html__(
648
-                    '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).',
649
-                    'event_espresso'
650
-                ),
651
-                $this->page_slug,
652
-                $this->_req_action,
653
-                get_class($this)
654
-            );
655
-            throw new EE_Error($msg);
656
-        }
657
-        $this->_set_model_object($this->request->getRequestParam('post', 0, DataType::INT));
658
-    }
659
-
660
-
661
-    /**
662
-     * Sets the _cpt_model_object property using what has been set for the _cpt_model_name and a given id.
663
-     *
664
-     * @param int    $id       The id to retrieve the model object for. If empty we set a default object.
665
-     * @param bool   $ignore_route_check
666
-     * @param string $req_type whether the current route is for inserting, updating, or deleting the CPT
667
-     * @throws EE_Error
668
-     * @throws InvalidArgumentException
669
-     * @throws InvalidDataTypeException
670
-     * @throws InvalidInterfaceException
671
-     * @throws ReflectionException
672
-     */
673
-    protected function _set_model_object(int $id = 0, bool $ignore_route_check = false, string $req_type = '')
674
-    {
675
-        $model = null;
676
-        if (
677
-            empty($this->_cpt_model_names)
678
-            || (
679
-                ! $ignore_route_check
680
-                && ! isset($this->_cpt_routes[ $this->_req_action ])
681
-            )
682
-            || (
683
-                $this->_cpt_model_obj instanceof EE_CPT_Base
684
-                && $this->_cpt_model_obj->ID() === $id
685
-            )
686
-        ) {
687
-            // 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.
688
-            return;
689
-        }
690
-        // if ignore_route_check is true, then get the model name via CustomPostTypeDefinitions
691
-        if ($ignore_route_check) {
692
-            $post_type = get_post_type($id);
693
-            /** @var EventEspresso\core\domain\entities\custom_post_types\CustomPostTypeDefinitions $custom_post_types */
694
-            $custom_post_types = $this->loader->getShared(
695
-                'EventEspresso\core\domain\entities\custom_post_types\CustomPostTypeDefinitions'
696
-            );
697
-            $model_names       = $custom_post_types->getCustomPostTypeModelNames($post_type);
698
-            if (isset($model_names[ $post_type ])) {
699
-                $model = EE_Registry::instance()->load_model($model_names[ $post_type ]);
700
-            }
701
-        } else {
702
-            $model = EE_Registry::instance()->load_model($this->_cpt_model_names[ $this->_req_action ]);
703
-        }
704
-        if ($model instanceof EEM_Base) {
705
-            $this->_cpt_model_obj = ! empty($id) ? $model->get_one_by_ID($id) : $model->create_default_object();
706
-        }
707
-        do_action(
708
-            'AHEE__EE_Admin_Page_CPT__set_model_object__after_set_object',
709
-            $this->_cpt_model_obj,
710
-            $req_type
711
-        );
712
-    }
713
-
714
-
715
-    /**
716
-     * admin_init_global
717
-     * This runs all the code that we want executed within the WP admin_init hook.
718
-     * This method executes for ALL EE Admin pages.
719
-     *
720
-     * @return void
721
-     */
722
-    public function admin_init_global()
723
-    {
724
-        $post_ID = $this->request->getRequestParam('post', 0, DataType::INT);
725
-        // its possible this is a new save so let's catch that instead
726
-        $post_ID        = $this->request->getRequestParam('post_ID', $post_ID, DataType::INT);
727
-        $post           = get_post($post_ID);
728
-        $post_type      = $post instanceof WP_Post ? $post->post_type : false;
729
-        $current_route  = $this->request->getRequestParam('current_route', 'shouldneverwork');
730
-        $route_to_check = $post_type && isset($this->_cpt_routes[ $current_route ])
731
-            ? $this->_cpt_routes[ $current_route ]
732
-            : '';
733
-        add_filter('get_delete_post_link', [$this, 'modify_delete_post_link'], 10, 2);
734
-        add_filter('get_edit_post_link', [$this, 'modify_edit_post_link'], 10, 2);
735
-        if ($post_type === $route_to_check) {
736
-            add_filter('redirect_post_location', [$this, 'cpt_post_location_redirect'], 10, 2);
737
-        }
738
-        // now let's filter redirect if we're on a revision page and the revision is for an event CPT.
739
-        $revision = $this->request->getRequestParam('revision');
740
-        if (! empty($revision)) {
741
-            $action = $this->request->getRequestParam('action');
742
-            // doing a restore?
743
-            if (! empty($action) && $action === 'restore') {
744
-                // get post for revision
745
-                $rev_post   = get_post($revision);
746
-                $rev_parent = get_post($rev_post->post_parent);
747
-                // only do our redirect filter AND our restore revision action if the post_type for the parent is one of our cpts.
748
-                if ($rev_parent && $rev_parent->post_type === $this->page_slug) {
749
-                    add_filter('wp_redirect', [$this, 'revision_redirect'], 10);
750
-                    // restores of revisions
751
-                    add_action('wp_restore_post_revision', [$this, 'restore_revision'], 10, 2);
752
-                }
753
-            }
754
-        }
755
-        // 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!
756
-        if ($post_type && $post_type === $route_to_check) {
757
-            // $post_id, $post
758
-            add_action('save_post', [$this, 'insert_update'], 10, 3);
759
-            // $post_id
760
-            add_action('trashed_post', [$this, 'before_trash_cpt_item'], 10);
761
-            add_action('trashed_post', [$this, 'dont_permanently_delete_ee_cpts'], 10);
762
-            add_action('untrashed_post', [$this, 'before_restore_cpt_item'], 10);
763
-            add_action('after_delete_post', [$this, 'before_delete_cpt_item'], 10);
764
-        }
765
-    }
766
-
767
-
768
-    /**
769
-     * Callback for the WordPress trashed_post hook.
770
-     * Execute some basic checks before calling the trash_cpt_item declared in the child class.
771
-     *
772
-     * @param int $post_id
773
-     * @throws EE_Error
774
-     * @throws ReflectionException
775
-     */
776
-    public function before_trash_cpt_item(int $post_id)
777
-    {
778
-        $this->_set_model_object($post_id, true, 'trash');
779
-        // if our cpt object isn't existent then get out immediately.
780
-        if (! $this->_cpt_model_obj instanceof EE_CPT_Base || $this->_cpt_model_obj->ID() !== $post_id) {
781
-            return;
782
-        }
783
-        $this->trash_cpt_item($post_id);
784
-    }
785
-
786
-
787
-    /**
788
-     * Callback for the WordPress untrashed_post hook.
789
-     * Execute some basic checks before calling the restore_cpt_method in the child class.
790
-     *
791
-     * @param $post_id
792
-     * @throws EE_Error
793
-     * @throws ReflectionException
794
-     */
795
-    public function before_restore_cpt_item($post_id)
796
-    {
797
-        $this->_set_model_object($post_id, true, 'restore');
798
-        // if our cpt object isn't existent then get out immediately.
799
-        if (! $this->_cpt_model_obj instanceof EE_CPT_Base || $this->_cpt_model_obj->ID() !== $post_id) {
800
-            return;
801
-        }
802
-        $this->restore_cpt_item($post_id);
803
-    }
804
-
805
-
806
-    /**
807
-     * Callback for the WordPress after_delete_post hook.
808
-     * Execute some basic checks before calling the delete_cpt_item method in the child class.
809
-     *
810
-     * @param $post_id
811
-     * @throws EE_Error
812
-     * @throws ReflectionException
813
-     */
814
-    public function before_delete_cpt_item($post_id)
815
-    {
816
-        $this->_set_model_object($post_id, true, 'delete');
817
-        // if our cpt object isn't existent then get out immediately.
818
-        if (! $this->_cpt_model_obj instanceof EE_CPT_Base || $this->_cpt_model_obj->ID() !== $post_id) {
819
-            return;
820
-        }
821
-        $this->delete_cpt_item($post_id);
822
-    }
823
-
824
-
825
-    /**
826
-     * This simply verifies if the cpt_model_object is instantiated for the given page and throws an error message
827
-     * accordingly.
828
-     *
829
-     * @return void
830
-     * @throws EE_Error
831
-     * @throws ReflectionException
832
-     */
833
-    public function verify_cpt_object()
834
-    {
835
-        $label = ! empty($this->_cpt_object) ? $this->_cpt_object->labels->singular_name : $this->page_label;
836
-        // verify event object
837
-        if (! $this->_cpt_model_obj instanceof EE_CPT_Base) {
838
-            throw new EE_Error(
839
-                sprintf(
840
-                    esc_html__(
841
-                        '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',
842
-                        'event_espresso'
843
-                    ),
844
-                    $label
845
-                )
846
-            );
847
-        }
848
-        // if auto-draft then throw an error
849
-        if ($this->_cpt_model_obj->get('status') === 'auto-draft') {
850
-            EE_Error::overwrite_errors();
851
-            EE_Error::add_error(
852
-                sprintf(
853
-                    esc_html__(
854
-                        '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.',
855
-                        'event_espresso'
856
-                    ),
857
-                    $label
858
-                ),
859
-                __FILE__,
860
-                __FUNCTION__,
861
-                __LINE__
862
-            );
863
-        }
864
-    }
865
-
866
-
867
-    /**
868
-     * admin_footer_scripts_global
869
-     * Anything triggered by the 'admin_print_footer_scripts' WP hook should be put in here. This particular method
870
-     * will apply on ALL EE_Admin pages.
871
-     *
872
-     * @return void
873
-     */
874
-    public function admin_footer_scripts_global()
875
-    {
876
-        $this->_add_admin_page_ajax_loading_img();
877
-        $this->_add_admin_page_overlay();
878
-    }
879
-
880
-
881
-    /**
882
-     * add in any global scripts for cpt routes
883
-     *
884
-     * @return void
885
-     */
886
-    public function load_global_scripts_styles()
887
-    {
888
-        parent::load_global_scripts_styles();
889
-        if ($this->_cpt_model_obj instanceof EE_CPT_Base) {
890
-            // setup custom post status object for localize script but only if we've got a cpt object
891
-            $statuses = $this->_cpt_model_obj->get_custom_post_statuses();
892
-            if (! empty($statuses)) {
893
-                // get ALL statuses!
894
-                $statuses = $this->_cpt_model_obj->get_all_post_statuses();
895
-                // setup object
896
-                $ee_cpt_statuses = [];
897
-                foreach ($statuses as $status => $label) {
898
-                    $ee_cpt_statuses[ $status ] = [
899
-                        'label'      => $label,
900
-                        'save_label' => sprintf(
901
-                            wp_strip_all_tags(__('Save as %s', 'event_espresso')),
902
-                            $label
903
-                        ),
904
-                    ];
905
-                }
906
-                wp_localize_script('ee_admin_js', 'eeCPTstatuses', $ee_cpt_statuses);
907
-            }
908
-        }
909
-    }
910
-
911
-
912
-    /**
913
-     * This is a wrapper for the insert/update routes for cpt items so we can add things that are common to ALL
914
-     * insert/updates
915
-     *
916
-     * @param int     $post_id ID of post being updated
917
-     * @param WP_Post $post    Post object from WP
918
-     * @param bool    $update  Whether this is an update or a new save.
919
-     * @return void
920
-     * @throws EE_Error
921
-     * @throws ReflectionException
922
-     */
923
-    public function insert_update(int $post_id, WP_Post $post, bool $update)
924
-    {
925
-        // make sure that if this is a revision OR trash action that we don't do any updates!
926
-        $action = $this->request->getRequestParam('action');
927
-        if ($action === 'restore' || $action === 'trash') {
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 (
933
-            $update
934
-            && (
935
-                ! $this->_cpt_model_obj instanceof EE_CPT_Base
936
-                || $this->_cpt_model_obj->ID() !== $post_id
937
-            )
938
-        ) {
939
-            return;
940
-        }
941
-        // check for autosave and update our req_data property accordingly.
942
-        /*if ( defined('DOING_AUTOSAVE') && DOING_AUTOSAVE && isset( $this->_req_data['ee_autosave_data'] ) ) {
492
+	}
493
+
494
+
495
+	/**
496
+	 * if this post is a draft or scheduled post then we provide a preview button for user to click
497
+	 * Method is called from parent and is hooked into the wp 'get_sample_permalink_html' filter.
498
+	 *
499
+	 * @param string $return    the current html
500
+	 * @param int    $id        the post id for the page
501
+	 * @return string            The new html string for the permalink area
502
+	 * @deprecated $VID:$
503
+	 * @see PreviewButton::addButton()
504
+	 */
505
+	public function preview_button_html(string $return, int $id): string
506
+	{
507
+		return PreviewButton::addButton($return, $id);
508
+	}
509
+
510
+
511
+	/**
512
+	 * add our custom post status dropdown on the wp post page for this cpt
513
+	 *
514
+	 * @return void
515
+	 */
516
+	public function custom_post_stati_dropdown()
517
+	{
518
+		$statuses         = $this->_cpt_model_obj->get_custom_post_statuses();
519
+		$cur_status_label = array_key_exists($this->_cpt_model_obj->status(), $statuses)
520
+			? $statuses[ $this->_cpt_model_obj->status() ]
521
+			: '';
522
+		$template_args    = [
523
+			'cur_status'            => $this->_cpt_model_obj->status(),
524
+			'statuses'              => $statuses,
525
+			'cur_status_label'      => $cur_status_label,
526
+			'localized_status_save' => sprintf(esc_html__('Save %s', 'event_espresso'), $cur_status_label),
527
+		];
528
+		// we'll add a trash post status (WP doesn't add one for some reason)
529
+		if ($this->_cpt_model_obj->status() === 'trash') {
530
+			$template_args['cur_status_label'] = esc_html__('Trashed', 'event_espresso');
531
+			$statuses['trash']                 = esc_html__('Trashed', 'event_espresso');
532
+			$template_args['statuses']         = $statuses;
533
+		}
534
+
535
+		$template = EE_ADMIN_TEMPLATE . 'status_dropdown.template.php';
536
+		EEH_Template::display_template($template, $template_args);
537
+	}
538
+
539
+
540
+	public function setup_autosave_hooks()
541
+	{
542
+		$this->_set_autosave_containers();
543
+		$this->_load_autosave_scripts_styles();
544
+	}
545
+
546
+
547
+	/**
548
+	 * This is run on all WordPress autosaves AFTER the autosave is complete and sends along a post object (available
549
+	 * in request data) containing: post_ID of the saved post autosavenonce for the saved post We'll do the check
550
+	 * for the nonce in here, but then this method looks for two things:
551
+	 * 1. Execute a method (if exists) matching 'ee_autosave_' and appended with the given route. OR
552
+	 * 2. do_actions() for global or class specific actions that have been registered (for plugins/addons not in an
553
+	 * EE_Admin_Page class. PLEASE NOTE: Data will be returned using the _return_json() object and so the
554
+	 * $_template_args property should be used to hold the $data array.  We're expecting the following things set in
555
+	 * template args.
556
+	 *    1. $template_args['error'] = IF there is an error you can add the message in here.
557
+	 *    2. $template_args['data']['items'] = an array of items that are setup in key index pairs of 'where_values_go'
558
+	 *    => 'values_to_add'.  In other words, for the datetime metabox we'll have something like
559
+	 *    $this->_template_args['data']['items'] = array(
560
+	 *        'event-datetime-ids' => '1,2,3';
561
+	 *    );
562
+	 *    Keep in mind the following things:
563
+	 *    - "where" index is for the input with the id as that string.
564
+	 *    - "what" index is what will be used for the value of that input.
565
+	 *
566
+	 * @return void
567
+	 * @throws EE_Error
568
+	 */
569
+	public function do_extra_autosave_stuff()
570
+	{
571
+		// next let's check for the autosave nonce (we'll use _verify_nonce )
572
+		$nonce = $this->request->getRequestParam('autosavenonce');
573
+		$this->_verify_nonce($nonce, 'autosave');
574
+		// make sure we define doing autosave (cause WP isn't triggering this we want to make sure we define it)
575
+		if (! defined('DOING_AUTOSAVE')) {
576
+			define('DOING_AUTOSAVE', true);
577
+		}
578
+		// if we made it here then the nonce checked out.  Let's run our methods and actions
579
+		$autosave = "_ee_autosave_$this->_current_view";
580
+		if (method_exists($this, $autosave)) {
581
+			$this->$autosave();
582
+		} else {
583
+			$this->_template_args['success'] = true;
584
+		}
585
+		do_action('AHEE__EE_Admin_Page_CPT__do_extra_autosave_stuff__global_after', $this);
586
+		do_action('AHEE__EE_Admin_Page_CPT__do_extra_autosave_stuff__after_' . get_class($this), $this);
587
+		// now let's return json
588
+		$this->_return_json();
589
+	}
590
+
591
+
592
+	/**
593
+	 * This takes care of setting up default routes and pages that utilize the core WP admin pages.
594
+	 * Child classes can override the defaults (in cases for adding metaboxes etc.)
595
+	 * but take care that you include the defaults here otherwise your core WP admin pages for the cpt won't work!
596
+	 *
597
+	 * @return void
598
+	 * @throws EE_Error
599
+	 * @throws ReflectionException
600
+	 */
601
+	protected function _extend_page_config_for_cpt()
602
+	{
603
+		// before doing anything we need to make sure this runs ONLY when the loaded page matches the set page_slug
604
+		if ($this->raw_req_page !== $this->page_slug) {
605
+			return;
606
+		}
607
+		// set page routes and page config but ONLY if we're not viewing a custom setup cpt route as defined in _cpt_routes
608
+		if (! empty($this->_cpt_object)) {
609
+			$this->_page_routes = array_merge(
610
+				[
611
+					'create_new' => [$this, '_create_new_cpt_item'],
612
+					'edit'       => [$this, '_edit_cpt_item'],
613
+				],
614
+				$this->_page_routes
615
+			);
616
+			$this->_page_config = array_merge(
617
+				[
618
+					'create_new' => [
619
+						'nav'           => [
620
+							'label' => $this->_cpt_object->labels->add_new_item,
621
+							'order' => 5,
622
+						],
623
+						'require_nonce' => false,
624
+					],
625
+					'edit'       => [
626
+						'nav'           => [
627
+							'label'      => $this->_cpt_object->labels->edit_item,
628
+							'order'      => 5,
629
+							'persistent' => false,
630
+							'url'        => '',
631
+						],
632
+						'require_nonce' => false,
633
+					],
634
+				],
635
+				$this->_page_config
636
+			);
637
+		}
638
+		// load the next section only if this is a matching cpt route as set in the cpt routes array.
639
+		if (! isset($this->_cpt_routes[ $this->_req_action ])) {
640
+			return;
641
+		}
642
+		$this->_cpt_route = true;
643
+		// $this->_cpt_route = isset($this->_cpt_routes[ $this->_req_action ]);
644
+		// add_action('FHEE__EE_Admin_Page___load_page_dependencies__after_load', array( $this, 'modify_current_screen') );
645
+		if (empty($this->_cpt_object)) {
646
+			$msg = sprintf(
647
+				esc_html__(
648
+					'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).',
649
+					'event_espresso'
650
+				),
651
+				$this->page_slug,
652
+				$this->_req_action,
653
+				get_class($this)
654
+			);
655
+			throw new EE_Error($msg);
656
+		}
657
+		$this->_set_model_object($this->request->getRequestParam('post', 0, DataType::INT));
658
+	}
659
+
660
+
661
+	/**
662
+	 * Sets the _cpt_model_object property using what has been set for the _cpt_model_name and a given id.
663
+	 *
664
+	 * @param int    $id       The id to retrieve the model object for. If empty we set a default object.
665
+	 * @param bool   $ignore_route_check
666
+	 * @param string $req_type whether the current route is for inserting, updating, or deleting the CPT
667
+	 * @throws EE_Error
668
+	 * @throws InvalidArgumentException
669
+	 * @throws InvalidDataTypeException
670
+	 * @throws InvalidInterfaceException
671
+	 * @throws ReflectionException
672
+	 */
673
+	protected function _set_model_object(int $id = 0, bool $ignore_route_check = false, string $req_type = '')
674
+	{
675
+		$model = null;
676
+		if (
677
+			empty($this->_cpt_model_names)
678
+			|| (
679
+				! $ignore_route_check
680
+				&& ! isset($this->_cpt_routes[ $this->_req_action ])
681
+			)
682
+			|| (
683
+				$this->_cpt_model_obj instanceof EE_CPT_Base
684
+				&& $this->_cpt_model_obj->ID() === $id
685
+			)
686
+		) {
687
+			// 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.
688
+			return;
689
+		}
690
+		// if ignore_route_check is true, then get the model name via CustomPostTypeDefinitions
691
+		if ($ignore_route_check) {
692
+			$post_type = get_post_type($id);
693
+			/** @var EventEspresso\core\domain\entities\custom_post_types\CustomPostTypeDefinitions $custom_post_types */
694
+			$custom_post_types = $this->loader->getShared(
695
+				'EventEspresso\core\domain\entities\custom_post_types\CustomPostTypeDefinitions'
696
+			);
697
+			$model_names       = $custom_post_types->getCustomPostTypeModelNames($post_type);
698
+			if (isset($model_names[ $post_type ])) {
699
+				$model = EE_Registry::instance()->load_model($model_names[ $post_type ]);
700
+			}
701
+		} else {
702
+			$model = EE_Registry::instance()->load_model($this->_cpt_model_names[ $this->_req_action ]);
703
+		}
704
+		if ($model instanceof EEM_Base) {
705
+			$this->_cpt_model_obj = ! empty($id) ? $model->get_one_by_ID($id) : $model->create_default_object();
706
+		}
707
+		do_action(
708
+			'AHEE__EE_Admin_Page_CPT__set_model_object__after_set_object',
709
+			$this->_cpt_model_obj,
710
+			$req_type
711
+		);
712
+	}
713
+
714
+
715
+	/**
716
+	 * admin_init_global
717
+	 * This runs all the code that we want executed within the WP admin_init hook.
718
+	 * This method executes for ALL EE Admin pages.
719
+	 *
720
+	 * @return void
721
+	 */
722
+	public function admin_init_global()
723
+	{
724
+		$post_ID = $this->request->getRequestParam('post', 0, DataType::INT);
725
+		// its possible this is a new save so let's catch that instead
726
+		$post_ID        = $this->request->getRequestParam('post_ID', $post_ID, DataType::INT);
727
+		$post           = get_post($post_ID);
728
+		$post_type      = $post instanceof WP_Post ? $post->post_type : false;
729
+		$current_route  = $this->request->getRequestParam('current_route', 'shouldneverwork');
730
+		$route_to_check = $post_type && isset($this->_cpt_routes[ $current_route ])
731
+			? $this->_cpt_routes[ $current_route ]
732
+			: '';
733
+		add_filter('get_delete_post_link', [$this, 'modify_delete_post_link'], 10, 2);
734
+		add_filter('get_edit_post_link', [$this, 'modify_edit_post_link'], 10, 2);
735
+		if ($post_type === $route_to_check) {
736
+			add_filter('redirect_post_location', [$this, 'cpt_post_location_redirect'], 10, 2);
737
+		}
738
+		// now let's filter redirect if we're on a revision page and the revision is for an event CPT.
739
+		$revision = $this->request->getRequestParam('revision');
740
+		if (! empty($revision)) {
741
+			$action = $this->request->getRequestParam('action');
742
+			// doing a restore?
743
+			if (! empty($action) && $action === 'restore') {
744
+				// get post for revision
745
+				$rev_post   = get_post($revision);
746
+				$rev_parent = get_post($rev_post->post_parent);
747
+				// only do our redirect filter AND our restore revision action if the post_type for the parent is one of our cpts.
748
+				if ($rev_parent && $rev_parent->post_type === $this->page_slug) {
749
+					add_filter('wp_redirect', [$this, 'revision_redirect'], 10);
750
+					// restores of revisions
751
+					add_action('wp_restore_post_revision', [$this, 'restore_revision'], 10, 2);
752
+				}
753
+			}
754
+		}
755
+		// 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!
756
+		if ($post_type && $post_type === $route_to_check) {
757
+			// $post_id, $post
758
+			add_action('save_post', [$this, 'insert_update'], 10, 3);
759
+			// $post_id
760
+			add_action('trashed_post', [$this, 'before_trash_cpt_item'], 10);
761
+			add_action('trashed_post', [$this, 'dont_permanently_delete_ee_cpts'], 10);
762
+			add_action('untrashed_post', [$this, 'before_restore_cpt_item'], 10);
763
+			add_action('after_delete_post', [$this, 'before_delete_cpt_item'], 10);
764
+		}
765
+	}
766
+
767
+
768
+	/**
769
+	 * Callback for the WordPress trashed_post hook.
770
+	 * Execute some basic checks before calling the trash_cpt_item declared in the child class.
771
+	 *
772
+	 * @param int $post_id
773
+	 * @throws EE_Error
774
+	 * @throws ReflectionException
775
+	 */
776
+	public function before_trash_cpt_item(int $post_id)
777
+	{
778
+		$this->_set_model_object($post_id, true, 'trash');
779
+		// if our cpt object isn't existent then get out immediately.
780
+		if (! $this->_cpt_model_obj instanceof EE_CPT_Base || $this->_cpt_model_obj->ID() !== $post_id) {
781
+			return;
782
+		}
783
+		$this->trash_cpt_item($post_id);
784
+	}
785
+
786
+
787
+	/**
788
+	 * Callback for the WordPress untrashed_post hook.
789
+	 * Execute some basic checks before calling the restore_cpt_method in the child class.
790
+	 *
791
+	 * @param $post_id
792
+	 * @throws EE_Error
793
+	 * @throws ReflectionException
794
+	 */
795
+	public function before_restore_cpt_item($post_id)
796
+	{
797
+		$this->_set_model_object($post_id, true, 'restore');
798
+		// if our cpt object isn't existent then get out immediately.
799
+		if (! $this->_cpt_model_obj instanceof EE_CPT_Base || $this->_cpt_model_obj->ID() !== $post_id) {
800
+			return;
801
+		}
802
+		$this->restore_cpt_item($post_id);
803
+	}
804
+
805
+
806
+	/**
807
+	 * Callback for the WordPress after_delete_post hook.
808
+	 * Execute some basic checks before calling the delete_cpt_item method in the child class.
809
+	 *
810
+	 * @param $post_id
811
+	 * @throws EE_Error
812
+	 * @throws ReflectionException
813
+	 */
814
+	public function before_delete_cpt_item($post_id)
815
+	{
816
+		$this->_set_model_object($post_id, true, 'delete');
817
+		// if our cpt object isn't existent then get out immediately.
818
+		if (! $this->_cpt_model_obj instanceof EE_CPT_Base || $this->_cpt_model_obj->ID() !== $post_id) {
819
+			return;
820
+		}
821
+		$this->delete_cpt_item($post_id);
822
+	}
823
+
824
+
825
+	/**
826
+	 * This simply verifies if the cpt_model_object is instantiated for the given page and throws an error message
827
+	 * accordingly.
828
+	 *
829
+	 * @return void
830
+	 * @throws EE_Error
831
+	 * @throws ReflectionException
832
+	 */
833
+	public function verify_cpt_object()
834
+	{
835
+		$label = ! empty($this->_cpt_object) ? $this->_cpt_object->labels->singular_name : $this->page_label;
836
+		// verify event object
837
+		if (! $this->_cpt_model_obj instanceof EE_CPT_Base) {
838
+			throw new EE_Error(
839
+				sprintf(
840
+					esc_html__(
841
+						'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',
842
+						'event_espresso'
843
+					),
844
+					$label
845
+				)
846
+			);
847
+		}
848
+		// if auto-draft then throw an error
849
+		if ($this->_cpt_model_obj->get('status') === 'auto-draft') {
850
+			EE_Error::overwrite_errors();
851
+			EE_Error::add_error(
852
+				sprintf(
853
+					esc_html__(
854
+						'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.',
855
+						'event_espresso'
856
+					),
857
+					$label
858
+				),
859
+				__FILE__,
860
+				__FUNCTION__,
861
+				__LINE__
862
+			);
863
+		}
864
+	}
865
+
866
+
867
+	/**
868
+	 * admin_footer_scripts_global
869
+	 * Anything triggered by the 'admin_print_footer_scripts' WP hook should be put in here. This particular method
870
+	 * will apply on ALL EE_Admin pages.
871
+	 *
872
+	 * @return void
873
+	 */
874
+	public function admin_footer_scripts_global()
875
+	{
876
+		$this->_add_admin_page_ajax_loading_img();
877
+		$this->_add_admin_page_overlay();
878
+	}
879
+
880
+
881
+	/**
882
+	 * add in any global scripts for cpt routes
883
+	 *
884
+	 * @return void
885
+	 */
886
+	public function load_global_scripts_styles()
887
+	{
888
+		parent::load_global_scripts_styles();
889
+		if ($this->_cpt_model_obj instanceof EE_CPT_Base) {
890
+			// setup custom post status object for localize script but only if we've got a cpt object
891
+			$statuses = $this->_cpt_model_obj->get_custom_post_statuses();
892
+			if (! empty($statuses)) {
893
+				// get ALL statuses!
894
+				$statuses = $this->_cpt_model_obj->get_all_post_statuses();
895
+				// setup object
896
+				$ee_cpt_statuses = [];
897
+				foreach ($statuses as $status => $label) {
898
+					$ee_cpt_statuses[ $status ] = [
899
+						'label'      => $label,
900
+						'save_label' => sprintf(
901
+							wp_strip_all_tags(__('Save as %s', 'event_espresso')),
902
+							$label
903
+						),
904
+					];
905
+				}
906
+				wp_localize_script('ee_admin_js', 'eeCPTstatuses', $ee_cpt_statuses);
907
+			}
908
+		}
909
+	}
910
+
911
+
912
+	/**
913
+	 * This is a wrapper for the insert/update routes for cpt items so we can add things that are common to ALL
914
+	 * insert/updates
915
+	 *
916
+	 * @param int     $post_id ID of post being updated
917
+	 * @param WP_Post $post    Post object from WP
918
+	 * @param bool    $update  Whether this is an update or a new save.
919
+	 * @return void
920
+	 * @throws EE_Error
921
+	 * @throws ReflectionException
922
+	 */
923
+	public function insert_update(int $post_id, WP_Post $post, bool $update)
924
+	{
925
+		// make sure that if this is a revision OR trash action that we don't do any updates!
926
+		$action = $this->request->getRequestParam('action');
927
+		if ($action === 'restore' || $action === 'trash') {
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 (
933
+			$update
934
+			&& (
935
+				! $this->_cpt_model_obj instanceof EE_CPT_Base
936
+				|| $this->_cpt_model_obj->ID() !== $post_id
937
+			)
938
+		) {
939
+			return;
940
+		}
941
+		// check for autosave and update our req_data property accordingly.
942
+		/*if ( defined('DOING_AUTOSAVE') && DOING_AUTOSAVE && isset( $this->_req_data['ee_autosave_data'] ) ) {
943 943
             foreach( (array) $this->_req_data['ee_autosave_data'] as $id => $values ) {
944 944
 
945 945
                 foreach ( (array) $values as $key => $value ) {
@@ -949,540 +949,540 @@  discard block
 block discarded – undo
949 949
 
950 950
         }/**/ // TODO reactivate after autosave is implemented in 4.2
951 951
 
952
-        // take care of updating any selected page_template IF this cpt supports it.
953
-
954
-        $page_template = $this->request->getRequestParam('page_template');
955
-        if ($this->_supports_page_templates($post->post_type) && ! empty($page_template)) {
956
-            // wp version aware.
957
-            if (RecommendedVersions::compareWordPressVersion('4.7')) {
958
-                $page_templates = wp_get_theme()->get_page_templates();
959
-            } else {
960
-                $post->page_template = $page_template;
961
-                $page_templates      = wp_get_theme()->get_page_templates($post);
962
-            }
963
-            if ($page_template !== 'default' && ! isset($page_templates[ $page_template ])) {
964
-                EE_Error::add_error(
965
-                    esc_html__('Invalid Page Template.', 'event_espresso'),
966
-                    __FILE__,
967
-                    __FUNCTION__,
968
-                    __LINE__
969
-                );
970
-            } else {
971
-                update_post_meta($post_id, '_wp_page_template', $page_template);
972
-            }
973
-        }
974
-        if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
975
-            return;
976
-        } //TODO we'll remove this after reimplementing autosave in 4.2
977
-        $this->_insert_update_cpt_item($post_id, $post);
978
-    }
979
-
980
-
981
-    /**
982
-     * This hooks into the wp_trash_post() function and removes the `_wp_trash_meta_status` and `_wp_trash_meta_time`
983
-     * post meta IF the trashed post is one of our CPT's - note this method should only be called with our cpt routes
984
-     * so we don't have to check for our CPT.
985
-     *
986
-     * @param int $post_id ID of the post
987
-     * @return void
988
-     */
989
-    public function dont_permanently_delete_ee_cpts(int $post_id)
990
-    {
991
-        // only do this if we're actually processing one of our CPTs
992
-        // if our cpt object isn't existent then get out immediately.
993
-        if (! $this->_cpt_model_obj instanceof EE_CPT_Base) {
994
-            return;
995
-        }
996
-        delete_post_meta($post_id, '_wp_trash_meta_status');
997
-        delete_post_meta($post_id, '_wp_trash_meta_time');
998
-        // our cpts may have comments so let's take care of that too
999
-        delete_post_meta($post_id, '_wp_trash_meta_comments_status');
1000
-    }
1001
-
1002
-
1003
-    /**
1004
-     * This is a wrapper for the restore_cpt_revision route for cpt items so we can make sure that when a revision is
1005
-     * triggered that we restore related items.  In order to work cpt classes MUST have a restore_cpt_revision method
1006
-     * in them. We also have our OWN action in here so addons can hook into the restore process easily.
1007
-     *
1008
-     * @param int $post_id     ID of cpt item
1009
-     * @param int $revision_id ID of revision being restored
1010
-     * @return void
1011
-     */
1012
-    public function restore_revision(int $post_id, int $revision_id)
1013
-    {
1014
-        $this->_restore_cpt_item($post_id, $revision_id);
1015
-        // global action
1016
-        do_action('AHEE_EE_Admin_Page_CPT__restore_revision', $post_id, $revision_id);
1017
-        // class specific action so you can limit hooking into a specific page.
1018
-        do_action('AHEE_EE_Admin_Page_CPT_' . get_class($this) . '__restore_revision', $post_id, $revision_id);
1019
-    }
1020
-
1021
-
1022
-    /**
1023
-     * @param int $post_id     ID of cpt item
1024
-     * @param int $revision_id ID of revision for item
1025
-     * @return void
1026
-     * @see restore_revision() for details
1027
-     */
1028
-    abstract protected function _restore_cpt_item(int $post_id, int $revision_id);
1029
-
1030
-
1031
-    /**
1032
-     * Execution of this method is added to the end of the load_page_dependencies method in the parent
1033
-     * so that we can fix a bug where default core metaboxes were not being called in the sidebar.
1034
-     * To fix we have to reset the current_screen using the page_slug
1035
-     * (which is identical - or should be - to our registered_post_type id.)
1036
-     * Also, since the core WP file loads the admin_header.php for WP
1037
-     * (and there are a bunch of other things edit-form-advanced.php loads that need to happen really early)
1038
-     * we need to load it NOW, hence our _route_admin_request in here. (Otherwise screen options won't be set).
1039
-     *
1040
-     * @return void
1041
-     * @throws EE_Error
1042
-     * @throws ReflectionException
1043
-     */
1044
-    public function modify_current_screen()
1045
-    {
1046
-        // ONLY do this if the current page_route IS a cpt route
1047
-        if (! $this->_cpt_route) {
1048
-            return;
1049
-        }
1050
-        // routing things REALLY early b/c this is a cpt admin page
1051
-        set_current_screen($this->_cpt_routes[ $this->_req_action ]);
1052
-        $this->_current_screen       = get_current_screen();
1053
-        $this->_current_screen->base = 'event-espresso';
1054
-        $this->_add_help_tabs(); // we make sure we add any help tabs back in!
1055
-        /*try {
952
+		// take care of updating any selected page_template IF this cpt supports it.
953
+
954
+		$page_template = $this->request->getRequestParam('page_template');
955
+		if ($this->_supports_page_templates($post->post_type) && ! empty($page_template)) {
956
+			// wp version aware.
957
+			if (RecommendedVersions::compareWordPressVersion('4.7')) {
958
+				$page_templates = wp_get_theme()->get_page_templates();
959
+			} else {
960
+				$post->page_template = $page_template;
961
+				$page_templates      = wp_get_theme()->get_page_templates($post);
962
+			}
963
+			if ($page_template !== 'default' && ! isset($page_templates[ $page_template ])) {
964
+				EE_Error::add_error(
965
+					esc_html__('Invalid Page Template.', 'event_espresso'),
966
+					__FILE__,
967
+					__FUNCTION__,
968
+					__LINE__
969
+				);
970
+			} else {
971
+				update_post_meta($post_id, '_wp_page_template', $page_template);
972
+			}
973
+		}
974
+		if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
975
+			return;
976
+		} //TODO we'll remove this after reimplementing autosave in 4.2
977
+		$this->_insert_update_cpt_item($post_id, $post);
978
+	}
979
+
980
+
981
+	/**
982
+	 * This hooks into the wp_trash_post() function and removes the `_wp_trash_meta_status` and `_wp_trash_meta_time`
983
+	 * post meta IF the trashed post is one of our CPT's - note this method should only be called with our cpt routes
984
+	 * so we don't have to check for our CPT.
985
+	 *
986
+	 * @param int $post_id ID of the post
987
+	 * @return void
988
+	 */
989
+	public function dont_permanently_delete_ee_cpts(int $post_id)
990
+	{
991
+		// only do this if we're actually processing one of our CPTs
992
+		// if our cpt object isn't existent then get out immediately.
993
+		if (! $this->_cpt_model_obj instanceof EE_CPT_Base) {
994
+			return;
995
+		}
996
+		delete_post_meta($post_id, '_wp_trash_meta_status');
997
+		delete_post_meta($post_id, '_wp_trash_meta_time');
998
+		// our cpts may have comments so let's take care of that too
999
+		delete_post_meta($post_id, '_wp_trash_meta_comments_status');
1000
+	}
1001
+
1002
+
1003
+	/**
1004
+	 * This is a wrapper for the restore_cpt_revision route for cpt items so we can make sure that when a revision is
1005
+	 * triggered that we restore related items.  In order to work cpt classes MUST have a restore_cpt_revision method
1006
+	 * in them. We also have our OWN action in here so addons can hook into the restore process easily.
1007
+	 *
1008
+	 * @param int $post_id     ID of cpt item
1009
+	 * @param int $revision_id ID of revision being restored
1010
+	 * @return void
1011
+	 */
1012
+	public function restore_revision(int $post_id, int $revision_id)
1013
+	{
1014
+		$this->_restore_cpt_item($post_id, $revision_id);
1015
+		// global action
1016
+		do_action('AHEE_EE_Admin_Page_CPT__restore_revision', $post_id, $revision_id);
1017
+		// class specific action so you can limit hooking into a specific page.
1018
+		do_action('AHEE_EE_Admin_Page_CPT_' . get_class($this) . '__restore_revision', $post_id, $revision_id);
1019
+	}
1020
+
1021
+
1022
+	/**
1023
+	 * @param int $post_id     ID of cpt item
1024
+	 * @param int $revision_id ID of revision for item
1025
+	 * @return void
1026
+	 * @see restore_revision() for details
1027
+	 */
1028
+	abstract protected function _restore_cpt_item(int $post_id, int $revision_id);
1029
+
1030
+
1031
+	/**
1032
+	 * Execution of this method is added to the end of the load_page_dependencies method in the parent
1033
+	 * so that we can fix a bug where default core metaboxes were not being called in the sidebar.
1034
+	 * To fix we have to reset the current_screen using the page_slug
1035
+	 * (which is identical - or should be - to our registered_post_type id.)
1036
+	 * Also, since the core WP file loads the admin_header.php for WP
1037
+	 * (and there are a bunch of other things edit-form-advanced.php loads that need to happen really early)
1038
+	 * we need to load it NOW, hence our _route_admin_request in here. (Otherwise screen options won't be set).
1039
+	 *
1040
+	 * @return void
1041
+	 * @throws EE_Error
1042
+	 * @throws ReflectionException
1043
+	 */
1044
+	public function modify_current_screen()
1045
+	{
1046
+		// ONLY do this if the current page_route IS a cpt route
1047
+		if (! $this->_cpt_route) {
1048
+			return;
1049
+		}
1050
+		// routing things REALLY early b/c this is a cpt admin page
1051
+		set_current_screen($this->_cpt_routes[ $this->_req_action ]);
1052
+		$this->_current_screen       = get_current_screen();
1053
+		$this->_current_screen->base = 'event-espresso';
1054
+		$this->_add_help_tabs(); // we make sure we add any help tabs back in!
1055
+		/*try {
1056 1056
             $this->_route_admin_request();
1057 1057
         } catch ( EE_Error $e ) {
1058 1058
             $e->get_error();
1059 1059
         }/**/
1060
-    }
1061
-
1062
-
1063
-    /**
1064
-     * This allows child classes to modify the default editor title that appears when people add a new or edit an
1065
-     * existing CPT item.     * This uses the _labels property set by the child class via _define_page_props. Just make
1066
-     * sure you have a key in _labels property that equals 'editor_title' and the value can be whatever you want the
1067
-     * default to be.
1068
-     *
1069
-     * @param string $title The new title (or existing if there is no editor_title defined)
1070
-     * @return string
1071
-     */
1072
-    public function add_custom_editor_default_title(string $title): string
1073
-    {
1074
-        return $this->_labels['editor_title'][ $this->_cpt_routes[ $this->_req_action ] ] ?? $title;
1075
-    }
1076
-
1077
-
1078
-    /**
1079
-     * hooks into the wp_get_shortlink button and makes sure that the shortlink gets generated
1080
-     *
1081
-     * @param string $shortlink   The already generated shortlink
1082
-     * @param int    $id          Post ID for this item
1083
-     * @return string
1084
-     * @deprecated $VID:$
1085
-     * @see EventShortlinkButton::addButton()
1086
-     */
1087
-    public function add_shortlink_button_to_editor(string $shortlink, int $id): string
1088
-    {
1089
-        return EventShortlinkButton::addButton($shortlink, $id);
1090
-    }
1091
-
1092
-
1093
-    /**
1094
-     * overriding the parent route_admin_request method so we DON'T run the route twice on cpt core page loads (it's
1095
-     * already run in modify_current_screen())
1096
-     *
1097
-     * @return void
1098
-     * @throws EE_Error
1099
-     * @throws ReflectionException
1100
-     */
1101
-    public function route_admin_request()
1102
-    {
1103
-        if ($this->_cpt_route) {
1104
-            return;
1105
-        }
1106
-        try {
1107
-            $this->_route_admin_request();
1108
-        } catch (EE_Error $e) {
1109
-            $e->get_error();
1110
-        }
1111
-    }
1112
-
1113
-
1114
-    /**
1115
-     * Add a hidden form input to cpt core pages so that we know to do redirects to our routes on saves
1116
-     *
1117
-     * @return void
1118
-     */
1119
-    public function cpt_post_form_hidden_input()
1120
-    {
1121
-        // we're also going to add the route value and the current page so we can direct autosave parsing correctly
1122
-        echo '
1060
+	}
1061
+
1062
+
1063
+	/**
1064
+	 * This allows child classes to modify the default editor title that appears when people add a new or edit an
1065
+	 * existing CPT item.     * This uses the _labels property set by the child class via _define_page_props. Just make
1066
+	 * sure you have a key in _labels property that equals 'editor_title' and the value can be whatever you want the
1067
+	 * default to be.
1068
+	 *
1069
+	 * @param string $title The new title (or existing if there is no editor_title defined)
1070
+	 * @return string
1071
+	 */
1072
+	public function add_custom_editor_default_title(string $title): string
1073
+	{
1074
+		return $this->_labels['editor_title'][ $this->_cpt_routes[ $this->_req_action ] ] ?? $title;
1075
+	}
1076
+
1077
+
1078
+	/**
1079
+	 * hooks into the wp_get_shortlink button and makes sure that the shortlink gets generated
1080
+	 *
1081
+	 * @param string $shortlink   The already generated shortlink
1082
+	 * @param int    $id          Post ID for this item
1083
+	 * @return string
1084
+	 * @deprecated $VID:$
1085
+	 * @see EventShortlinkButton::addButton()
1086
+	 */
1087
+	public function add_shortlink_button_to_editor(string $shortlink, int $id): string
1088
+	{
1089
+		return EventShortlinkButton::addButton($shortlink, $id);
1090
+	}
1091
+
1092
+
1093
+	/**
1094
+	 * overriding the parent route_admin_request method so we DON'T run the route twice on cpt core page loads (it's
1095
+	 * already run in modify_current_screen())
1096
+	 *
1097
+	 * @return void
1098
+	 * @throws EE_Error
1099
+	 * @throws ReflectionException
1100
+	 */
1101
+	public function route_admin_request()
1102
+	{
1103
+		if ($this->_cpt_route) {
1104
+			return;
1105
+		}
1106
+		try {
1107
+			$this->_route_admin_request();
1108
+		} catch (EE_Error $e) {
1109
+			$e->get_error();
1110
+		}
1111
+	}
1112
+
1113
+
1114
+	/**
1115
+	 * Add a hidden form input to cpt core pages so that we know to do redirects to our routes on saves
1116
+	 *
1117
+	 * @return void
1118
+	 */
1119
+	public function cpt_post_form_hidden_input()
1120
+	{
1121
+		// we're also going to add the route value and the current page so we can direct autosave parsing correctly
1122
+		echo '
1123 1123
         <input type="hidden" name="ee_cpt_item_redirect_url" value="' . esc_url_raw($this->_admin_base_url) . '"/>
1124 1124
         <div id="ee-cpt-hidden-inputs">
1125 1125
             <input type="hidden" id="current_route" name="current_route" value="' . esc_attr($this->_current_view) . '"/>
1126 1126
             <input type="hidden" id="current_page" name="current_page" value="' . esc_attr($this->page_slug) . '"/>
1127 1127
         </div>';
1128
-    }
1129
-
1130
-
1131
-    /**
1132
-     * This allows us to redirect the location of revision restores when they happen so it goes to our CPT routes.
1133
-     *
1134
-     * @param string $location Original location url
1135
-     * @return string           new (or original) url to redirect to.
1136
-     * @throws EE_Error
1137
-     */
1138
-    public function revision_redirect(string $location): string
1139
-    {
1140
-        // get revision
1141
-        $revision = $this->request->getRequestParam('revision');
1142
-        // can't do anything without revision so let's get out if not present
1143
-        if (empty($revision)) {
1144
-            return $location;
1145
-        }
1146
-        // get rev_post_data
1147
-        $rev        = get_post($revision);
1148
-        $admin_url  = $this->_admin_base_url;
1149
-        $query_args = [
1150
-            'action'   => 'edit',
1151
-            'post'     => $rev->post_parent,
1152
-            'revision' => $revision,
1153
-            'message'  => 5,
1154
-        ];
1155
-        $this->_process_notices($query_args, true);
1156
-        return EE_Admin_Page_CPT::add_query_args_and_nonce($query_args, $admin_url);
1157
-    }
1158
-
1159
-
1160
-    /**
1161
-     * Modify the edit post link generated by wp core function so that EE CPTs get setup differently.
1162
-     *
1163
-     * @param string $link    the original generated link
1164
-     * @param int    $id      post id
1165
-     * @return string          the link
1166
-     */
1167
-    public function modify_edit_post_link(string $link, int $id): string
1168
-    {
1169
-        $post = get_post($id);
1170
-        $action = $this->request->getRequestParam('action');
1171
-        if (
1172
-            empty($action)
1173
-            || ! isset($this->_cpt_routes[ $action ])
1174
-            || $post->post_type !== $this->_cpt_routes[ $action ]
1175
-        ) {
1176
-            return $link;
1177
-        }
1178
-        $query_args = [
1179
-            'action' => $this->_cpt_edit_routes[ $post->post_type ] ?? 'edit',
1180
-            'post'   => $id,
1181
-        ];
1182
-        return EE_Admin_Page_CPT::add_query_args_and_nonce($query_args, $this->_admin_base_url);
1183
-    }
1184
-
1185
-
1186
-    /**
1187
-     * Modify the trash link on our cpt edit pages so it has the required query var for triggering redirect properly on
1188
-     * our routes.
1189
-     *
1190
-     * @param string $delete_link  original delete link
1191
-     * @param int    $post_id      id of cpt object
1192
-     * @return string new delete link
1193
-     * @throws EE_Error
1194
-     * @throws ReflectionException
1195
-     */
1196
-    public function modify_delete_post_link(string $delete_link, int $post_id): string
1197
-    {
1198
-        $post = get_post($post_id);
1199
-        $action = $this->request->getRequestParam('action');
1200
-        if (
1201
-            ! $post instanceof WP_Post
1202
-            || empty($action)
1203
-            || ! isset($this->_cpt_routes[ $action ])
1204
-            || $post->post_type !== $this->_cpt_routes[ $action ]
1205
-        ) {
1206
-            return $delete_link;
1207
-        }
1208
-        $this->_set_model_object($post->ID, true);
1209
-
1210
-        // returns something like `trash_event` or `trash_attendee` or `trash_venue`
1211
-        $action = 'trash_' . str_replace('ee_', '', strtolower(get_class($this->_cpt_model_obj)));
1212
-
1213
-        return EE_Admin_Page::add_query_args_and_nonce(
1214
-            [
1215
-                'page'   => $this->request->getRequestParam('page'),
1216
-                'action' => $action,
1217
-                $this->_cpt_model_obj->get_model()->get_primary_key_field()->get_name() => $post->ID,
1218
-            ],
1219
-            admin_url()
1220
-        );
1221
-    }
1222
-
1223
-
1224
-    /**
1225
-     * This is the callback for the 'redirect_post_location' filter in wp-admin/post.php
1226
-     * so that we can hijack the default redirect locations for wp custom post types
1227
-     * that WE'RE using and send back to OUR routes.  This should only be hooked in on the right route.
1228
-     *
1229
-     * @param string $location This is the incoming currently set redirect location
1230
-     * @param string $post_id  This is the 'ID' value of the wp_posts table
1231
-     * @return string           the new location to redirect to
1232
-     * @throws EE_Error
1233
-     */
1234
-    public function cpt_post_location_redirect(string $location, string $post_id): string
1235
-    {
1236
-        // we DO have a match so let's setup the url
1237
-        // we have to get the post to determine our route
1238
-        $post       = get_post($post_id);
1239
-        $edit_route = $this->_cpt_edit_routes[ $post->post_type ];
1240
-        // shared query_args
1241
-        $query_args = ['action' => $edit_route, 'post' => $post_id];
1242
-
1243
-        $save = $this->request->getRequestParam('save');
1244
-        $publish = $this->request->getRequestParam('publish');
1245
-        $add_meta = $this->request->getRequestParam('addmeta');
1246
-        $delete_meta = $this->request->getRequestParam('deletemeta');
1247
-        if ($save || $publish) {
1248
-            $status = get_post_status($post_id);
1249
-            if ($publish) {
1250
-                switch ($status) {
1251
-                    case 'pending':
1252
-                        $message = 8;
1253
-                        break;
1254
-                    case 'future':
1255
-                        $message = 9;
1256
-                        break;
1257
-                    default:
1258
-                        $message = 6;
1259
-                }
1260
-            } else {
1261
-                $message = 'draft' === $status ? 10 : 1;
1262
-            }
1263
-        } elseif ($add_meta) {
1264
-            $message = 2;
1265
-        } elseif ($delete_meta) {
1266
-            $message = 3;
1267
-        } elseif ($this->request->getRequestParam('action') === 'post-quickpress-save-cont') {
1268
-            $message = 7;
1269
-        } else {
1270
-            $message = 4;
1271
-        }
1272
-        // change the message if the post type is not viewable on the frontend
1273
-        $this->_cpt_object = get_post_type_object($post->post_type);
1274
-
1275
-        $query_args['message'] = $message === 1 && ! $this->_cpt_object->publicly_queryable ? 4 : $message;
1276
-        $this->_process_notices($query_args, true);
1277
-        return EE_Admin_Page_CPT::add_query_args_and_nonce($query_args, $this->_admin_base_url);
1278
-    }
1279
-
1280
-
1281
-    /**
1282
-     * This method is called to inject nav tabs on core WP cpt pages
1283
-     *
1284
-     * @return void
1285
-     * @throws EE_Error
1286
-     */
1287
-    public function inject_nav_tabs()
1288
-    {
1289
-        echo wp_kses($this->_get_main_nav_tabs(), AllowedTags::getWithFormTags());
1290
-    }
1291
-
1292
-
1293
-    /**
1294
-     * This just sets up the post update messages when an update form is loaded
1295
-     *
1296
-     * @param array $messages the original messages array
1297
-     * @return array           the new messages array
1298
-     */
1299
-    public function post_update_messages(array $messages): array
1300
-    {
1301
-        global $post;
1302
-        $id       = $this->request->getRequestParam('post');
1303
-        $id       = empty($id) && is_object($post) ? $post->ID : null;
1304
-        $revision = $this->request->getRequestParam('revision', 0, 'int');
1305
-
1306
-        $messages[ $post->post_type ] = [
1307
-            0  => '', // Unused. Messages start at index 1.
1308
-            1  => sprintf(
1309
-                esc_html__('%1$s updated. %2$sView %1$s%3$s', 'event_espresso'),
1310
-                $this->_cpt_object->labels->singular_name,
1311
-                '<a href="' . esc_url(get_permalink($id)) . '">',
1312
-                '</a>'
1313
-            ),
1314
-            2  => esc_html__('Custom field updated', 'event_espresso'),
1315
-            3  => esc_html__('Custom field deleted.', 'event_espresso'),
1316
-            4  => sprintf(esc_html__('%1$s updated.', 'event_espresso'), $this->_cpt_object->labels->singular_name),
1317
-            5  => $revision
1318
-                ? sprintf(
1319
-                    esc_html__('%s restored to revision from %s', 'event_espresso'),
1320
-                    $this->_cpt_object->labels->singular_name,
1321
-                    wp_post_revision_title($revision, false)
1322
-                )
1323
-                : false,
1324
-            6  => sprintf(
1325
-                esc_html__('%1$s published. %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
-            7  => sprintf(esc_html__('%1$s saved.', 'event_espresso'), $this->_cpt_object->labels->singular_name),
1331
-            8  => sprintf(
1332
-                esc_html__('%1$s submitted. %2$sPreview %1$s%3$s', 'event_espresso'),
1333
-                $this->_cpt_object->labels->singular_name,
1334
-                '<a target="_blank" href="' . esc_url(add_query_arg('preview', 'true', get_permalink($id))) . '">',
1335
-                '</a>'
1336
-            ),
1337
-            9  => sprintf(
1338
-                esc_html__('%1$s scheduled for: %2$s. %3$s">Preview %1$s%3$s', 'event_espresso'),
1339
-                $this->_cpt_object->labels->singular_name,
1340
-                '<strong>' . date_i18n('M j, Y @ G:i', strtotime($post->post_date)) . '</strong>',
1341
-                '<a target="_blank" href="' . esc_url(get_permalink($id)),
1342
-                '</a>'
1343
-            ),
1344
-            10 => sprintf(
1345
-                esc_html__('%1$s draft updated. %2$s">Preview page%3$s', 'event_espresso'),
1346
-                $this->_cpt_object->labels->singular_name,
1347
-                '<a target="_blank" href="' . esc_url(add_query_arg('preview', 'true', get_permalink($id))),
1348
-                '</a>'
1349
-            ),
1350
-        ];
1351
-        return $messages;
1352
-    }
1353
-
1354
-
1355
-    /**
1356
-     * default method for the 'create_new' route for cpt admin pages.
1357
-     * For reference what to include in here, see wp-admin/post-new.php
1358
-     *
1359
-     * @return void
1360
-     */
1361
-    protected function _create_new_cpt_item()
1362
-    {
1363
-        // gather template vars for WP_ADMIN_PATH . 'edit-form-advanced.php'
1364
-        global $post, $title, $post_type, $post_type_object;
1365
-        $post_type        = $this->_cpt_routes[ $this->_req_action ];
1366
-        $post_type_object = $this->_cpt_object;
1367
-        $title            = $post_type_object->labels->add_new_item;
1368
-        $post             = $post = get_default_post_to_edit($this->_cpt_routes[ $this->_req_action ], true);
1369
-        add_action('admin_print_styles', [$this, 'add_new_admin_page_global']);
1370
-        // modify the default editor title field with default title.
1371
-        add_filter('enter_title_here', [$this, 'add_custom_editor_default_title']);
1372
-        $this->loadEditorTemplate();
1373
-    }
1374
-
1375
-
1376
-    /**
1377
-     * Enqueues auto-save and loads the editor template
1378
-     *
1379
-     * @param bool $creating
1380
-     */
1381
-    private function loadEditorTemplate(bool $creating = true)
1382
-    {
1383
-        global $post, $title, $is_IE, $post_type, $post_type_object;
1384
-        // these vars are used by the template
1385
-        $editing = true;
1386
-        $post_ID = $post->ID;
1387
-        if (apply_filters('FHEE__EE_Admin_Page_CPT___create_new_cpt_item__replace_editor', false, $post) === false) {
1388
-            // only enqueue autosave when creating event (necessary to get permalink/url generated)
1389
-            // otherwise EE doesn't support autosave fully, so to prevent user confusion we disable it in edit context.
1390
-            $action = $this->request->getRequestParam('action');
1391
-            if ($creating) {
1392
-                wp_enqueue_script('autosave');
1393
-            } elseif (
1394
-                isset($this->_cpt_routes[ $action ])
1395
-                && ! isset($this->_labels['hide_add_button_on_cpt_route'][ $action ])
1396
-            ) {
1397
-                $create_new_action = apply_filters(
1398
-                    'FHEE__EE_Admin_Page_CPT___edit_cpt_item__create_new_action',
1399
-                    'create_new',
1400
-                    $this
1401
-                );
1402
-                $post_new_file     = EE_Admin_Page::add_query_args_and_nonce(
1403
-                    [
1404
-                        'action' => $create_new_action,
1405
-                        'page'   => $this->page_slug,
1406
-                    ],
1407
-                    'admin.php'
1408
-                );
1409
-            }
1410
-            include_once WP_ADMIN_PATH . 'edit-form-advanced.php';
1411
-        }
1412
-    }
1413
-
1414
-
1415
-    public function add_new_admin_page_global()
1416
-    {
1417
-        $admin_page = $this->request->getRequestParam('post', 0, DataType::INT) !== 0
1418
-            ? 'post-php'
1419
-            : 'post-new-php';
1420
-        ?>
1128
+	}
1129
+
1130
+
1131
+	/**
1132
+	 * This allows us to redirect the location of revision restores when they happen so it goes to our CPT routes.
1133
+	 *
1134
+	 * @param string $location Original location url
1135
+	 * @return string           new (or original) url to redirect to.
1136
+	 * @throws EE_Error
1137
+	 */
1138
+	public function revision_redirect(string $location): string
1139
+	{
1140
+		// get revision
1141
+		$revision = $this->request->getRequestParam('revision');
1142
+		// can't do anything without revision so let's get out if not present
1143
+		if (empty($revision)) {
1144
+			return $location;
1145
+		}
1146
+		// get rev_post_data
1147
+		$rev        = get_post($revision);
1148
+		$admin_url  = $this->_admin_base_url;
1149
+		$query_args = [
1150
+			'action'   => 'edit',
1151
+			'post'     => $rev->post_parent,
1152
+			'revision' => $revision,
1153
+			'message'  => 5,
1154
+		];
1155
+		$this->_process_notices($query_args, true);
1156
+		return EE_Admin_Page_CPT::add_query_args_and_nonce($query_args, $admin_url);
1157
+	}
1158
+
1159
+
1160
+	/**
1161
+	 * Modify the edit post link generated by wp core function so that EE CPTs get setup differently.
1162
+	 *
1163
+	 * @param string $link    the original generated link
1164
+	 * @param int    $id      post id
1165
+	 * @return string          the link
1166
+	 */
1167
+	public function modify_edit_post_link(string $link, int $id): string
1168
+	{
1169
+		$post = get_post($id);
1170
+		$action = $this->request->getRequestParam('action');
1171
+		if (
1172
+			empty($action)
1173
+			|| ! isset($this->_cpt_routes[ $action ])
1174
+			|| $post->post_type !== $this->_cpt_routes[ $action ]
1175
+		) {
1176
+			return $link;
1177
+		}
1178
+		$query_args = [
1179
+			'action' => $this->_cpt_edit_routes[ $post->post_type ] ?? 'edit',
1180
+			'post'   => $id,
1181
+		];
1182
+		return EE_Admin_Page_CPT::add_query_args_and_nonce($query_args, $this->_admin_base_url);
1183
+	}
1184
+
1185
+
1186
+	/**
1187
+	 * Modify the trash link on our cpt edit pages so it has the required query var for triggering redirect properly on
1188
+	 * our routes.
1189
+	 *
1190
+	 * @param string $delete_link  original delete link
1191
+	 * @param int    $post_id      id of cpt object
1192
+	 * @return string new delete link
1193
+	 * @throws EE_Error
1194
+	 * @throws ReflectionException
1195
+	 */
1196
+	public function modify_delete_post_link(string $delete_link, int $post_id): string
1197
+	{
1198
+		$post = get_post($post_id);
1199
+		$action = $this->request->getRequestParam('action');
1200
+		if (
1201
+			! $post instanceof WP_Post
1202
+			|| empty($action)
1203
+			|| ! isset($this->_cpt_routes[ $action ])
1204
+			|| $post->post_type !== $this->_cpt_routes[ $action ]
1205
+		) {
1206
+			return $delete_link;
1207
+		}
1208
+		$this->_set_model_object($post->ID, true);
1209
+
1210
+		// returns something like `trash_event` or `trash_attendee` or `trash_venue`
1211
+		$action = 'trash_' . str_replace('ee_', '', strtolower(get_class($this->_cpt_model_obj)));
1212
+
1213
+		return EE_Admin_Page::add_query_args_and_nonce(
1214
+			[
1215
+				'page'   => $this->request->getRequestParam('page'),
1216
+				'action' => $action,
1217
+				$this->_cpt_model_obj->get_model()->get_primary_key_field()->get_name() => $post->ID,
1218
+			],
1219
+			admin_url()
1220
+		);
1221
+	}
1222
+
1223
+
1224
+	/**
1225
+	 * This is the callback for the 'redirect_post_location' filter in wp-admin/post.php
1226
+	 * so that we can hijack the default redirect locations for wp custom post types
1227
+	 * that WE'RE using and send back to OUR routes.  This should only be hooked in on the right route.
1228
+	 *
1229
+	 * @param string $location This is the incoming currently set redirect location
1230
+	 * @param string $post_id  This is the 'ID' value of the wp_posts table
1231
+	 * @return string           the new location to redirect to
1232
+	 * @throws EE_Error
1233
+	 */
1234
+	public function cpt_post_location_redirect(string $location, string $post_id): string
1235
+	{
1236
+		// we DO have a match so let's setup the url
1237
+		// we have to get the post to determine our route
1238
+		$post       = get_post($post_id);
1239
+		$edit_route = $this->_cpt_edit_routes[ $post->post_type ];
1240
+		// shared query_args
1241
+		$query_args = ['action' => $edit_route, 'post' => $post_id];
1242
+
1243
+		$save = $this->request->getRequestParam('save');
1244
+		$publish = $this->request->getRequestParam('publish');
1245
+		$add_meta = $this->request->getRequestParam('addmeta');
1246
+		$delete_meta = $this->request->getRequestParam('deletemeta');
1247
+		if ($save || $publish) {
1248
+			$status = get_post_status($post_id);
1249
+			if ($publish) {
1250
+				switch ($status) {
1251
+					case 'pending':
1252
+						$message = 8;
1253
+						break;
1254
+					case 'future':
1255
+						$message = 9;
1256
+						break;
1257
+					default:
1258
+						$message = 6;
1259
+				}
1260
+			} else {
1261
+				$message = 'draft' === $status ? 10 : 1;
1262
+			}
1263
+		} elseif ($add_meta) {
1264
+			$message = 2;
1265
+		} elseif ($delete_meta) {
1266
+			$message = 3;
1267
+		} elseif ($this->request->getRequestParam('action') === 'post-quickpress-save-cont') {
1268
+			$message = 7;
1269
+		} else {
1270
+			$message = 4;
1271
+		}
1272
+		// change the message if the post type is not viewable on the frontend
1273
+		$this->_cpt_object = get_post_type_object($post->post_type);
1274
+
1275
+		$query_args['message'] = $message === 1 && ! $this->_cpt_object->publicly_queryable ? 4 : $message;
1276
+		$this->_process_notices($query_args, true);
1277
+		return EE_Admin_Page_CPT::add_query_args_and_nonce($query_args, $this->_admin_base_url);
1278
+	}
1279
+
1280
+
1281
+	/**
1282
+	 * This method is called to inject nav tabs on core WP cpt pages
1283
+	 *
1284
+	 * @return void
1285
+	 * @throws EE_Error
1286
+	 */
1287
+	public function inject_nav_tabs()
1288
+	{
1289
+		echo wp_kses($this->_get_main_nav_tabs(), AllowedTags::getWithFormTags());
1290
+	}
1291
+
1292
+
1293
+	/**
1294
+	 * This just sets up the post update messages when an update form is loaded
1295
+	 *
1296
+	 * @param array $messages the original messages array
1297
+	 * @return array           the new messages array
1298
+	 */
1299
+	public function post_update_messages(array $messages): array
1300
+	{
1301
+		global $post;
1302
+		$id       = $this->request->getRequestParam('post');
1303
+		$id       = empty($id) && is_object($post) ? $post->ID : null;
1304
+		$revision = $this->request->getRequestParam('revision', 0, 'int');
1305
+
1306
+		$messages[ $post->post_type ] = [
1307
+			0  => '', // Unused. Messages start at index 1.
1308
+			1  => sprintf(
1309
+				esc_html__('%1$s updated. %2$sView %1$s%3$s', 'event_espresso'),
1310
+				$this->_cpt_object->labels->singular_name,
1311
+				'<a href="' . esc_url(get_permalink($id)) . '">',
1312
+				'</a>'
1313
+			),
1314
+			2  => esc_html__('Custom field updated', 'event_espresso'),
1315
+			3  => esc_html__('Custom field deleted.', 'event_espresso'),
1316
+			4  => sprintf(esc_html__('%1$s updated.', 'event_espresso'), $this->_cpt_object->labels->singular_name),
1317
+			5  => $revision
1318
+				? sprintf(
1319
+					esc_html__('%s restored to revision from %s', 'event_espresso'),
1320
+					$this->_cpt_object->labels->singular_name,
1321
+					wp_post_revision_title($revision, false)
1322
+				)
1323
+				: false,
1324
+			6  => sprintf(
1325
+				esc_html__('%1$s published. %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
+			7  => sprintf(esc_html__('%1$s saved.', 'event_espresso'), $this->_cpt_object->labels->singular_name),
1331
+			8  => sprintf(
1332
+				esc_html__('%1$s submitted. %2$sPreview %1$s%3$s', 'event_espresso'),
1333
+				$this->_cpt_object->labels->singular_name,
1334
+				'<a target="_blank" href="' . esc_url(add_query_arg('preview', 'true', get_permalink($id))) . '">',
1335
+				'</a>'
1336
+			),
1337
+			9  => sprintf(
1338
+				esc_html__('%1$s scheduled for: %2$s. %3$s">Preview %1$s%3$s', 'event_espresso'),
1339
+				$this->_cpt_object->labels->singular_name,
1340
+				'<strong>' . date_i18n('M j, Y @ G:i', strtotime($post->post_date)) . '</strong>',
1341
+				'<a target="_blank" href="' . esc_url(get_permalink($id)),
1342
+				'</a>'
1343
+			),
1344
+			10 => sprintf(
1345
+				esc_html__('%1$s draft updated. %2$s">Preview page%3$s', 'event_espresso'),
1346
+				$this->_cpt_object->labels->singular_name,
1347
+				'<a target="_blank" href="' . esc_url(add_query_arg('preview', 'true', get_permalink($id))),
1348
+				'</a>'
1349
+			),
1350
+		];
1351
+		return $messages;
1352
+	}
1353
+
1354
+
1355
+	/**
1356
+	 * default method for the 'create_new' route for cpt admin pages.
1357
+	 * For reference what to include in here, see wp-admin/post-new.php
1358
+	 *
1359
+	 * @return void
1360
+	 */
1361
+	protected function _create_new_cpt_item()
1362
+	{
1363
+		// gather template vars for WP_ADMIN_PATH . 'edit-form-advanced.php'
1364
+		global $post, $title, $post_type, $post_type_object;
1365
+		$post_type        = $this->_cpt_routes[ $this->_req_action ];
1366
+		$post_type_object = $this->_cpt_object;
1367
+		$title            = $post_type_object->labels->add_new_item;
1368
+		$post             = $post = get_default_post_to_edit($this->_cpt_routes[ $this->_req_action ], true);
1369
+		add_action('admin_print_styles', [$this, 'add_new_admin_page_global']);
1370
+		// modify the default editor title field with default title.
1371
+		add_filter('enter_title_here', [$this, 'add_custom_editor_default_title']);
1372
+		$this->loadEditorTemplate();
1373
+	}
1374
+
1375
+
1376
+	/**
1377
+	 * Enqueues auto-save and loads the editor template
1378
+	 *
1379
+	 * @param bool $creating
1380
+	 */
1381
+	private function loadEditorTemplate(bool $creating = true)
1382
+	{
1383
+		global $post, $title, $is_IE, $post_type, $post_type_object;
1384
+		// these vars are used by the template
1385
+		$editing = true;
1386
+		$post_ID = $post->ID;
1387
+		if (apply_filters('FHEE__EE_Admin_Page_CPT___create_new_cpt_item__replace_editor', false, $post) === false) {
1388
+			// only enqueue autosave when creating event (necessary to get permalink/url generated)
1389
+			// otherwise EE doesn't support autosave fully, so to prevent user confusion we disable it in edit context.
1390
+			$action = $this->request->getRequestParam('action');
1391
+			if ($creating) {
1392
+				wp_enqueue_script('autosave');
1393
+			} elseif (
1394
+				isset($this->_cpt_routes[ $action ])
1395
+				&& ! isset($this->_labels['hide_add_button_on_cpt_route'][ $action ])
1396
+			) {
1397
+				$create_new_action = apply_filters(
1398
+					'FHEE__EE_Admin_Page_CPT___edit_cpt_item__create_new_action',
1399
+					'create_new',
1400
+					$this
1401
+				);
1402
+				$post_new_file     = EE_Admin_Page::add_query_args_and_nonce(
1403
+					[
1404
+						'action' => $create_new_action,
1405
+						'page'   => $this->page_slug,
1406
+					],
1407
+					'admin.php'
1408
+				);
1409
+			}
1410
+			include_once WP_ADMIN_PATH . 'edit-form-advanced.php';
1411
+		}
1412
+	}
1413
+
1414
+
1415
+	public function add_new_admin_page_global()
1416
+	{
1417
+		$admin_page = $this->request->getRequestParam('post', 0, DataType::INT) !== 0
1418
+			? 'post-php'
1419
+			: 'post-new-php';
1420
+		?>
1421 1421
         <script type="text/javascript">
1422 1422
             adminpage = '<?php echo esc_js($admin_page); ?>';
1423 1423
         </script>
1424 1424
         <?php
1425
-    }
1426
-
1427
-
1428
-    /**
1429
-     * default method for the 'edit' route for cpt admin pages
1430
-     * For reference on what to put in here, refer to wp-admin/post.php
1431
-     *
1432
-     * @return void
1433
-     */
1434
-    protected function _edit_cpt_item()
1435
-    {
1436
-        global $post, $post_type, $post_type_object, $title;
1437
-        $post_id = $this->request->getRequestParam('post', 0, DataType::INT);
1438
-        $post    = $post_id ? get_post($post_id, OBJECT, 'edit') : null;
1439
-        if (empty($post)) {
1440
-            wp_die(
1441
-                esc_html__(
1442
-                    "You attempted to edit an item that doesn't exist. Perhaps it was deleted?",
1443
-                    'event_espresso'
1444
-                )
1445
-            );
1446
-        }
1447
-
1448
-        $post_lock = $this->request->getRequestParam('get-post-lock');
1449
-        if ($post_lock) {
1450
-            wp_set_post_lock($post_id);
1451
-            EEH_URL::safeRedirectAndExit(get_edit_post_link($post_id, 'url'));
1452
-        }
1453
-
1454
-        // template vars for WP_ADMIN_PATH . 'edit-form-advanced.php'
1455
-        $post_type        = $this->_cpt_routes[ $this->_req_action ];
1456
-        $post_type_object = $this->_cpt_object;
1457
-        $title = $this->_labels['editor_title'][ $this->_cpt_routes[ $this->_req_action ] ]
1458
-                 ?? $post_type_object->labels->edit_item;
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', [$this, 'add_new_admin_page_global']);
1469
-        // modify the default editor title field with default title.
1470
-        add_filter('enter_title_here', [$this, 'add_custom_editor_default_title']);
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
-    }
1425
+	}
1426
+
1427
+
1428
+	/**
1429
+	 * default method for the 'edit' route for cpt admin pages
1430
+	 * For reference on what to put in here, refer to wp-admin/post.php
1431
+	 *
1432
+	 * @return void
1433
+	 */
1434
+	protected function _edit_cpt_item()
1435
+	{
1436
+		global $post, $post_type, $post_type_object, $title;
1437
+		$post_id = $this->request->getRequestParam('post', 0, DataType::INT);
1438
+		$post    = $post_id ? get_post($post_id, OBJECT, 'edit') : null;
1439
+		if (empty($post)) {
1440
+			wp_die(
1441
+				esc_html__(
1442
+					"You attempted to edit an item that doesn't exist. Perhaps it was deleted?",
1443
+					'event_espresso'
1444
+				)
1445
+			);
1446
+		}
1447
+
1448
+		$post_lock = $this->request->getRequestParam('get-post-lock');
1449
+		if ($post_lock) {
1450
+			wp_set_post_lock($post_id);
1451
+			EEH_URL::safeRedirectAndExit(get_edit_post_link($post_id, 'url'));
1452
+		}
1453
+
1454
+		// template vars for WP_ADMIN_PATH . 'edit-form-advanced.php'
1455
+		$post_type        = $this->_cpt_routes[ $this->_req_action ];
1456
+		$post_type_object = $this->_cpt_object;
1457
+		$title = $this->_labels['editor_title'][ $this->_cpt_routes[ $this->_req_action ] ]
1458
+				 ?? $post_type_object->labels->edit_item;
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', [$this, 'add_new_admin_page_global']);
1469
+		// modify the default editor title field with default title.
1470
+		add_filter('enter_title_here', [$this, 'add_custom_editor_default_title']);
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
 }
Please login to merge, or discard this patch.
core/admin/EE_Admin.core.php 1 patch
Indentation   +998 added lines, -998 removed lines patch added patch discarded remove patch
@@ -20,1002 +20,1002 @@
 block discarded – undo
20 20
  */
21 21
 final class EE_Admin implements InterminableInterface
22 22
 {
23
-    /**
24
-     * @var EE_Admin $_instance
25
-     */
26
-    private static $_instance;
27
-
28
-    /**
29
-     * @var PersistentAdminNoticeManager $persistent_admin_notice_manager
30
-     */
31
-    private $persistent_admin_notice_manager;
32
-
33
-    /**
34
-     * @var LoaderInterface $loader
35
-     */
36
-    protected $loader;
37
-
38
-    /**
39
-     * @var RequestInterface
40
-     */
41
-    protected $request;
42
-
43
-
44
-    /**
45
-     * @singleton method used to instantiate class object
46
-     * @param LoaderInterface  $loader
47
-     * @param RequestInterface $request
48
-     * @return EE_Admin
49
-     * @throws EE_Error
50
-     */
51
-    public static function instance(LoaderInterface $loader = null, RequestInterface $request = null)
52
-    {
53
-        // check if class object is instantiated
54
-        if (! EE_Admin::$_instance instanceof EE_Admin) {
55
-            EE_Admin::$_instance = new EE_Admin($loader, $request);
56
-        }
57
-        return EE_Admin::$_instance;
58
-    }
59
-
60
-
61
-    /**
62
-     * @return EE_Admin
63
-     * @throws EE_Error
64
-     */
65
-    public static function reset()
66
-    {
67
-        EE_Admin::$_instance = null;
68
-        $loader = LoaderFactory::getLoader();
69
-        $request = $loader->getShared('EventEspresso\core\services\request\Request');
70
-        return EE_Admin::instance($loader, $request);
71
-    }
72
-
73
-
74
-    /**
75
-     * @param LoaderInterface  $loader
76
-     * @param RequestInterface $request
77
-     * @throws EE_Error
78
-     * @throws InvalidDataTypeException
79
-     * @throws InvalidInterfaceException
80
-     * @throws InvalidArgumentException
81
-     */
82
-    protected function __construct(LoaderInterface $loader, RequestInterface $request)
83
-    {
84
-        $this->loader = $loader;
85
-        $this->request = $request;
86
-        // define global EE_Admin constants
87
-        $this->_define_all_constants();
88
-        // set autoloaders for our admin page classes based on included path information
89
-        EEH_Autoloader::register_autoloaders_for_each_file_in_folder(EE_ADMIN);
90
-        // reset Environment config (we only do this on admin page loads);
91
-        EE_Registry::instance()->CFG->environment->recheck_values();
92
-        // load EE_Request_Handler early
93
-        add_action('AHEE__EE_System__initialize_last', [$this, 'init']);
94
-        add_action('admin_init', [$this, 'admin_init'], 100);
95
-        if (! $this->request->isAjax()) {
96
-            // admin hooks
97
-            add_action('admin_notices', [$this, 'display_admin_notices'], 10);
98
-            add_action('network_admin_notices', [$this, 'display_admin_notices'], 10);
99
-            add_filter('pre_update_option', [$this, 'check_for_invalid_datetime_formats'], 100, 2);
100
-            add_filter('plugin_action_links', [$this, 'filter_plugin_actions'], 10, 2);
101
-            add_filter('admin_footer_text', [$this, 'espresso_admin_footer']);
102
-            add_action('display_post_states', [$this, 'displayStateForCriticalPages'], 10, 2);
103
-            add_filter('plugin_row_meta', [$this, 'addLinksToPluginRowMeta'], 10, 2);
104
-        }
105
-        do_action('AHEE__EE_Admin__loaded');
106
-    }
107
-
108
-
109
-    /**
110
-     * _define_all_constants
111
-     * define constants that are set globally for all admin pages
112
-     *
113
-     * @return void
114
-     */
115
-    private function _define_all_constants()
116
-    {
117
-        if (! defined('EE_ADMIN_URL')) {
118
-            define('EE_ADMIN_URL', EE_PLUGIN_DIR_URL . 'core/admin/');
119
-            define('EE_ADMIN_PAGES_URL', EE_PLUGIN_DIR_URL . 'admin_pages/');
120
-            define('EE_ADMIN_TEMPLATE', EE_ADMIN . 'templates/');
121
-            define('WP_ADMIN_PATH', ABSPATH . 'wp-admin/');
122
-            define('WP_AJAX_URL', admin_url('admin-ajax.php'));
123
-        }
124
-    }
125
-
126
-
127
-    /**
128
-     * filter_plugin_actions - adds links to the Plugins page listing
129
-     *
130
-     * @param array  $links
131
-     * @param string $plugin
132
-     * @return    array
133
-     */
134
-    public function filter_plugin_actions($links, $plugin)
135
-    {
136
-        // set $main_file in stone
137
-        static $main_file;
138
-        // if $main_file is not set yet
139
-        if (! $main_file) {
140
-            $main_file = EE_PLUGIN_BASENAME;
141
-        }
142
-        if ($plugin === $main_file) {
143
-            // compare current plugin to this one
144
-            if (EE_Maintenance_Mode::instance()->level() === EE_Maintenance_Mode::level_2_complete_maintenance) {
145
-                $maintenance_link = '<a href="admin.php?page=espresso_maintenance_settings"'
146
-                                    . ' title="Event Espresso is in maintenance mode.  Click this link to learn why.">'
147
-                                    . esc_html__('Maintenance Mode Active', 'event_espresso')
148
-                                    . '</a>';
149
-                array_unshift($links, $maintenance_link);
150
-            } else {
151
-                $org_settings_link = '<a href="admin.php?page=espresso_general_settings">'
152
-                                     . esc_html__('Settings', 'event_espresso')
153
-                                     . '</a>';
154
-                $events_link       = '<a href="admin.php?page=espresso_events">'
155
-                                     . esc_html__('Events', 'event_espresso')
156
-                                     . '</a>';
157
-                // add before other links
158
-                array_unshift($links, $org_settings_link, $events_link);
159
-            }
160
-        }
161
-        return $links;
162
-    }
163
-
164
-
165
-    /**
166
-     * hide_admin_pages_except_maintenance_mode
167
-     *
168
-     * @param array $admin_page_folder_names
169
-     * @return array
170
-     */
171
-    public function hide_admin_pages_except_maintenance_mode($admin_page_folder_names = [])
172
-    {
173
-        return [
174
-            'maintenance' => EE_ADMIN_PAGES . 'maintenance/',
175
-            'about'       => EE_ADMIN_PAGES . 'about/',
176
-            'support'     => EE_ADMIN_PAGES . 'support/',
177
-        ];
178
-    }
179
-
180
-
181
-    /**
182
-     * init- should fire after shortcode, module,  addon, other plugin (default priority), and even
183
-     * EE_Front_Controller's init phases have run
184
-     *
185
-     * @return void
186
-     * @throws EE_Error
187
-     * @throws InvalidArgumentException
188
-     * @throws InvalidDataTypeException
189
-     * @throws InvalidInterfaceException
190
-     * @throws ReflectionException
191
-     * @throws ServiceNotFoundException
192
-     */
193
-    public function init()
194
-    {
195
-        // only enable most of the EE_Admin IF we're not in full maintenance mode
196
-        if (EE_Maintenance_Mode::instance()->models_can_query()) {
197
-            $this->initModelsReady();
198
-        }
199
-        // run the admin page factory but ONLY if:
200
-        // - it is a regular non ajax admin request
201
-        // - we are doing an ee admin ajax request
202
-        if ($this->request->isAdmin() || $this->request->isAdminAjax() || $this->request->isActivation()) {
203
-            try {
204
-                // this loads the controller for the admin pages which will setup routing etc
205
-                $admin_page_loader = $this->loader->getShared('EE_Admin_Page_Loader', [$this->loader]);
206
-                /** @var EE_Admin_Page_Loader $admin_page_loader */
207
-                $admin_page_loader->init();
208
-            } catch (EE_Error $e) {
209
-                $e->get_error();
210
-            }
211
-        }
212
-        if ($this->request->isAjax()) {
213
-            return;
214
-        }
215
-        add_filter('content_save_pre', [$this, 'its_eSpresso'], 10, 1);
216
-        // make sure our CPTs and custom taxonomy metaboxes get shown for first time users
217
-        add_action('admin_head', [$this, 'enable_hidden_ee_nav_menu_metaboxes'], 10);
218
-        add_action('admin_head', [$this, 'register_custom_nav_menu_boxes'], 10);
219
-        // exclude EE critical pages from all nav menus and wp_list_pages
220
-        add_filter('nav_menu_meta_box_object', [$this, 'remove_pages_from_nav_menu'], 10);
221
-    }
222
-
223
-
224
-    /**
225
-     * Gets the loader (and if it wasn't previously set, sets it)
226
-     *
227
-     * @return LoaderInterface
228
-     * @throws InvalidArgumentException
229
-     * @throws InvalidDataTypeException
230
-     * @throws InvalidInterfaceException
231
-     */
232
-    protected function getLoader()
233
-    {
234
-        return $this->loader;
235
-    }
236
-
237
-
238
-    /**
239
-     * Method that's fired on admin requests (including admin ajax) but only when the models are usable
240
-     * (ie, the site isn't in maintenance mode)
241
-     *
242
-     * @return void
243
-     * @throws EE_Error
244
-     * @since 4.9.63.p
245
-     */
246
-    protected function initModelsReady()
247
-    {
248
-        // ok so we want to enable the entire admin
249
-        $this->persistent_admin_notice_manager = $this->loader->getShared(
250
-            'EventEspresso\core\services\notifications\PersistentAdminNoticeManager'
251
-        );
252
-        $this->persistent_admin_notice_manager->setReturnUrl(
253
-            EE_Admin_Page::add_query_args_and_nonce(
254
-                [
255
-                    'page'   => $this->request->getRequestParam('page', ''),
256
-                    'action' => $this->request->getRequestParam('action', ''),
257
-                ],
258
-                EE_ADMIN_URL
259
-            )
260
-        );
261
-        $this->maybeSetDatetimeWarningNotice();
262
-        // at a glance dashboard widget
263
-        add_filter('dashboard_glance_items', [$this, 'dashboard_glance_items'], 10);
264
-        // filter for get_edit_post_link used on comments for custom post types
265
-        add_filter('get_edit_post_link', [$this, 'modify_edit_post_link'], 10, 2);
266
-    }
267
-
268
-
269
-    /**
270
-     *    get_persistent_admin_notices
271
-     *
272
-     * @access    public
273
-     * @return void
274
-     * @throws EE_Error
275
-     * @throws InvalidArgumentException
276
-     * @throws InvalidDataTypeException
277
-     * @throws InvalidInterfaceException
278
-     */
279
-    public function maybeSetDatetimeWarningNotice()
280
-    {
281
-        // add dismissible notice for datetime changes.  Only valid if site does not have a timezone_string set.
282
-        // @todo This needs to stay in core for a bit to catch anyone upgrading from a version without this to a version
283
-        // with this.  But after enough time (indeterminate at this point) we can just remove this notice.
284
-        // this was added with https://events.codebasehq.com/projects/event-espresso/tickets/10626
285
-        if (
286
-            apply_filters('FHEE__EE_Admin__maybeSetDatetimeWarningNotice', true)
287
-            && ! get_option('timezone_string')
288
-            && EEM_Event::instance()->count() > 0
289
-        ) {
290
-            new PersistentAdminNotice(
291
-                'datetime_fix_notice',
292
-                sprintf(
293
-                    esc_html__(
294
-                        '%1$sImportant announcement related to your install of Event Espresso%2$s: There are some changes made to your site that could affect how dates display for your events and other related items with dates and times.  Read more about it %3$shere%4$s. If your dates and times are displaying incorrectly (incorrect offset), you can fix it using the tool on %5$sthis page%4$s.',
295
-                        'event_espresso'
296
-                    ),
297
-                    '<strong>',
298
-                    '</strong>',
299
-                    '<a href="https://eventespresso.com/2017/08/important-upcoming-changes-dates-times">',
300
-                    '</a>',
301
-                    '<a href="' . EE_Admin_Page::add_query_args_and_nonce(
302
-                        [
303
-                            'page'   => 'espresso_maintenance_settings',
304
-                            'action' => 'datetime_tools',
305
-                        ],
306
-                        admin_url('admin.php')
307
-                    ) . '">'
308
-                ),
309
-                false,
310
-                'manage_options',
311
-                'datetime_fix_persistent_notice'
312
-            );
313
-        }
314
-    }
315
-
316
-
317
-    /**
318
-     * this simply hooks into the nav menu setup of pages metabox and makes sure that we remove EE critical pages from
319
-     * the list of options. the wp function "wp_nav_menu_item_post_type_meta_box" found in
320
-     * wp-admin/includes/nav-menu.php looks for the "_default_query" property on the post_type object and it uses that
321
-     * to override any queries found in the existing query for the given post type.  Note that _default_query is not a
322
-     * normal property on the post_type object.  It's found ONLY in this particular context.
323
-     *
324
-     * @param WP_Post $post_type WP post type object
325
-     * @return WP_Post
326
-     * @throws InvalidArgumentException
327
-     * @throws InvalidDataTypeException
328
-     * @throws InvalidInterfaceException
329
-     */
330
-    public function remove_pages_from_nav_menu($post_type)
331
-    {
332
-        // if this isn't the "pages" post type let's get out
333
-        if ($post_type->name !== 'page') {
334
-            return $post_type;
335
-        }
336
-        $critical_pages            = EE_Registry::instance()->CFG->core->get_critical_pages_array();
337
-        $post_type->_default_query = [
338
-            'post__not_in' => $critical_pages,
339
-        ];
340
-        return $post_type;
341
-    }
342
-
343
-
344
-    /**
345
-     * WP by default only shows three metaboxes in "nav-menus.php" for first times users.
346
-     * We want to make sure our metaboxes get shown as well
347
-     *
348
-     * @return void
349
-     */
350
-    public function enable_hidden_ee_nav_menu_metaboxes()
351
-    {
352
-        global $wp_meta_boxes, $pagenow;
353
-        if (! is_array($wp_meta_boxes) || $pagenow !== 'nav-menus.php') {
354
-            return;
355
-        }
356
-        $user = wp_get_current_user();
357
-        // has this been done yet?
358
-        if (get_user_option('ee_nav_menu_initialized', $user->ID)) {
359
-            return;
360
-        }
361
-
362
-        $hidden_meta_boxes  = get_user_option('metaboxhidden_nav-menus', $user->ID);
363
-        $initial_meta_boxes = apply_filters(
364
-            'FHEE__EE_Admin__enable_hidden_ee_nav_menu_boxes__initial_meta_boxes',
365
-            [
366
-                'nav-menu-theme-locations',
367
-                'add-page',
368
-                'add-custom-links',
369
-                'add-category',
370
-                'add-espresso_events',
371
-                'add-espresso_venues',
372
-                'add-espresso_event_categories',
373
-                'add-espresso_venue_categories',
374
-                'add-post-type-post',
375
-                'add-post-type-page',
376
-            ]
377
-        );
378
-
379
-        if (is_array($hidden_meta_boxes)) {
380
-            foreach ($hidden_meta_boxes as $key => $meta_box_id) {
381
-                if (in_array($meta_box_id, $initial_meta_boxes, true)) {
382
-                    unset($hidden_meta_boxes[ $key ]);
383
-                }
384
-            }
385
-        }
386
-        update_user_option($user->ID, 'metaboxhidden_nav-menus', $hidden_meta_boxes, true);
387
-        update_user_option($user->ID, 'ee_nav_menu_initialized', 1, true);
388
-    }
389
-
390
-
391
-    /**
392
-     * This method simply registers custom nav menu boxes for "nav_menus.php route"
393
-     * Currently EE is using this to make sure there are menu options for our CPT archive page routes.
394
-     *
395
-     * @return void
396
-     * @todo   modify this so its more dynamic and automatic for all ee CPTs and setups and can also be hooked into by
397
-     *         addons etc.
398
-     */
399
-    public function register_custom_nav_menu_boxes()
400
-    {
401
-        add_meta_box(
402
-            'add-extra-nav-menu-pages',
403
-            esc_html__('Event Espresso Pages', 'event_espresso'),
404
-            [$this, 'ee_cpt_archive_pages'],
405
-            'nav-menus',
406
-            'side',
407
-            'core'
408
-        );
409
-        add_filter(
410
-            "postbox_classes_nav-menus_add-extra-nav-menu-pages",
411
-            function ($classes) {
412
-                array_push($classes, 'ee-admin-container');
413
-                return $classes;
414
-            }
415
-        );
416
-    }
417
-
418
-
419
-    /**
420
-     * Use this to edit the post link for our cpts so that the edit link points to the correct page.
421
-     *
422
-     * @param string $link the original link generated by wp
423
-     * @param int    $id   post id
424
-     * @return string  the (maybe) modified link
425
-     * @since   4.3.0
426
-     */
427
-    public function modify_edit_post_link($link, $id)
428
-    {
429
-        if (! $post = get_post($id)) {
430
-            return $link;
431
-        }
432
-        if ($post->post_type === 'espresso_attendees') {
433
-            $query_args = [
434
-                'action' => 'edit_attendee',
435
-                'post'   => $id,
436
-            ];
437
-            return EEH_URL::add_query_args_and_nonce(
438
-                $query_args,
439
-                admin_url('admin.php?page=espresso_registrations')
440
-            );
441
-        }
442
-        return $link;
443
-    }
444
-
445
-
446
-    public function ee_cpt_archive_pages()
447
-    {
448
-        global $nav_menu_selected_id;
449
-        $removed_args = [
450
-            'action',
451
-            'customlink-tab',
452
-            'edit-menu-item',
453
-            'menu-item',
454
-            'page-tab',
455
-            '_wpnonce',
456
-        ];
457
-        $nav_tab_link = $nav_menu_selected_id
458
-            ? esc_url(
459
-                add_query_arg(
460
-                    'extra-nav-menu-pages-tab',
461
-                    'event-archives',
462
-                    remove_query_arg($removed_args)
463
-                )
464
-            )
465
-            : '';
466
-        $select_all_link = esc_url(
467
-            add_query_arg(
468
-                [
469
-                    'extra-nav-menu-pages-tab' => 'event-archives',
470
-                    'selectall'                => 1,
471
-                ],
472
-                remove_query_arg($removed_args)
473
-            )
474
-        );
475
-        $pages = $this->_get_extra_nav_menu_pages_items();
476
-        $args['walker'] = new Walker_Nav_Menu_Checklist(false);
477
-        ;
478
-        $nav_menu_pages_items = walk_nav_menu_tree(
479
-            array_map(
480
-                [$this, '_setup_extra_nav_menu_pages_items'],
481
-                $pages
482
-            ),
483
-            0,
484
-            (object) $args
485
-        );
486
-        EEH_Template::display_template(
487
-            EE_ADMIN_TEMPLATE . 'cpt_archive_page.template.php',
488
-            [
489
-                'nav_menu_selected_id' => $nav_menu_selected_id,
490
-                'nav_menu_pages_items' => $nav_menu_pages_items,
491
-                'nav_tab_link'         => $nav_tab_link,
492
-                'select_all_link'      => $select_all_link,
493
-            ]
494
-        );
495
-    }
496
-
497
-
498
-    /**
499
-     * Returns an array of event archive nav items.
500
-     *
501
-     * @return array
502
-     * @todo  for now this method is just in place so when it gets abstracted further we can substitute in whatever
503
-     *        method we use for getting the extra nav menu items
504
-     */
505
-    private function _get_extra_nav_menu_pages_items()
506
-    {
507
-        $menuitems[] = [
508
-            'title'       => esc_html__('Event List', 'event_espresso'),
509
-            'url'         => get_post_type_archive_link('espresso_events'),
510
-            'description' => esc_html__('Archive page for all events.', 'event_espresso'),
511
-        ];
512
-        return apply_filters('FHEE__EE_Admin__get_extra_nav_menu_pages_items', $menuitems);
513
-    }
514
-
515
-
516
-    /**
517
-     * Setup nav menu walker item for usage in the event archive nav menu metabox.  It receives a menu_item array with
518
-     * the properties and converts it to the menu item object.
519
-     *
520
-     * @param $menu_item_values
521
-     * @return stdClass
522
-     * @see wp_setup_nav_menu_item() in wp-includes/nav-menu.php
523
-     */
524
-    private function _setup_extra_nav_menu_pages_items($menu_item_values)
525
-    {
526
-        $menu_item = new stdClass();
527
-        $keys      = [
528
-            'ID'               => 0,
529
-            'db_id'            => 0,
530
-            'menu_item_parent' => 0,
531
-            'object_id'        => -1,
532
-            'post_parent'      => 0,
533
-            'type'             => 'custom',
534
-            'object'           => '',
535
-            'type_label'       => esc_html__('Extra Nav Menu Item', 'event_espresso'),
536
-            'title'            => '',
537
-            'url'              => '',
538
-            'target'           => '',
539
-            'attr_title'       => '',
540
-            'description'      => '',
541
-            'classes'          => [],
542
-            'xfn'              => '',
543
-        ];
544
-        foreach ($keys as $key => $value) {
545
-            $menu_item->{$key} = $menu_item_values[ $key ] ?? $value;
546
-        }
547
-        return $menu_item;
548
-    }
549
-
550
-
551
-    /**
552
-     * admin_init
553
-     *
554
-     * @return void
555
-     * @throws InvalidArgumentException
556
-     * @throws InvalidDataTypeException
557
-     * @throws InvalidInterfaceException
558
-     */
559
-    public function admin_init()
560
-    {
561
-        /**
562
-         * our cpt models must be instantiated on WordPress post processing routes (wp-admin/post.php),
563
-         * so any hooking into core WP routes is taken care of.  So in this next few lines of code:
564
-         * - check if doing post processing.
565
-         * - check if doing post processing of one of EE CPTs
566
-         * - instantiate the corresponding EE CPT model for the post_type being processed.
567
-         */
568
-        $action    = $this->request->getRequestParam('action');
569
-        $post_type = $this->request->getRequestParam('post_type');
570
-        if ($post_type && $action === 'editpost') {
571
-            /** @var CustomPostTypeDefinitions $custom_post_types */
572
-            $custom_post_types = $this->loader->getShared(CustomPostTypeDefinitions::class);
573
-            $custom_post_types->getCustomPostTypeModels($post_type);
574
-        }
575
-
576
-
577
-        if (! $this->request->isAjax()) {
578
-            /**
579
-             * This code excludes EE critical pages anywhere `wp_dropdown_pages` is used to create a dropdown for selecting
580
-             * critical pages.  The only place critical pages need included in a generated dropdown is on the "Critical
581
-             * Pages" tab in the EE General Settings Admin page.
582
-             * This is for user-proofing.
583
-             */
584
-            add_filter('wp_dropdown_pages', [$this, 'modify_dropdown_pages']);
585
-            if (EE_Maintenance_Mode::instance()->models_can_query()) {
586
-                $this->adminInitModelsReady();
587
-            }
588
-        }
589
-    }
590
-
591
-
592
-    /**
593
-     * Runs on admin_init but only if models are usable (ie, we're not in maintenance mode)
594
-     */
595
-    protected function adminInitModelsReady()
596
-    {
597
-        if (function_exists('wp_add_privacy_policy_content')) {
598
-            $this->loader->getShared('EventEspresso\core\services\privacy\policy\PrivacyPolicyManager');
599
-        }
600
-    }
601
-
602
-
603
-    /**
604
-     * Callback for wp_dropdown_pages hook to remove ee critical pages from the dropdown selection.
605
-     *
606
-     * @param string $output Current output.
607
-     * @return string
608
-     * @throws InvalidArgumentException
609
-     * @throws InvalidDataTypeException
610
-     * @throws InvalidInterfaceException
611
-     */
612
-    public function modify_dropdown_pages($output)
613
-    {
614
-        // get critical pages
615
-        $critical_pages = EE_Registry::instance()->CFG->core->get_critical_pages_array();
616
-
617
-        // split current output by line break for easier parsing.
618
-        $split_output = explode("\n", $output);
619
-
620
-        // loop through to remove any critical pages from the array.
621
-        foreach ($critical_pages as $page_id) {
622
-            $needle = 'value="' . $page_id . '"';
623
-            foreach ($split_output as $key => $haystack) {
624
-                if (strpos($haystack, $needle) !== false) {
625
-                    unset($split_output[ $key ]);
626
-                }
627
-            }
628
-        }
629
-        // replace output with the new contents
630
-        return implode("\n", $split_output);
631
-    }
632
-
633
-
634
-    /**
635
-     * display_admin_notices
636
-     *
637
-     * @return void
638
-     */
639
-    public function display_admin_notices()
640
-    {
641
-        echo EE_Error::get_notices(); // already escaped
642
-    }
643
-
644
-
645
-    /**
646
-     * @param array $elements
647
-     * @return array
648
-     * @throws EE_Error
649
-     * @throws InvalidArgumentException
650
-     * @throws InvalidDataTypeException
651
-     * @throws InvalidInterfaceException
652
-     */
653
-    public function dashboard_glance_items($elements)
654
-    {
655
-        $elements                        = is_array($elements) ? $elements : [$elements];
656
-        $events                          = EEM_Event::instance()->count();
657
-        $items['events']['url']          = EE_Admin_Page::add_query_args_and_nonce(
658
-            ['page' => 'espresso_events'],
659
-            admin_url('admin.php')
660
-        );
661
-        $items['events']['text']         = sprintf(
662
-            esc_html(
663
-                _n('%s Event', '%s Events', $events, 'event_espresso')
664
-            ),
665
-            number_format_i18n($events)
666
-        );
667
-        $items['events']['title']        = esc_html__('Click to view all Events', 'event_espresso');
668
-        $registrations                   = EEM_Registration::instance()->count(
669
-            [
670
-                [
671
-                    'STS_ID' => ['!=', EEM_Registration::status_id_incomplete],
672
-                ],
673
-            ]
674
-        );
675
-        $items['registrations']['url']   = EE_Admin_Page::add_query_args_and_nonce(
676
-            ['page' => 'espresso_registrations'],
677
-            admin_url('admin.php')
678
-        );
679
-        $items['registrations']['text']  = sprintf(
680
-            esc_html(
681
-                _n('%s Registration', '%s Registrations', $registrations, 'event_espresso')
682
-            ),
683
-            number_format_i18n($registrations)
684
-        );
685
-        $items['registrations']['title'] = esc_html__('Click to view all registrations', 'event_espresso');
686
-
687
-        $items = (array) apply_filters('FHEE__EE_Admin__dashboard_glance_items__items', $items);
688
-
689
-        foreach ($items as $type => $item_properties) {
690
-            $elements[] = sprintf(
691
-                '<a class="ee-dashboard-link-' . $type . '" href="%s" title="%s">%s</a>',
692
-                $item_properties['url'],
693
-                $item_properties['title'],
694
-                $item_properties['text']
695
-            );
696
-        }
697
-        return $elements;
698
-    }
699
-
700
-
701
-    /**
702
-     * check_for_invalid_datetime_formats
703
-     * if an admin changes their date or time format settings on the WP General Settings admin page, verify that
704
-     * their selected format can be parsed by PHP
705
-     *
706
-     * @param    $value
707
-     * @param    $option
708
-     * @return    string
709
-     */
710
-    public function check_for_invalid_datetime_formats($value, $option)
711
-    {
712
-        // check for date_format or time_format
713
-        switch ($option) {
714
-            case 'date_format':
715
-                $date_time_format = $value . ' ' . get_option('time_format');
716
-                break;
717
-            case 'time_format':
718
-                $date_time_format = get_option('date_format') . ' ' . $value;
719
-                break;
720
-            default:
721
-                $date_time_format = false;
722
-        }
723
-        // do we have a date_time format to check ?
724
-        if ($date_time_format) {
725
-            $error_msg = EEH_DTT_Helper::validate_format_string($date_time_format);
726
-
727
-            if (is_array($error_msg)) {
728
-                $msg = '<p>'
729
-                       . sprintf(
730
-                           esc_html__(
731
-                               'The following date time "%s" ( %s ) is difficult to be properly parsed by PHP for the following reasons:',
732
-                               'event_espresso'
733
-                           ),
734
-                           date($date_time_format),
735
-                           $date_time_format
736
-                       )
737
-                       . '</p><p><ul>';
738
-
739
-
740
-                foreach ($error_msg as $error) {
741
-                    $msg .= '<li>' . $error . '</li>';
742
-                }
743
-
744
-                $msg .= '</ul></p><p>'
745
-                        . sprintf(
746
-                            esc_html__(
747
-                                '%sPlease note that your date and time formats have been reset to "F j, Y" and "g:i a" respectively.%s',
748
-                                'event_espresso'
749
-                            ),
750
-                            '<span style="color:#D54E21;">',
751
-                            '</span>'
752
-                        )
753
-                        . '</p>';
754
-
755
-                // trigger WP settings error
756
-                add_settings_error(
757
-                    'date_format',
758
-                    'date_format',
759
-                    $msg
760
-                );
761
-
762
-                // set format to something valid
763
-                switch ($option) {
764
-                    case 'date_format':
765
-                        $value = 'F j, Y';
766
-                        break;
767
-                    case 'time_format':
768
-                        $value = 'g:i a';
769
-                        break;
770
-                }
771
-            }
772
-        }
773
-        return $value;
774
-    }
775
-
776
-
777
-    /**
778
-     * its_eSpresso - converts the less commonly used spelling of "Expresso" to "Espresso"
779
-     *
780
-     * @param $content
781
-     * @return    string
782
-     */
783
-    public function its_eSpresso($content)
784
-    {
785
-        return str_replace('[EXPRESSO_', '[ESPRESSO_', $content);
786
-    }
787
-
788
-
789
-    /**
790
-     * espresso_admin_footer
791
-     *
792
-     * @return    string
793
-     */
794
-    public function espresso_admin_footer()
795
-    {
796
-        return EEH_Template::powered_by_event_espresso('aln-cntr', '', ['utm_content' => 'admin_footer']);
797
-    }
798
-
799
-
800
-    /**
801
-     * Hooks into the "post states" filter in a wp post type list table.
802
-     *
803
-     * @param array   $post_states
804
-     * @param WP_Post $post
805
-     * @return array
806
-     * @throws InvalidArgumentException
807
-     * @throws InvalidDataTypeException
808
-     * @throws InvalidInterfaceException
809
-     */
810
-    public function displayStateForCriticalPages($post_states, $post)
811
-    {
812
-        $post_states = (array) $post_states;
813
-        if (! $post instanceof WP_Post || $post->post_type !== 'page') {
814
-            return $post_states;
815
-        }
816
-        /** @var EE_Core_Config $config */
817
-        $config = $this->loader->getShared('EE_Config')->core;
818
-        if (in_array($post->ID, $config->get_critical_pages_array(), true)) {
819
-            $post_states[] = sprintf(
820
-            /* Translators: Using company name - Event Espresso Critical Page */
821
-                esc_html__('%s Critical Page', 'event_espresso'),
822
-                'Event Espresso'
823
-            );
824
-        }
825
-        return $post_states;
826
-    }
827
-
828
-
829
-    /**
830
-     * Show documentation links on the plugins page
831
-     *
832
-     * @param mixed $meta Plugin Row Meta
833
-     * @param mixed $file Plugin Base file
834
-     * @return array
835
-     */
836
-    public function addLinksToPluginRowMeta($meta, $file)
837
-    {
838
-        if (EE_PLUGIN_BASENAME === $file) {
839
-            $row_meta = [
840
-                'docs' => '<a href="https://eventespresso.com/support/documentation/versioned-docs/?doc_ver=ee4"'
841
-                          . ' aria-label="'
842
-                          . esc_attr__('View Event Espresso documentation', 'event_espresso')
843
-                          . '">'
844
-                          . esc_html__('Docs', 'event_espresso')
845
-                          . '</a>',
846
-                'api'  => '<a href="https://github.com/eventespresso/event-espresso-core/tree/master/docs/C--REST-API"'
847
-                          . ' aria-label="'
848
-                          . esc_attr__('View Event Espresso API docs', 'event_espresso')
849
-                          . '">'
850
-                          . esc_html__('API docs', 'event_espresso')
851
-                          . '</a>',
852
-            ];
853
-            return array_merge($meta, $row_meta);
854
-        }
855
-        return (array) $meta;
856
-    }
857
-
858
-     /**************************************************************************************/
859
-     /************************************* DEPRECATED *************************************/
860
-     /**************************************************************************************/
861
-
862
-
863
-    /**
864
-     * This is the action hook for the AHEE__EE_Admin_Page__route_admin_request hook that fires off right before an
865
-     * EE_Admin_Page route is called.
866
-     *
867
-     * @return void
868
-     */
869
-    public function route_admin_request()
870
-    {
871
-    }
872
-
873
-
874
-    /**
875
-     * wp_loaded should fire on the WordPress wp_loaded hook.  This fires on a VERY late priority.
876
-     *
877
-     * @return void
878
-     */
879
-    public function wp_loaded()
880
-    {
881
-    }
882
-
883
-
884
-    /**
885
-     * static method for registering ee admin page.
886
-     * This method is deprecated in favor of the new location in EE_Register_Admin_Page::register.
887
-     *
888
-     * @param       $page_basename
889
-     * @param       $page_path
890
-     * @param array $config
891
-     * @return void
892
-     * @throws EE_Error
893
-     * @see        EE_Register_Admin_Page::register()
894
-     * @since      4.3.0
895
-     * @deprecated 4.3.0    Use EE_Register_Admin_Page::register() instead
896
-     */
897
-    public static function register_ee_admin_page($page_basename, $page_path, $config = [])
898
-    {
899
-        EE_Error::doing_it_wrong(
900
-            __METHOD__,
901
-            sprintf(
902
-                esc_html__(
903
-                    'Usage is deprecated.  Use EE_Register_Admin_Page::register() for registering the %s admin page.',
904
-                    'event_espresso'
905
-                ),
906
-                $page_basename
907
-            ),
908
-            '4.3'
909
-        );
910
-        if (class_exists('EE_Register_Admin_Page')) {
911
-            $config['page_path'] = $page_path;
912
-        }
913
-        EE_Register_Admin_Page::register($page_basename, $config);
914
-    }
915
-
916
-
917
-    /**
918
-     * @param int      $post_ID
919
-     * @param \WP_Post $post
920
-     * @return void
921
-     * @deprecated 4.8.41
922
-     */
923
-    public static function parse_post_content_on_save($post_ID, $post)
924
-    {
925
-        EE_Error::doing_it_wrong(
926
-            __METHOD__,
927
-            esc_html__('Usage is deprecated', 'event_espresso'),
928
-            '4.8.41'
929
-        );
930
-    }
931
-
932
-
933
-    /**
934
-     * @param  $option
935
-     * @param  $old_value
936
-     * @param  $value
937
-     * @return void
938
-     * @deprecated 4.8.41
939
-     */
940
-    public function reset_page_for_posts_on_change($option, $old_value, $value)
941
-    {
942
-        EE_Error::doing_it_wrong(
943
-            __METHOD__,
944
-            esc_html__('Usage is deprecated', 'event_espresso'),
945
-            '4.8.41'
946
-        );
947
-    }
948
-
949
-
950
-    /**
951
-     * @return void
952
-     * @deprecated 4.9.27
953
-     */
954
-    public function get_persistent_admin_notices()
955
-    {
956
-        EE_Error::doing_it_wrong(
957
-            __METHOD__,
958
-            sprintf(
959
-                esc_html__('Usage is deprecated. Use "%1$s" instead.', 'event_espresso'),
960
-                '\EventEspresso\core\services\notifications\PersistentAdminNoticeManager'
961
-            ),
962
-            '4.9.27'
963
-        );
964
-    }
965
-
966
-
967
-    /**
968
-     * @throws InvalidInterfaceException
969
-     * @throws InvalidDataTypeException
970
-     * @throws DomainException
971
-     * @deprecated 4.9.27
972
-     */
973
-    public function dismiss_ee_nag_notice_callback()
974
-    {
975
-        EE_Error::doing_it_wrong(
976
-            __METHOD__,
977
-            sprintf(
978
-                esc_html__('Usage is deprecated. Use "%1$s" instead.', 'event_espresso'),
979
-                '\EventEspresso\core\services\notifications\PersistentAdminNoticeManager'
980
-            ),
981
-            '4.9.27'
982
-        );
983
-        $this->persistent_admin_notice_manager->dismissNotice();
984
-    }
985
-
986
-
987
-    /**
988
-     * @return void
989
-     * @deprecated $VID:$
990
-     */
991
-    public function enqueue_admin_scripts()
992
-    {
993
-    }
994
-
995
-
996
-
997
-    /**
998
-     * @return RequestInterface
999
-     * @deprecated $VID:$
1000
-     */
1001
-    public function get_request()
1002
-    {
1003
-        EE_Error::doing_it_wrong(
1004
-            __METHOD__,
1005
-            sprintf(
1006
-                esc_html__('Usage is deprecated. Use "%1$s" instead.', 'event_espresso'),
1007
-                'EventEspresso\core\services\request\Request'
1008
-            ),
1009
-            '$VID:$'
1010
-        );
1011
-        return $this->request;
1012
-    }
1013
-
1014
-
1015
-    /**
1016
-     * @deprecated $VID:$
1017
-     */
1018
-    public function hookIntoWpPluginsPage()
1019
-    {
1020
-    }
23
+	/**
24
+	 * @var EE_Admin $_instance
25
+	 */
26
+	private static $_instance;
27
+
28
+	/**
29
+	 * @var PersistentAdminNoticeManager $persistent_admin_notice_manager
30
+	 */
31
+	private $persistent_admin_notice_manager;
32
+
33
+	/**
34
+	 * @var LoaderInterface $loader
35
+	 */
36
+	protected $loader;
37
+
38
+	/**
39
+	 * @var RequestInterface
40
+	 */
41
+	protected $request;
42
+
43
+
44
+	/**
45
+	 * @singleton method used to instantiate class object
46
+	 * @param LoaderInterface  $loader
47
+	 * @param RequestInterface $request
48
+	 * @return EE_Admin
49
+	 * @throws EE_Error
50
+	 */
51
+	public static function instance(LoaderInterface $loader = null, RequestInterface $request = null)
52
+	{
53
+		// check if class object is instantiated
54
+		if (! EE_Admin::$_instance instanceof EE_Admin) {
55
+			EE_Admin::$_instance = new EE_Admin($loader, $request);
56
+		}
57
+		return EE_Admin::$_instance;
58
+	}
59
+
60
+
61
+	/**
62
+	 * @return EE_Admin
63
+	 * @throws EE_Error
64
+	 */
65
+	public static function reset()
66
+	{
67
+		EE_Admin::$_instance = null;
68
+		$loader = LoaderFactory::getLoader();
69
+		$request = $loader->getShared('EventEspresso\core\services\request\Request');
70
+		return EE_Admin::instance($loader, $request);
71
+	}
72
+
73
+
74
+	/**
75
+	 * @param LoaderInterface  $loader
76
+	 * @param RequestInterface $request
77
+	 * @throws EE_Error
78
+	 * @throws InvalidDataTypeException
79
+	 * @throws InvalidInterfaceException
80
+	 * @throws InvalidArgumentException
81
+	 */
82
+	protected function __construct(LoaderInterface $loader, RequestInterface $request)
83
+	{
84
+		$this->loader = $loader;
85
+		$this->request = $request;
86
+		// define global EE_Admin constants
87
+		$this->_define_all_constants();
88
+		// set autoloaders for our admin page classes based on included path information
89
+		EEH_Autoloader::register_autoloaders_for_each_file_in_folder(EE_ADMIN);
90
+		// reset Environment config (we only do this on admin page loads);
91
+		EE_Registry::instance()->CFG->environment->recheck_values();
92
+		// load EE_Request_Handler early
93
+		add_action('AHEE__EE_System__initialize_last', [$this, 'init']);
94
+		add_action('admin_init', [$this, 'admin_init'], 100);
95
+		if (! $this->request->isAjax()) {
96
+			// admin hooks
97
+			add_action('admin_notices', [$this, 'display_admin_notices'], 10);
98
+			add_action('network_admin_notices', [$this, 'display_admin_notices'], 10);
99
+			add_filter('pre_update_option', [$this, 'check_for_invalid_datetime_formats'], 100, 2);
100
+			add_filter('plugin_action_links', [$this, 'filter_plugin_actions'], 10, 2);
101
+			add_filter('admin_footer_text', [$this, 'espresso_admin_footer']);
102
+			add_action('display_post_states', [$this, 'displayStateForCriticalPages'], 10, 2);
103
+			add_filter('plugin_row_meta', [$this, 'addLinksToPluginRowMeta'], 10, 2);
104
+		}
105
+		do_action('AHEE__EE_Admin__loaded');
106
+	}
107
+
108
+
109
+	/**
110
+	 * _define_all_constants
111
+	 * define constants that are set globally for all admin pages
112
+	 *
113
+	 * @return void
114
+	 */
115
+	private function _define_all_constants()
116
+	{
117
+		if (! defined('EE_ADMIN_URL')) {
118
+			define('EE_ADMIN_URL', EE_PLUGIN_DIR_URL . 'core/admin/');
119
+			define('EE_ADMIN_PAGES_URL', EE_PLUGIN_DIR_URL . 'admin_pages/');
120
+			define('EE_ADMIN_TEMPLATE', EE_ADMIN . 'templates/');
121
+			define('WP_ADMIN_PATH', ABSPATH . 'wp-admin/');
122
+			define('WP_AJAX_URL', admin_url('admin-ajax.php'));
123
+		}
124
+	}
125
+
126
+
127
+	/**
128
+	 * filter_plugin_actions - adds links to the Plugins page listing
129
+	 *
130
+	 * @param array  $links
131
+	 * @param string $plugin
132
+	 * @return    array
133
+	 */
134
+	public function filter_plugin_actions($links, $plugin)
135
+	{
136
+		// set $main_file in stone
137
+		static $main_file;
138
+		// if $main_file is not set yet
139
+		if (! $main_file) {
140
+			$main_file = EE_PLUGIN_BASENAME;
141
+		}
142
+		if ($plugin === $main_file) {
143
+			// compare current plugin to this one
144
+			if (EE_Maintenance_Mode::instance()->level() === EE_Maintenance_Mode::level_2_complete_maintenance) {
145
+				$maintenance_link = '<a href="admin.php?page=espresso_maintenance_settings"'
146
+									. ' title="Event Espresso is in maintenance mode.  Click this link to learn why.">'
147
+									. esc_html__('Maintenance Mode Active', 'event_espresso')
148
+									. '</a>';
149
+				array_unshift($links, $maintenance_link);
150
+			} else {
151
+				$org_settings_link = '<a href="admin.php?page=espresso_general_settings">'
152
+									 . esc_html__('Settings', 'event_espresso')
153
+									 . '</a>';
154
+				$events_link       = '<a href="admin.php?page=espresso_events">'
155
+									 . esc_html__('Events', 'event_espresso')
156
+									 . '</a>';
157
+				// add before other links
158
+				array_unshift($links, $org_settings_link, $events_link);
159
+			}
160
+		}
161
+		return $links;
162
+	}
163
+
164
+
165
+	/**
166
+	 * hide_admin_pages_except_maintenance_mode
167
+	 *
168
+	 * @param array $admin_page_folder_names
169
+	 * @return array
170
+	 */
171
+	public function hide_admin_pages_except_maintenance_mode($admin_page_folder_names = [])
172
+	{
173
+		return [
174
+			'maintenance' => EE_ADMIN_PAGES . 'maintenance/',
175
+			'about'       => EE_ADMIN_PAGES . 'about/',
176
+			'support'     => EE_ADMIN_PAGES . 'support/',
177
+		];
178
+	}
179
+
180
+
181
+	/**
182
+	 * init- should fire after shortcode, module,  addon, other plugin (default priority), and even
183
+	 * EE_Front_Controller's init phases have run
184
+	 *
185
+	 * @return void
186
+	 * @throws EE_Error
187
+	 * @throws InvalidArgumentException
188
+	 * @throws InvalidDataTypeException
189
+	 * @throws InvalidInterfaceException
190
+	 * @throws ReflectionException
191
+	 * @throws ServiceNotFoundException
192
+	 */
193
+	public function init()
194
+	{
195
+		// only enable most of the EE_Admin IF we're not in full maintenance mode
196
+		if (EE_Maintenance_Mode::instance()->models_can_query()) {
197
+			$this->initModelsReady();
198
+		}
199
+		// run the admin page factory but ONLY if:
200
+		// - it is a regular non ajax admin request
201
+		// - we are doing an ee admin ajax request
202
+		if ($this->request->isAdmin() || $this->request->isAdminAjax() || $this->request->isActivation()) {
203
+			try {
204
+				// this loads the controller for the admin pages which will setup routing etc
205
+				$admin_page_loader = $this->loader->getShared('EE_Admin_Page_Loader', [$this->loader]);
206
+				/** @var EE_Admin_Page_Loader $admin_page_loader */
207
+				$admin_page_loader->init();
208
+			} catch (EE_Error $e) {
209
+				$e->get_error();
210
+			}
211
+		}
212
+		if ($this->request->isAjax()) {
213
+			return;
214
+		}
215
+		add_filter('content_save_pre', [$this, 'its_eSpresso'], 10, 1);
216
+		// make sure our CPTs and custom taxonomy metaboxes get shown for first time users
217
+		add_action('admin_head', [$this, 'enable_hidden_ee_nav_menu_metaboxes'], 10);
218
+		add_action('admin_head', [$this, 'register_custom_nav_menu_boxes'], 10);
219
+		// exclude EE critical pages from all nav menus and wp_list_pages
220
+		add_filter('nav_menu_meta_box_object', [$this, 'remove_pages_from_nav_menu'], 10);
221
+	}
222
+
223
+
224
+	/**
225
+	 * Gets the loader (and if it wasn't previously set, sets it)
226
+	 *
227
+	 * @return LoaderInterface
228
+	 * @throws InvalidArgumentException
229
+	 * @throws InvalidDataTypeException
230
+	 * @throws InvalidInterfaceException
231
+	 */
232
+	protected function getLoader()
233
+	{
234
+		return $this->loader;
235
+	}
236
+
237
+
238
+	/**
239
+	 * Method that's fired on admin requests (including admin ajax) but only when the models are usable
240
+	 * (ie, the site isn't in maintenance mode)
241
+	 *
242
+	 * @return void
243
+	 * @throws EE_Error
244
+	 * @since 4.9.63.p
245
+	 */
246
+	protected function initModelsReady()
247
+	{
248
+		// ok so we want to enable the entire admin
249
+		$this->persistent_admin_notice_manager = $this->loader->getShared(
250
+			'EventEspresso\core\services\notifications\PersistentAdminNoticeManager'
251
+		);
252
+		$this->persistent_admin_notice_manager->setReturnUrl(
253
+			EE_Admin_Page::add_query_args_and_nonce(
254
+				[
255
+					'page'   => $this->request->getRequestParam('page', ''),
256
+					'action' => $this->request->getRequestParam('action', ''),
257
+				],
258
+				EE_ADMIN_URL
259
+			)
260
+		);
261
+		$this->maybeSetDatetimeWarningNotice();
262
+		// at a glance dashboard widget
263
+		add_filter('dashboard_glance_items', [$this, 'dashboard_glance_items'], 10);
264
+		// filter for get_edit_post_link used on comments for custom post types
265
+		add_filter('get_edit_post_link', [$this, 'modify_edit_post_link'], 10, 2);
266
+	}
267
+
268
+
269
+	/**
270
+	 *    get_persistent_admin_notices
271
+	 *
272
+	 * @access    public
273
+	 * @return void
274
+	 * @throws EE_Error
275
+	 * @throws InvalidArgumentException
276
+	 * @throws InvalidDataTypeException
277
+	 * @throws InvalidInterfaceException
278
+	 */
279
+	public function maybeSetDatetimeWarningNotice()
280
+	{
281
+		// add dismissible notice for datetime changes.  Only valid if site does not have a timezone_string set.
282
+		// @todo This needs to stay in core for a bit to catch anyone upgrading from a version without this to a version
283
+		// with this.  But after enough time (indeterminate at this point) we can just remove this notice.
284
+		// this was added with https://events.codebasehq.com/projects/event-espresso/tickets/10626
285
+		if (
286
+			apply_filters('FHEE__EE_Admin__maybeSetDatetimeWarningNotice', true)
287
+			&& ! get_option('timezone_string')
288
+			&& EEM_Event::instance()->count() > 0
289
+		) {
290
+			new PersistentAdminNotice(
291
+				'datetime_fix_notice',
292
+				sprintf(
293
+					esc_html__(
294
+						'%1$sImportant announcement related to your install of Event Espresso%2$s: There are some changes made to your site that could affect how dates display for your events and other related items with dates and times.  Read more about it %3$shere%4$s. If your dates and times are displaying incorrectly (incorrect offset), you can fix it using the tool on %5$sthis page%4$s.',
295
+						'event_espresso'
296
+					),
297
+					'<strong>',
298
+					'</strong>',
299
+					'<a href="https://eventespresso.com/2017/08/important-upcoming-changes-dates-times">',
300
+					'</a>',
301
+					'<a href="' . EE_Admin_Page::add_query_args_and_nonce(
302
+						[
303
+							'page'   => 'espresso_maintenance_settings',
304
+							'action' => 'datetime_tools',
305
+						],
306
+						admin_url('admin.php')
307
+					) . '">'
308
+				),
309
+				false,
310
+				'manage_options',
311
+				'datetime_fix_persistent_notice'
312
+			);
313
+		}
314
+	}
315
+
316
+
317
+	/**
318
+	 * this simply hooks into the nav menu setup of pages metabox and makes sure that we remove EE critical pages from
319
+	 * the list of options. the wp function "wp_nav_menu_item_post_type_meta_box" found in
320
+	 * wp-admin/includes/nav-menu.php looks for the "_default_query" property on the post_type object and it uses that
321
+	 * to override any queries found in the existing query for the given post type.  Note that _default_query is not a
322
+	 * normal property on the post_type object.  It's found ONLY in this particular context.
323
+	 *
324
+	 * @param WP_Post $post_type WP post type object
325
+	 * @return WP_Post
326
+	 * @throws InvalidArgumentException
327
+	 * @throws InvalidDataTypeException
328
+	 * @throws InvalidInterfaceException
329
+	 */
330
+	public function remove_pages_from_nav_menu($post_type)
331
+	{
332
+		// if this isn't the "pages" post type let's get out
333
+		if ($post_type->name !== 'page') {
334
+			return $post_type;
335
+		}
336
+		$critical_pages            = EE_Registry::instance()->CFG->core->get_critical_pages_array();
337
+		$post_type->_default_query = [
338
+			'post__not_in' => $critical_pages,
339
+		];
340
+		return $post_type;
341
+	}
342
+
343
+
344
+	/**
345
+	 * WP by default only shows three metaboxes in "nav-menus.php" for first times users.
346
+	 * We want to make sure our metaboxes get shown as well
347
+	 *
348
+	 * @return void
349
+	 */
350
+	public function enable_hidden_ee_nav_menu_metaboxes()
351
+	{
352
+		global $wp_meta_boxes, $pagenow;
353
+		if (! is_array($wp_meta_boxes) || $pagenow !== 'nav-menus.php') {
354
+			return;
355
+		}
356
+		$user = wp_get_current_user();
357
+		// has this been done yet?
358
+		if (get_user_option('ee_nav_menu_initialized', $user->ID)) {
359
+			return;
360
+		}
361
+
362
+		$hidden_meta_boxes  = get_user_option('metaboxhidden_nav-menus', $user->ID);
363
+		$initial_meta_boxes = apply_filters(
364
+			'FHEE__EE_Admin__enable_hidden_ee_nav_menu_boxes__initial_meta_boxes',
365
+			[
366
+				'nav-menu-theme-locations',
367
+				'add-page',
368
+				'add-custom-links',
369
+				'add-category',
370
+				'add-espresso_events',
371
+				'add-espresso_venues',
372
+				'add-espresso_event_categories',
373
+				'add-espresso_venue_categories',
374
+				'add-post-type-post',
375
+				'add-post-type-page',
376
+			]
377
+		);
378
+
379
+		if (is_array($hidden_meta_boxes)) {
380
+			foreach ($hidden_meta_boxes as $key => $meta_box_id) {
381
+				if (in_array($meta_box_id, $initial_meta_boxes, true)) {
382
+					unset($hidden_meta_boxes[ $key ]);
383
+				}
384
+			}
385
+		}
386
+		update_user_option($user->ID, 'metaboxhidden_nav-menus', $hidden_meta_boxes, true);
387
+		update_user_option($user->ID, 'ee_nav_menu_initialized', 1, true);
388
+	}
389
+
390
+
391
+	/**
392
+	 * This method simply registers custom nav menu boxes for "nav_menus.php route"
393
+	 * Currently EE is using this to make sure there are menu options for our CPT archive page routes.
394
+	 *
395
+	 * @return void
396
+	 * @todo   modify this so its more dynamic and automatic for all ee CPTs and setups and can also be hooked into by
397
+	 *         addons etc.
398
+	 */
399
+	public function register_custom_nav_menu_boxes()
400
+	{
401
+		add_meta_box(
402
+			'add-extra-nav-menu-pages',
403
+			esc_html__('Event Espresso Pages', 'event_espresso'),
404
+			[$this, 'ee_cpt_archive_pages'],
405
+			'nav-menus',
406
+			'side',
407
+			'core'
408
+		);
409
+		add_filter(
410
+			"postbox_classes_nav-menus_add-extra-nav-menu-pages",
411
+			function ($classes) {
412
+				array_push($classes, 'ee-admin-container');
413
+				return $classes;
414
+			}
415
+		);
416
+	}
417
+
418
+
419
+	/**
420
+	 * Use this to edit the post link for our cpts so that the edit link points to the correct page.
421
+	 *
422
+	 * @param string $link the original link generated by wp
423
+	 * @param int    $id   post id
424
+	 * @return string  the (maybe) modified link
425
+	 * @since   4.3.0
426
+	 */
427
+	public function modify_edit_post_link($link, $id)
428
+	{
429
+		if (! $post = get_post($id)) {
430
+			return $link;
431
+		}
432
+		if ($post->post_type === 'espresso_attendees') {
433
+			$query_args = [
434
+				'action' => 'edit_attendee',
435
+				'post'   => $id,
436
+			];
437
+			return EEH_URL::add_query_args_and_nonce(
438
+				$query_args,
439
+				admin_url('admin.php?page=espresso_registrations')
440
+			);
441
+		}
442
+		return $link;
443
+	}
444
+
445
+
446
+	public function ee_cpt_archive_pages()
447
+	{
448
+		global $nav_menu_selected_id;
449
+		$removed_args = [
450
+			'action',
451
+			'customlink-tab',
452
+			'edit-menu-item',
453
+			'menu-item',
454
+			'page-tab',
455
+			'_wpnonce',
456
+		];
457
+		$nav_tab_link = $nav_menu_selected_id
458
+			? esc_url(
459
+				add_query_arg(
460
+					'extra-nav-menu-pages-tab',
461
+					'event-archives',
462
+					remove_query_arg($removed_args)
463
+				)
464
+			)
465
+			: '';
466
+		$select_all_link = esc_url(
467
+			add_query_arg(
468
+				[
469
+					'extra-nav-menu-pages-tab' => 'event-archives',
470
+					'selectall'                => 1,
471
+				],
472
+				remove_query_arg($removed_args)
473
+			)
474
+		);
475
+		$pages = $this->_get_extra_nav_menu_pages_items();
476
+		$args['walker'] = new Walker_Nav_Menu_Checklist(false);
477
+		;
478
+		$nav_menu_pages_items = walk_nav_menu_tree(
479
+			array_map(
480
+				[$this, '_setup_extra_nav_menu_pages_items'],
481
+				$pages
482
+			),
483
+			0,
484
+			(object) $args
485
+		);
486
+		EEH_Template::display_template(
487
+			EE_ADMIN_TEMPLATE . 'cpt_archive_page.template.php',
488
+			[
489
+				'nav_menu_selected_id' => $nav_menu_selected_id,
490
+				'nav_menu_pages_items' => $nav_menu_pages_items,
491
+				'nav_tab_link'         => $nav_tab_link,
492
+				'select_all_link'      => $select_all_link,
493
+			]
494
+		);
495
+	}
496
+
497
+
498
+	/**
499
+	 * Returns an array of event archive nav items.
500
+	 *
501
+	 * @return array
502
+	 * @todo  for now this method is just in place so when it gets abstracted further we can substitute in whatever
503
+	 *        method we use for getting the extra nav menu items
504
+	 */
505
+	private function _get_extra_nav_menu_pages_items()
506
+	{
507
+		$menuitems[] = [
508
+			'title'       => esc_html__('Event List', 'event_espresso'),
509
+			'url'         => get_post_type_archive_link('espresso_events'),
510
+			'description' => esc_html__('Archive page for all events.', 'event_espresso'),
511
+		];
512
+		return apply_filters('FHEE__EE_Admin__get_extra_nav_menu_pages_items', $menuitems);
513
+	}
514
+
515
+
516
+	/**
517
+	 * Setup nav menu walker item for usage in the event archive nav menu metabox.  It receives a menu_item array with
518
+	 * the properties and converts it to the menu item object.
519
+	 *
520
+	 * @param $menu_item_values
521
+	 * @return stdClass
522
+	 * @see wp_setup_nav_menu_item() in wp-includes/nav-menu.php
523
+	 */
524
+	private function _setup_extra_nav_menu_pages_items($menu_item_values)
525
+	{
526
+		$menu_item = new stdClass();
527
+		$keys      = [
528
+			'ID'               => 0,
529
+			'db_id'            => 0,
530
+			'menu_item_parent' => 0,
531
+			'object_id'        => -1,
532
+			'post_parent'      => 0,
533
+			'type'             => 'custom',
534
+			'object'           => '',
535
+			'type_label'       => esc_html__('Extra Nav Menu Item', 'event_espresso'),
536
+			'title'            => '',
537
+			'url'              => '',
538
+			'target'           => '',
539
+			'attr_title'       => '',
540
+			'description'      => '',
541
+			'classes'          => [],
542
+			'xfn'              => '',
543
+		];
544
+		foreach ($keys as $key => $value) {
545
+			$menu_item->{$key} = $menu_item_values[ $key ] ?? $value;
546
+		}
547
+		return $menu_item;
548
+	}
549
+
550
+
551
+	/**
552
+	 * admin_init
553
+	 *
554
+	 * @return void
555
+	 * @throws InvalidArgumentException
556
+	 * @throws InvalidDataTypeException
557
+	 * @throws InvalidInterfaceException
558
+	 */
559
+	public function admin_init()
560
+	{
561
+		/**
562
+		 * our cpt models must be instantiated on WordPress post processing routes (wp-admin/post.php),
563
+		 * so any hooking into core WP routes is taken care of.  So in this next few lines of code:
564
+		 * - check if doing post processing.
565
+		 * - check if doing post processing of one of EE CPTs
566
+		 * - instantiate the corresponding EE CPT model for the post_type being processed.
567
+		 */
568
+		$action    = $this->request->getRequestParam('action');
569
+		$post_type = $this->request->getRequestParam('post_type');
570
+		if ($post_type && $action === 'editpost') {
571
+			/** @var CustomPostTypeDefinitions $custom_post_types */
572
+			$custom_post_types = $this->loader->getShared(CustomPostTypeDefinitions::class);
573
+			$custom_post_types->getCustomPostTypeModels($post_type);
574
+		}
575
+
576
+
577
+		if (! $this->request->isAjax()) {
578
+			/**
579
+			 * This code excludes EE critical pages anywhere `wp_dropdown_pages` is used to create a dropdown for selecting
580
+			 * critical pages.  The only place critical pages need included in a generated dropdown is on the "Critical
581
+			 * Pages" tab in the EE General Settings Admin page.
582
+			 * This is for user-proofing.
583
+			 */
584
+			add_filter('wp_dropdown_pages', [$this, 'modify_dropdown_pages']);
585
+			if (EE_Maintenance_Mode::instance()->models_can_query()) {
586
+				$this->adminInitModelsReady();
587
+			}
588
+		}
589
+	}
590
+
591
+
592
+	/**
593
+	 * Runs on admin_init but only if models are usable (ie, we're not in maintenance mode)
594
+	 */
595
+	protected function adminInitModelsReady()
596
+	{
597
+		if (function_exists('wp_add_privacy_policy_content')) {
598
+			$this->loader->getShared('EventEspresso\core\services\privacy\policy\PrivacyPolicyManager');
599
+		}
600
+	}
601
+
602
+
603
+	/**
604
+	 * Callback for wp_dropdown_pages hook to remove ee critical pages from the dropdown selection.
605
+	 *
606
+	 * @param string $output Current output.
607
+	 * @return string
608
+	 * @throws InvalidArgumentException
609
+	 * @throws InvalidDataTypeException
610
+	 * @throws InvalidInterfaceException
611
+	 */
612
+	public function modify_dropdown_pages($output)
613
+	{
614
+		// get critical pages
615
+		$critical_pages = EE_Registry::instance()->CFG->core->get_critical_pages_array();
616
+
617
+		// split current output by line break for easier parsing.
618
+		$split_output = explode("\n", $output);
619
+
620
+		// loop through to remove any critical pages from the array.
621
+		foreach ($critical_pages as $page_id) {
622
+			$needle = 'value="' . $page_id . '"';
623
+			foreach ($split_output as $key => $haystack) {
624
+				if (strpos($haystack, $needle) !== false) {
625
+					unset($split_output[ $key ]);
626
+				}
627
+			}
628
+		}
629
+		// replace output with the new contents
630
+		return implode("\n", $split_output);
631
+	}
632
+
633
+
634
+	/**
635
+	 * display_admin_notices
636
+	 *
637
+	 * @return void
638
+	 */
639
+	public function display_admin_notices()
640
+	{
641
+		echo EE_Error::get_notices(); // already escaped
642
+	}
643
+
644
+
645
+	/**
646
+	 * @param array $elements
647
+	 * @return array
648
+	 * @throws EE_Error
649
+	 * @throws InvalidArgumentException
650
+	 * @throws InvalidDataTypeException
651
+	 * @throws InvalidInterfaceException
652
+	 */
653
+	public function dashboard_glance_items($elements)
654
+	{
655
+		$elements                        = is_array($elements) ? $elements : [$elements];
656
+		$events                          = EEM_Event::instance()->count();
657
+		$items['events']['url']          = EE_Admin_Page::add_query_args_and_nonce(
658
+			['page' => 'espresso_events'],
659
+			admin_url('admin.php')
660
+		);
661
+		$items['events']['text']         = sprintf(
662
+			esc_html(
663
+				_n('%s Event', '%s Events', $events, 'event_espresso')
664
+			),
665
+			number_format_i18n($events)
666
+		);
667
+		$items['events']['title']        = esc_html__('Click to view all Events', 'event_espresso');
668
+		$registrations                   = EEM_Registration::instance()->count(
669
+			[
670
+				[
671
+					'STS_ID' => ['!=', EEM_Registration::status_id_incomplete],
672
+				],
673
+			]
674
+		);
675
+		$items['registrations']['url']   = EE_Admin_Page::add_query_args_and_nonce(
676
+			['page' => 'espresso_registrations'],
677
+			admin_url('admin.php')
678
+		);
679
+		$items['registrations']['text']  = sprintf(
680
+			esc_html(
681
+				_n('%s Registration', '%s Registrations', $registrations, 'event_espresso')
682
+			),
683
+			number_format_i18n($registrations)
684
+		);
685
+		$items['registrations']['title'] = esc_html__('Click to view all registrations', 'event_espresso');
686
+
687
+		$items = (array) apply_filters('FHEE__EE_Admin__dashboard_glance_items__items', $items);
688
+
689
+		foreach ($items as $type => $item_properties) {
690
+			$elements[] = sprintf(
691
+				'<a class="ee-dashboard-link-' . $type . '" href="%s" title="%s">%s</a>',
692
+				$item_properties['url'],
693
+				$item_properties['title'],
694
+				$item_properties['text']
695
+			);
696
+		}
697
+		return $elements;
698
+	}
699
+
700
+
701
+	/**
702
+	 * check_for_invalid_datetime_formats
703
+	 * if an admin changes their date or time format settings on the WP General Settings admin page, verify that
704
+	 * their selected format can be parsed by PHP
705
+	 *
706
+	 * @param    $value
707
+	 * @param    $option
708
+	 * @return    string
709
+	 */
710
+	public function check_for_invalid_datetime_formats($value, $option)
711
+	{
712
+		// check for date_format or time_format
713
+		switch ($option) {
714
+			case 'date_format':
715
+				$date_time_format = $value . ' ' . get_option('time_format');
716
+				break;
717
+			case 'time_format':
718
+				$date_time_format = get_option('date_format') . ' ' . $value;
719
+				break;
720
+			default:
721
+				$date_time_format = false;
722
+		}
723
+		// do we have a date_time format to check ?
724
+		if ($date_time_format) {
725
+			$error_msg = EEH_DTT_Helper::validate_format_string($date_time_format);
726
+
727
+			if (is_array($error_msg)) {
728
+				$msg = '<p>'
729
+					   . sprintf(
730
+						   esc_html__(
731
+							   'The following date time "%s" ( %s ) is difficult to be properly parsed by PHP for the following reasons:',
732
+							   'event_espresso'
733
+						   ),
734
+						   date($date_time_format),
735
+						   $date_time_format
736
+					   )
737
+					   . '</p><p><ul>';
738
+
739
+
740
+				foreach ($error_msg as $error) {
741
+					$msg .= '<li>' . $error . '</li>';
742
+				}
743
+
744
+				$msg .= '</ul></p><p>'
745
+						. sprintf(
746
+							esc_html__(
747
+								'%sPlease note that your date and time formats have been reset to "F j, Y" and "g:i a" respectively.%s',
748
+								'event_espresso'
749
+							),
750
+							'<span style="color:#D54E21;">',
751
+							'</span>'
752
+						)
753
+						. '</p>';
754
+
755
+				// trigger WP settings error
756
+				add_settings_error(
757
+					'date_format',
758
+					'date_format',
759
+					$msg
760
+				);
761
+
762
+				// set format to something valid
763
+				switch ($option) {
764
+					case 'date_format':
765
+						$value = 'F j, Y';
766
+						break;
767
+					case 'time_format':
768
+						$value = 'g:i a';
769
+						break;
770
+				}
771
+			}
772
+		}
773
+		return $value;
774
+	}
775
+
776
+
777
+	/**
778
+	 * its_eSpresso - converts the less commonly used spelling of "Expresso" to "Espresso"
779
+	 *
780
+	 * @param $content
781
+	 * @return    string
782
+	 */
783
+	public function its_eSpresso($content)
784
+	{
785
+		return str_replace('[EXPRESSO_', '[ESPRESSO_', $content);
786
+	}
787
+
788
+
789
+	/**
790
+	 * espresso_admin_footer
791
+	 *
792
+	 * @return    string
793
+	 */
794
+	public function espresso_admin_footer()
795
+	{
796
+		return EEH_Template::powered_by_event_espresso('aln-cntr', '', ['utm_content' => 'admin_footer']);
797
+	}
798
+
799
+
800
+	/**
801
+	 * Hooks into the "post states" filter in a wp post type list table.
802
+	 *
803
+	 * @param array   $post_states
804
+	 * @param WP_Post $post
805
+	 * @return array
806
+	 * @throws InvalidArgumentException
807
+	 * @throws InvalidDataTypeException
808
+	 * @throws InvalidInterfaceException
809
+	 */
810
+	public function displayStateForCriticalPages($post_states, $post)
811
+	{
812
+		$post_states = (array) $post_states;
813
+		if (! $post instanceof WP_Post || $post->post_type !== 'page') {
814
+			return $post_states;
815
+		}
816
+		/** @var EE_Core_Config $config */
817
+		$config = $this->loader->getShared('EE_Config')->core;
818
+		if (in_array($post->ID, $config->get_critical_pages_array(), true)) {
819
+			$post_states[] = sprintf(
820
+			/* Translators: Using company name - Event Espresso Critical Page */
821
+				esc_html__('%s Critical Page', 'event_espresso'),
822
+				'Event Espresso'
823
+			);
824
+		}
825
+		return $post_states;
826
+	}
827
+
828
+
829
+	/**
830
+	 * Show documentation links on the plugins page
831
+	 *
832
+	 * @param mixed $meta Plugin Row Meta
833
+	 * @param mixed $file Plugin Base file
834
+	 * @return array
835
+	 */
836
+	public function addLinksToPluginRowMeta($meta, $file)
837
+	{
838
+		if (EE_PLUGIN_BASENAME === $file) {
839
+			$row_meta = [
840
+				'docs' => '<a href="https://eventespresso.com/support/documentation/versioned-docs/?doc_ver=ee4"'
841
+						  . ' aria-label="'
842
+						  . esc_attr__('View Event Espresso documentation', 'event_espresso')
843
+						  . '">'
844
+						  . esc_html__('Docs', 'event_espresso')
845
+						  . '</a>',
846
+				'api'  => '<a href="https://github.com/eventespresso/event-espresso-core/tree/master/docs/C--REST-API"'
847
+						  . ' aria-label="'
848
+						  . esc_attr__('View Event Espresso API docs', 'event_espresso')
849
+						  . '">'
850
+						  . esc_html__('API docs', 'event_espresso')
851
+						  . '</a>',
852
+			];
853
+			return array_merge($meta, $row_meta);
854
+		}
855
+		return (array) $meta;
856
+	}
857
+
858
+	 /**************************************************************************************/
859
+	 /************************************* DEPRECATED *************************************/
860
+	 /**************************************************************************************/
861
+
862
+
863
+	/**
864
+	 * This is the action hook for the AHEE__EE_Admin_Page__route_admin_request hook that fires off right before an
865
+	 * EE_Admin_Page route is called.
866
+	 *
867
+	 * @return void
868
+	 */
869
+	public function route_admin_request()
870
+	{
871
+	}
872
+
873
+
874
+	/**
875
+	 * wp_loaded should fire on the WordPress wp_loaded hook.  This fires on a VERY late priority.
876
+	 *
877
+	 * @return void
878
+	 */
879
+	public function wp_loaded()
880
+	{
881
+	}
882
+
883
+
884
+	/**
885
+	 * static method for registering ee admin page.
886
+	 * This method is deprecated in favor of the new location in EE_Register_Admin_Page::register.
887
+	 *
888
+	 * @param       $page_basename
889
+	 * @param       $page_path
890
+	 * @param array $config
891
+	 * @return void
892
+	 * @throws EE_Error
893
+	 * @see        EE_Register_Admin_Page::register()
894
+	 * @since      4.3.0
895
+	 * @deprecated 4.3.0    Use EE_Register_Admin_Page::register() instead
896
+	 */
897
+	public static function register_ee_admin_page($page_basename, $page_path, $config = [])
898
+	{
899
+		EE_Error::doing_it_wrong(
900
+			__METHOD__,
901
+			sprintf(
902
+				esc_html__(
903
+					'Usage is deprecated.  Use EE_Register_Admin_Page::register() for registering the %s admin page.',
904
+					'event_espresso'
905
+				),
906
+				$page_basename
907
+			),
908
+			'4.3'
909
+		);
910
+		if (class_exists('EE_Register_Admin_Page')) {
911
+			$config['page_path'] = $page_path;
912
+		}
913
+		EE_Register_Admin_Page::register($page_basename, $config);
914
+	}
915
+
916
+
917
+	/**
918
+	 * @param int      $post_ID
919
+	 * @param \WP_Post $post
920
+	 * @return void
921
+	 * @deprecated 4.8.41
922
+	 */
923
+	public static function parse_post_content_on_save($post_ID, $post)
924
+	{
925
+		EE_Error::doing_it_wrong(
926
+			__METHOD__,
927
+			esc_html__('Usage is deprecated', 'event_espresso'),
928
+			'4.8.41'
929
+		);
930
+	}
931
+
932
+
933
+	/**
934
+	 * @param  $option
935
+	 * @param  $old_value
936
+	 * @param  $value
937
+	 * @return void
938
+	 * @deprecated 4.8.41
939
+	 */
940
+	public function reset_page_for_posts_on_change($option, $old_value, $value)
941
+	{
942
+		EE_Error::doing_it_wrong(
943
+			__METHOD__,
944
+			esc_html__('Usage is deprecated', 'event_espresso'),
945
+			'4.8.41'
946
+		);
947
+	}
948
+
949
+
950
+	/**
951
+	 * @return void
952
+	 * @deprecated 4.9.27
953
+	 */
954
+	public function get_persistent_admin_notices()
955
+	{
956
+		EE_Error::doing_it_wrong(
957
+			__METHOD__,
958
+			sprintf(
959
+				esc_html__('Usage is deprecated. Use "%1$s" instead.', 'event_espresso'),
960
+				'\EventEspresso\core\services\notifications\PersistentAdminNoticeManager'
961
+			),
962
+			'4.9.27'
963
+		);
964
+	}
965
+
966
+
967
+	/**
968
+	 * @throws InvalidInterfaceException
969
+	 * @throws InvalidDataTypeException
970
+	 * @throws DomainException
971
+	 * @deprecated 4.9.27
972
+	 */
973
+	public function dismiss_ee_nag_notice_callback()
974
+	{
975
+		EE_Error::doing_it_wrong(
976
+			__METHOD__,
977
+			sprintf(
978
+				esc_html__('Usage is deprecated. Use "%1$s" instead.', 'event_espresso'),
979
+				'\EventEspresso\core\services\notifications\PersistentAdminNoticeManager'
980
+			),
981
+			'4.9.27'
982
+		);
983
+		$this->persistent_admin_notice_manager->dismissNotice();
984
+	}
985
+
986
+
987
+	/**
988
+	 * @return void
989
+	 * @deprecated $VID:$
990
+	 */
991
+	public function enqueue_admin_scripts()
992
+	{
993
+	}
994
+
995
+
996
+
997
+	/**
998
+	 * @return RequestInterface
999
+	 * @deprecated $VID:$
1000
+	 */
1001
+	public function get_request()
1002
+	{
1003
+		EE_Error::doing_it_wrong(
1004
+			__METHOD__,
1005
+			sprintf(
1006
+				esc_html__('Usage is deprecated. Use "%1$s" instead.', 'event_espresso'),
1007
+				'EventEspresso\core\services\request\Request'
1008
+			),
1009
+			'$VID:$'
1010
+		);
1011
+		return $this->request;
1012
+	}
1013
+
1014
+
1015
+	/**
1016
+	 * @deprecated $VID:$
1017
+	 */
1018
+	public function hookIntoWpPluginsPage()
1019
+	{
1020
+	}
1021 1021
 }
Please login to merge, or discard this patch.
core/domain/entities/routing/handlers/shared/RegularRequests.php 1 patch
Indentation   +136 added lines, -136 removed lines patch added patch discarded remove patch
@@ -28,148 +28,148 @@
 block discarded – undo
28 28
  */
29 29
 class RegularRequests extends PrimaryRoute
30 30
 {
31
-    /**
32
-     * called just before matchesCurrentRequest()
33
-     * and allows Route to perform any setup required such as calling setSpecification()
34
-     *
35
-     * @since $VID:$
36
-     */
37
-    public function initialize()
38
-    {
39
-        $basic_nodes = [
40
-            'EventEspresso\core\domain\entities\routing\data_nodes\core\Api',
41
-            'EventEspresso\core\domain\entities\routing\data_nodes\core\Capabilities',
42
-            'EventEspresso\core\domain\entities\routing\data_nodes\core\Locale',
43
-            'EventEspresso\core\domain\entities\routing\data_nodes\core\SiteUrls',
44
-        ];
45
-        foreach ($basic_nodes as $basic_node) {
46
-            $this->dependency_map->registerDependencies(
47
-                $basic_node,
48
-                ['EventEspresso\core\services\json\JsonDataNodeValidator' => EE_Dependency_Map::load_from_cache]
49
-            );
50
-        }
51
-        $this->dependency_map->registerDependencies(
52
-            'EventEspresso\core\domain\entities\routing\data_nodes\core\SitePermissions',
53
-            [
54
-                'EventEspresso\core\domain\services\capabilities\FeatureFlags' => EE_Dependency_Map::load_from_cache,
55
-                'EventEspresso\core\services\json\JsonDataNodeValidator'       => EE_Dependency_Map::load_from_cache,
56
-            ]
57
-        );
58
-        $this->dependency_map->registerDependencies(
59
-            'EventEspresso\core\domain\entities\routing\data_nodes\core\GeneralSettings',
60
-            [
61
-                'EventEspresso\core\services\json\JsonDataNodeValidator'                => EE_Dependency_Map::load_from_cache,
62
-                'EventEspresso\core\services\converters\date_time_formats\PhpToUnicode' => EE_Dependency_Map::load_from_cache,
63
-            ]
64
-        );
65
-        $this->dependency_map->registerDependencies(
66
-            'EventEspresso\core\domain\entities\routing\data_nodes\EventEspressoData',
67
-            [
68
-                'EventEspresso\core\domain\entities\routing\data_nodes\core\Api'    => EE_Dependency_Map::load_from_cache,
69
-                'EventEspresso\core\domain\entities\routing\data_nodes\core\Config' => EE_Dependency_Map::load_from_cache,
70
-                'EventEspresso\core\services\assets\JedLocaleData'                  => EE_Dependency_Map::load_from_cache,
71
-                'EventEspresso\core\services\json\JsonDataNodeValidator'            => EE_Dependency_Map::load_from_cache,
72
-            ]
73
-        );
74
-        $this->dependency_map->registerDependencies(
75
-            'EventEspresso\core\domain\entities\routing\data_nodes\core\Config',
76
-            [
77
-                'EventEspresso\core\domain\entities\routing\data_nodes\core\CurrentUser'        => EE_Dependency_Map::load_from_cache,
78
-                'EventEspresso\core\domain\entities\routing\data_nodes\core\EspressoCoreDomain' => EE_Dependency_Map::load_from_cache,
79
-                'EventEspresso\core\domain\entities\routing\data_nodes\core\GeneralSettings'    => EE_Dependency_Map::load_from_cache,
80
-                'EventEspresso\core\domain\entities\routing\data_nodes\core\Locale'             => EE_Dependency_Map::load_from_cache,
81
-                'EventEspresso\core\domain\entities\routing\data_nodes\core\SiteCurrency'       => EE_Dependency_Map::load_from_cache,
82
-                'EventEspresso\core\domain\entities\routing\data_nodes\core\SitePermissions'    => EE_Dependency_Map::load_from_cache,
83
-                'EventEspresso\core\domain\entities\routing\data_nodes\core\SiteUrls'           => EE_Dependency_Map::load_from_cache,
84
-                'EventEspresso\core\services\json\JsonDataNodeValidator'                        => EE_Dependency_Map::load_from_cache,
85
-            ]
86
-        );
87
-        $this->dependency_map->registerDependencies(
88
-            'EventEspresso\core\domain\entities\routing\data_nodes\core\CurrentUser',
89
-            [
90
-                'EventEspresso\core\domain\entities\routing\data_nodes\core\Capabilities' => EE_Dependency_Map::load_from_cache,
91
-                'EventEspresso\core\services\json\JsonDataNodeValidator'                  => EE_Dependency_Map::load_from_cache,
92
-            ]
93
-        );
94
-        $this->dependency_map->registerDependencies(
95
-            'EventEspresso\core\domain\entities\routing\data_nodes\core\EspressoCoreDomain',
96
-            [
97
-                'EventEspresso\core\domain\Domain'                       => EE_Dependency_Map::load_from_cache,
98
-                'EventEspresso\core\services\json\JsonDataNodeValidator' => EE_Dependency_Map::load_from_cache,
99
-            ]
100
-        );
101
-        $this->dependency_map->registerDependencies(
102
-            'EventEspresso\core\domain\entities\routing\data_nodes\core\SiteCurrency',
103
-            [
104
-                'EE_Currency_Config'                                     => EE_Dependency_Map::load_from_cache,
105
-                'EventEspresso\core\services\json\JsonDataNodeValidator' => EE_Dependency_Map::load_from_cache,
106
-            ]
107
-        );
108
-        $this->setDataNode(
109
-            $this->loader->getShared('EventEspresso\core\domain\entities\routing\data_nodes\EventEspressoData')
110
-        );
111
-    }
31
+	/**
32
+	 * called just before matchesCurrentRequest()
33
+	 * and allows Route to perform any setup required such as calling setSpecification()
34
+	 *
35
+	 * @since $VID:$
36
+	 */
37
+	public function initialize()
38
+	{
39
+		$basic_nodes = [
40
+			'EventEspresso\core\domain\entities\routing\data_nodes\core\Api',
41
+			'EventEspresso\core\domain\entities\routing\data_nodes\core\Capabilities',
42
+			'EventEspresso\core\domain\entities\routing\data_nodes\core\Locale',
43
+			'EventEspresso\core\domain\entities\routing\data_nodes\core\SiteUrls',
44
+		];
45
+		foreach ($basic_nodes as $basic_node) {
46
+			$this->dependency_map->registerDependencies(
47
+				$basic_node,
48
+				['EventEspresso\core\services\json\JsonDataNodeValidator' => EE_Dependency_Map::load_from_cache]
49
+			);
50
+		}
51
+		$this->dependency_map->registerDependencies(
52
+			'EventEspresso\core\domain\entities\routing\data_nodes\core\SitePermissions',
53
+			[
54
+				'EventEspresso\core\domain\services\capabilities\FeatureFlags' => EE_Dependency_Map::load_from_cache,
55
+				'EventEspresso\core\services\json\JsonDataNodeValidator'       => EE_Dependency_Map::load_from_cache,
56
+			]
57
+		);
58
+		$this->dependency_map->registerDependencies(
59
+			'EventEspresso\core\domain\entities\routing\data_nodes\core\GeneralSettings',
60
+			[
61
+				'EventEspresso\core\services\json\JsonDataNodeValidator'                => EE_Dependency_Map::load_from_cache,
62
+				'EventEspresso\core\services\converters\date_time_formats\PhpToUnicode' => EE_Dependency_Map::load_from_cache,
63
+			]
64
+		);
65
+		$this->dependency_map->registerDependencies(
66
+			'EventEspresso\core\domain\entities\routing\data_nodes\EventEspressoData',
67
+			[
68
+				'EventEspresso\core\domain\entities\routing\data_nodes\core\Api'    => EE_Dependency_Map::load_from_cache,
69
+				'EventEspresso\core\domain\entities\routing\data_nodes\core\Config' => EE_Dependency_Map::load_from_cache,
70
+				'EventEspresso\core\services\assets\JedLocaleData'                  => EE_Dependency_Map::load_from_cache,
71
+				'EventEspresso\core\services\json\JsonDataNodeValidator'            => EE_Dependency_Map::load_from_cache,
72
+			]
73
+		);
74
+		$this->dependency_map->registerDependencies(
75
+			'EventEspresso\core\domain\entities\routing\data_nodes\core\Config',
76
+			[
77
+				'EventEspresso\core\domain\entities\routing\data_nodes\core\CurrentUser'        => EE_Dependency_Map::load_from_cache,
78
+				'EventEspresso\core\domain\entities\routing\data_nodes\core\EspressoCoreDomain' => EE_Dependency_Map::load_from_cache,
79
+				'EventEspresso\core\domain\entities\routing\data_nodes\core\GeneralSettings'    => EE_Dependency_Map::load_from_cache,
80
+				'EventEspresso\core\domain\entities\routing\data_nodes\core\Locale'             => EE_Dependency_Map::load_from_cache,
81
+				'EventEspresso\core\domain\entities\routing\data_nodes\core\SiteCurrency'       => EE_Dependency_Map::load_from_cache,
82
+				'EventEspresso\core\domain\entities\routing\data_nodes\core\SitePermissions'    => EE_Dependency_Map::load_from_cache,
83
+				'EventEspresso\core\domain\entities\routing\data_nodes\core\SiteUrls'           => EE_Dependency_Map::load_from_cache,
84
+				'EventEspresso\core\services\json\JsonDataNodeValidator'                        => EE_Dependency_Map::load_from_cache,
85
+			]
86
+		);
87
+		$this->dependency_map->registerDependencies(
88
+			'EventEspresso\core\domain\entities\routing\data_nodes\core\CurrentUser',
89
+			[
90
+				'EventEspresso\core\domain\entities\routing\data_nodes\core\Capabilities' => EE_Dependency_Map::load_from_cache,
91
+				'EventEspresso\core\services\json\JsonDataNodeValidator'                  => EE_Dependency_Map::load_from_cache,
92
+			]
93
+		);
94
+		$this->dependency_map->registerDependencies(
95
+			'EventEspresso\core\domain\entities\routing\data_nodes\core\EspressoCoreDomain',
96
+			[
97
+				'EventEspresso\core\domain\Domain'                       => EE_Dependency_Map::load_from_cache,
98
+				'EventEspresso\core\services\json\JsonDataNodeValidator' => EE_Dependency_Map::load_from_cache,
99
+			]
100
+		);
101
+		$this->dependency_map->registerDependencies(
102
+			'EventEspresso\core\domain\entities\routing\data_nodes\core\SiteCurrency',
103
+			[
104
+				'EE_Currency_Config'                                     => EE_Dependency_Map::load_from_cache,
105
+				'EventEspresso\core\services\json\JsonDataNodeValidator' => EE_Dependency_Map::load_from_cache,
106
+			]
107
+		);
108
+		$this->setDataNode(
109
+			$this->loader->getShared('EventEspresso\core\domain\entities\routing\data_nodes\EventEspressoData')
110
+		);
111
+	}
112 112
 
113 113
 
114
-    /**
115
-     * returns true if the current request matches this route
116
-     *
117
-     * @return bool
118
-     * @since   $VID:$
119
-     */
120
-    public function matchesCurrentRequest(): bool
121
-    {
122
-        return ! $this->request->isActivation() || $this->request->isUnitTesting();
123
-    }
114
+	/**
115
+	 * returns true if the current request matches this route
116
+	 *
117
+	 * @return bool
118
+	 * @since   $VID:$
119
+	 */
120
+	public function matchesCurrentRequest(): bool
121
+	{
122
+		return ! $this->request->isActivation() || $this->request->isUnitTesting();
123
+	}
124 124
 
125 125
 
126
-    /**
127
-     * @since $VID:$
128
-     */
129
-    protected function registerDependencies()
130
-    {
131
-        $public = ['EE_Maintenance_Mode' => EE_Dependency_Map::load_from_cache] + Route::getDefaultDependencies();
126
+	/**
127
+	 * @since $VID:$
128
+	 */
129
+	protected function registerDependencies()
130
+	{
131
+		$public = ['EE_Maintenance_Mode' => EE_Dependency_Map::load_from_cache] + Route::getDefaultDependencies();
132 132
 
133
-        $default_with_barista  = [BaristaFactory::class => EE_Dependency_Map::load_from_cache] +
134
-                                 Route::getDefaultDependencies();
135
-        $default_with_manifest = [AssetManifestFactory::class => EE_Dependency_Map::load_from_cache] +
136
-                                 Route::getDefaultDependencies();
133
+		$default_with_barista  = [BaristaFactory::class => EE_Dependency_Map::load_from_cache] +
134
+								 Route::getDefaultDependencies();
135
+		$default_with_manifest = [AssetManifestFactory::class => EE_Dependency_Map::load_from_cache] +
136
+								 Route::getDefaultDependencies();
137 137
 
138
-        $default_routes = [
139
-            // default dependencies
140
-            ShortcodeRequests::class    => Route::getDefaultDependencies(),
141
-            RestApiRequests::class      => Route::getDefaultDependencies(),
142
-            SessionRequests::class      => Route::getDefaultDependencies(),
143
-            WordPressHeartbeat::class   => Route::getDefaultDependencies(),
144
-            AssetRequests::class        => $default_with_barista,
145
-            GQLRequests::class          => $default_with_manifest,
146
-            // admin dependencies
147
-            AdminRoute::class           => AdminRoute::getDefaultDependencies(),
148
-            EspressoEventsAdmin::class  => AdminRoute::getDefaultDependencies(),
149
-            EspressoEventEditor::class  => AdminRoute::getDefaultDependencies(),
150
-            EspressoLegacyAdmin::class  => AdminRoute::getDefaultDependencies(),
151
-            GutenbergEditor::class      => AdminRoute::getDefaultDependencies(),
152
-            NonEspressoAdminAjax::class => AdminRoute::getDefaultDependencies(),
153
-            WordPressPluginsPage::class => AdminRoute::getDefaultDependencies(),
154
-            // public dependencies
155
-            PersonalDataRequests::class => $public,
156
-            FrontendRequests::class     => $public,
157
-        ];
158
-        foreach ($default_routes as $route => $dependencies) {
159
-            $this->dependency_map->registerDependencies($route, $dependencies);
160
-        }
161
-    }
138
+		$default_routes = [
139
+			// default dependencies
140
+			ShortcodeRequests::class    => Route::getDefaultDependencies(),
141
+			RestApiRequests::class      => Route::getDefaultDependencies(),
142
+			SessionRequests::class      => Route::getDefaultDependencies(),
143
+			WordPressHeartbeat::class   => Route::getDefaultDependencies(),
144
+			AssetRequests::class        => $default_with_barista,
145
+			GQLRequests::class          => $default_with_manifest,
146
+			// admin dependencies
147
+			AdminRoute::class           => AdminRoute::getDefaultDependencies(),
148
+			EspressoEventsAdmin::class  => AdminRoute::getDefaultDependencies(),
149
+			EspressoEventEditor::class  => AdminRoute::getDefaultDependencies(),
150
+			EspressoLegacyAdmin::class  => AdminRoute::getDefaultDependencies(),
151
+			GutenbergEditor::class      => AdminRoute::getDefaultDependencies(),
152
+			NonEspressoAdminAjax::class => AdminRoute::getDefaultDependencies(),
153
+			WordPressPluginsPage::class => AdminRoute::getDefaultDependencies(),
154
+			// public dependencies
155
+			PersonalDataRequests::class => $public,
156
+			FrontendRequests::class     => $public,
157
+		];
158
+		foreach ($default_routes as $route => $dependencies) {
159
+			$this->dependency_map->registerDependencies($route, $dependencies);
160
+		}
161
+	}
162 162
 
163 163
 
164
-    /**
165
-     * implements logic required to run during request
166
-     *
167
-     * @return bool
168
-     * @since   $VID:$
169
-     */
170
-    protected function requestHandler(): bool
171
-    {
172
-        $this->setRouteRequestType(PrimaryRoute::ROUTE_REQUEST_TYPE_REGULAR);
173
-        return true;
174
-    }
164
+	/**
165
+	 * implements logic required to run during request
166
+	 *
167
+	 * @return bool
168
+	 * @since   $VID:$
169
+	 */
170
+	protected function requestHandler(): bool
171
+	{
172
+		$this->setRouteRequestType(PrimaryRoute::ROUTE_REQUEST_TYPE_REGULAR);
173
+		return true;
174
+	}
175 175
 }
Please login to merge, or discard this patch.
core/domain/entities/routing/handlers/shared/AssetRequests.php 1 patch
Indentation   +134 added lines, -134 removed lines patch added patch discarded remove patch
@@ -22,148 +22,148 @@
 block discarded – undo
22 22
  */
23 23
 class AssetRequests extends Route
24 24
 {
25
-    /**
26
-     * @var BaristaFactory $barista_factory
27
-     */
28
-    protected $barista_factory;
25
+	/**
26
+	 * @var BaristaFactory $barista_factory
27
+	 */
28
+	protected $barista_factory;
29 29
 
30 30
 
31
-    /**
32
-     * AssetRequests constructor.
33
-     *
34
-     * @param EE_Dependency_Map                $dependency_map
35
-     * @param LoaderInterface                  $loader
36
-     * @param RequestInterface                 $request
37
-     * @param BaristaFactory $barista_factory
38
-     */
39
-    public function __construct(
40
-        EE_Dependency_Map $dependency_map,
41
-        LoaderInterface $loader,
42
-        RequestInterface $request,
43
-        BaristaFactory $barista_factory
44
-    ) {
45
-        $this->barista_factory = $barista_factory;
46
-        parent::__construct($dependency_map, $loader, $request);
47
-    }
31
+	/**
32
+	 * AssetRequests constructor.
33
+	 *
34
+	 * @param EE_Dependency_Map                $dependency_map
35
+	 * @param LoaderInterface                  $loader
36
+	 * @param RequestInterface                 $request
37
+	 * @param BaristaFactory $barista_factory
38
+	 */
39
+	public function __construct(
40
+		EE_Dependency_Map $dependency_map,
41
+		LoaderInterface $loader,
42
+		RequestInterface $request,
43
+		BaristaFactory $barista_factory
44
+	) {
45
+		$this->barista_factory = $barista_factory;
46
+		parent::__construct($dependency_map, $loader, $request);
47
+	}
48 48
 
49 49
 
50
-    /**
51
-     * returns true if the current request matches this route
52
-     *
53
-     * @return bool
54
-     * @since   $VID:$
55
-     */
56
-    public function matchesCurrentRequest(): bool
57
-    {
58
-        return $this->request->isAdmin()
59
-               || $this->request->isFrontend()
60
-               || $this->request->isIframe()
61
-               || $this->request->isWordPressApi();
62
-    }
50
+	/**
51
+	 * returns true if the current request matches this route
52
+	 *
53
+	 * @return bool
54
+	 * @since   $VID:$
55
+	 */
56
+	public function matchesCurrentRequest(): bool
57
+	{
58
+		return $this->request->isAdmin()
59
+			   || $this->request->isFrontend()
60
+			   || $this->request->isIframe()
61
+			   || $this->request->isWordPressApi();
62
+	}
63 63
 
64 64
 
65
-    /**
66
-     * @since $VID:$
67
-     */
68
-    protected function registerDependencies()
69
-    {
70
-        $default_dependencies = [
71
-            'EventEspresso\core\domain\Domain'                   => EE_Dependency_Map::load_from_cache,
72
-            'EventEspresso\core\services\assets\AssetCollection' => EE_Dependency_Map::load_new_object,
73
-            'EventEspresso\core\services\assets\Registry'        => EE_Dependency_Map::load_from_cache,
74
-        ];
75
-        $this->dependency_map->registerDependencies(JqueryAssetManager::class, $default_dependencies);
76
-        $this->dependency_map->registerDependencies(ReactAssetManager::class, $default_dependencies);
77
-        $this->dependency_map->registerDependencies(
78
-            CoreAssetManager::class,
79
-            [
80
-                'EventEspresso\core\services\assets\AssetCollection' => EE_Dependency_Map::load_new_object,
81
-                'EE_Currency_Config'                                 => EE_Dependency_Map::load_from_cache,
82
-                'EE_Template_Config'                                 => EE_Dependency_Map::load_from_cache,
83
-                'EventEspresso\core\domain\Domain'                   => EE_Dependency_Map::load_from_cache,
84
-                'EventEspresso\core\services\assets\Registry'        => EE_Dependency_Map::load_from_cache,
85
-            ]
86
-        );
87
-        $this->dependency_map->registerDependencies(
88
-            'EventEspresso\core\services\editor\BlockRegistrationManager',
89
-            [
90
-                'EventEspresso\core\services\assets\BlockAssetManagerCollection'     => EE_Dependency_Map::load_from_cache,
91
-                'EventEspresso\core\domain\entities\editor\BlockCollection'          => EE_Dependency_Map::load_from_cache,
92
-                'EventEspresso\core\services\routing\RouteMatchSpecificationManager' => EE_Dependency_Map::load_from_cache,
93
-                'EventEspresso\core\services\request\Request'                        => EE_Dependency_Map::load_from_cache,
94
-            ]
95
-        );
96
-        $this->dependency_map->registerDependencies(
97
-            'EventEspresso\core\domain\entities\editor\CoreBlocksAssetManager',
98
-            [
99
-                'EventEspresso\core\domain\Domain'                   => EE_Dependency_Map::load_from_cache,
100
-                'EventEspresso\core\services\assets\AssetCollection' => EE_Dependency_Map::load_new_object,
101
-                'EventEspresso\core\services\assets\Registry'        => EE_Dependency_Map::load_from_cache,
102
-            ]
103
-        );
104
-        $this->dependency_map->registerDependencies(
105
-            'EventEspresso\core\domain\services\blocks\EventAttendeesBlockRenderer',
106
-            [
107
-                'EventEspresso\core\domain\Domain'                                        => EE_Dependency_Map::load_from_cache,
108
-                'EEM_Attendee'                                                            => EE_Dependency_Map::load_from_cache,
109
-                'EventEspresso\core\domain\services\graphql\enums\RegistrationStatusEnum' => EE_Dependency_Map::load_from_cache,
110
-            ]
111
-        );
112
-        $this->dependency_map->registerDependencies(
113
-            'EventEspresso\core\domain\entities\editor\blocks\EventAttendees',
114
-            [
115
-                'EventEspresso\core\domain\entities\editor\CoreBlocksAssetManager'      => EE_Dependency_Map::load_from_cache,
116
-                'EventEspresso\core\services\request\Request'                           => EE_Dependency_Map::load_from_cache,
117
-                'EventEspresso\core\domain\services\blocks\EventAttendeesBlockRenderer' => EE_Dependency_Map::load_from_cache,
118
-            ]
119
-        );
120
-        if (apply_filters('FHEE__load_Barista', true)) {
121
-            $this->dependency_map->registerDependencies(
122
-                'EventEspresso\core\services\assets\Barista',
123
-                ['EventEspresso\core\services\assets\AssetManifest' => EE_Dependency_Map::load_from_cache]
124
-            );
125
-        }
126
-    }
65
+	/**
66
+	 * @since $VID:$
67
+	 */
68
+	protected function registerDependencies()
69
+	{
70
+		$default_dependencies = [
71
+			'EventEspresso\core\domain\Domain'                   => EE_Dependency_Map::load_from_cache,
72
+			'EventEspresso\core\services\assets\AssetCollection' => EE_Dependency_Map::load_new_object,
73
+			'EventEspresso\core\services\assets\Registry'        => EE_Dependency_Map::load_from_cache,
74
+		];
75
+		$this->dependency_map->registerDependencies(JqueryAssetManager::class, $default_dependencies);
76
+		$this->dependency_map->registerDependencies(ReactAssetManager::class, $default_dependencies);
77
+		$this->dependency_map->registerDependencies(
78
+			CoreAssetManager::class,
79
+			[
80
+				'EventEspresso\core\services\assets\AssetCollection' => EE_Dependency_Map::load_new_object,
81
+				'EE_Currency_Config'                                 => EE_Dependency_Map::load_from_cache,
82
+				'EE_Template_Config'                                 => EE_Dependency_Map::load_from_cache,
83
+				'EventEspresso\core\domain\Domain'                   => EE_Dependency_Map::load_from_cache,
84
+				'EventEspresso\core\services\assets\Registry'        => EE_Dependency_Map::load_from_cache,
85
+			]
86
+		);
87
+		$this->dependency_map->registerDependencies(
88
+			'EventEspresso\core\services\editor\BlockRegistrationManager',
89
+			[
90
+				'EventEspresso\core\services\assets\BlockAssetManagerCollection'     => EE_Dependency_Map::load_from_cache,
91
+				'EventEspresso\core\domain\entities\editor\BlockCollection'          => EE_Dependency_Map::load_from_cache,
92
+				'EventEspresso\core\services\routing\RouteMatchSpecificationManager' => EE_Dependency_Map::load_from_cache,
93
+				'EventEspresso\core\services\request\Request'                        => EE_Dependency_Map::load_from_cache,
94
+			]
95
+		);
96
+		$this->dependency_map->registerDependencies(
97
+			'EventEspresso\core\domain\entities\editor\CoreBlocksAssetManager',
98
+			[
99
+				'EventEspresso\core\domain\Domain'                   => EE_Dependency_Map::load_from_cache,
100
+				'EventEspresso\core\services\assets\AssetCollection' => EE_Dependency_Map::load_new_object,
101
+				'EventEspresso\core\services\assets\Registry'        => EE_Dependency_Map::load_from_cache,
102
+			]
103
+		);
104
+		$this->dependency_map->registerDependencies(
105
+			'EventEspresso\core\domain\services\blocks\EventAttendeesBlockRenderer',
106
+			[
107
+				'EventEspresso\core\domain\Domain'                                        => EE_Dependency_Map::load_from_cache,
108
+				'EEM_Attendee'                                                            => EE_Dependency_Map::load_from_cache,
109
+				'EventEspresso\core\domain\services\graphql\enums\RegistrationStatusEnum' => EE_Dependency_Map::load_from_cache,
110
+			]
111
+		);
112
+		$this->dependency_map->registerDependencies(
113
+			'EventEspresso\core\domain\entities\editor\blocks\EventAttendees',
114
+			[
115
+				'EventEspresso\core\domain\entities\editor\CoreBlocksAssetManager'      => EE_Dependency_Map::load_from_cache,
116
+				'EventEspresso\core\services\request\Request'                           => EE_Dependency_Map::load_from_cache,
117
+				'EventEspresso\core\domain\services\blocks\EventAttendeesBlockRenderer' => EE_Dependency_Map::load_from_cache,
118
+			]
119
+		);
120
+		if (apply_filters('FHEE__load_Barista', true)) {
121
+			$this->dependency_map->registerDependencies(
122
+				'EventEspresso\core\services\assets\Barista',
123
+				['EventEspresso\core\services\assets\AssetManifest' => EE_Dependency_Map::load_from_cache]
124
+			);
125
+		}
126
+	}
127 127
 
128 128
 
129
-    /**
130
-     * implements logic required to run during request
131
-     *
132
-     * @return bool
133
-     * @since   $VID:$
134
-     */
135
-    protected function requestHandler(): bool
136
-    {
137
-        if (apply_filters('FHEE__load_Barista', true)) {
138
-            $barista = $this->barista_factory->create();
139
-            if ($barista instanceof BaristaInterface) {
140
-                $barista->initialize();
141
-                $this->loader->getShared('EventEspresso\core\services\assets\Registry');
142
-            }
143
-        }
144
-        $this->loader->getShared(JqueryAssetManager::class);
145
-        $this->loader->getShared(CoreAssetManager::class);
146
-        if ($this->canLoadBlocks()) {
147
-            $this->loader->getShared(
148
-                'EventEspresso\core\services\editor\BlockRegistrationManager'
149
-            );
150
-        }
151
-        return true;
152
-    }
129
+	/**
130
+	 * implements logic required to run during request
131
+	 *
132
+	 * @return bool
133
+	 * @since   $VID:$
134
+	 */
135
+	protected function requestHandler(): bool
136
+	{
137
+		if (apply_filters('FHEE__load_Barista', true)) {
138
+			$barista = $this->barista_factory->create();
139
+			if ($barista instanceof BaristaInterface) {
140
+				$barista->initialize();
141
+				$this->loader->getShared('EventEspresso\core\services\assets\Registry');
142
+			}
143
+		}
144
+		$this->loader->getShared(JqueryAssetManager::class);
145
+		$this->loader->getShared(CoreAssetManager::class);
146
+		if ($this->canLoadBlocks()) {
147
+			$this->loader->getShared(
148
+				'EventEspresso\core\services\editor\BlockRegistrationManager'
149
+			);
150
+		}
151
+		return true;
152
+	}
153 153
 
154 154
 
155
-    /**
156
-     * Return whether blocks can be registered/loaded or not.
157
-     *
158
-     * @return bool
159
-     * @since $VID:$
160
-     */
161
-    private function canLoadBlocks()
162
-    {
163
-        return apply_filters('FHEE__EE_System__canLoadBlocks', true)
164
-               && function_exists('register_block_type')
165
-               // don't load blocks if in the Divi page builder editor context
166
-               // @see https://github.com/eventespresso/event-espresso-core/issues/814
167
-               && ! $this->request->getRequestParam('et_fb', false);
168
-    }
155
+	/**
156
+	 * Return whether blocks can be registered/loaded or not.
157
+	 *
158
+	 * @return bool
159
+	 * @since $VID:$
160
+	 */
161
+	private function canLoadBlocks()
162
+	{
163
+		return apply_filters('FHEE__EE_System__canLoadBlocks', true)
164
+			   && function_exists('register_block_type')
165
+			   // don't load blocks if in the Divi page builder editor context
166
+			   // @see https://github.com/eventespresso/event-espresso-core/issues/814
167
+			   && ! $this->request->getRequestParam('et_fb', false);
168
+	}
169 169
 }
Please login to merge, or discard this patch.
core/domain/entities/routing/handlers/shared/GQLRequests.php 1 patch
Indentation   +216 added lines, -216 removed lines patch added patch discarded remove patch
@@ -19,228 +19,228 @@
 block discarded – undo
19 19
  */
20 20
 class GQLRequests extends Route
21 21
 {
22
-    /**
23
-     * @var AssetManifestFactory
24
-     */
25
-    private $manifest_factory;
22
+	/**
23
+	 * @var AssetManifestFactory
24
+	 */
25
+	private $manifest_factory;
26 26
 
27 27
 
28
-    /**
29
-     * AssetRequests constructor.
30
-     *
31
-     * @param EE_Dependency_Map    $dependency_map
32
-     * @param LoaderInterface      $loader
33
-     * @param RequestInterface     $request
34
-     * @param AssetManifestFactory $manifest_factory
35
-     */
36
-    public function __construct(
37
-        EE_Dependency_Map $dependency_map,
38
-        LoaderInterface $loader,
39
-        RequestInterface $request,
40
-        AssetManifestFactory $manifest_factory
41
-    ) {
42
-        $this->manifest_factory = $manifest_factory;
43
-        parent::__construct($dependency_map, $loader, $request);
44
-    }
28
+	/**
29
+	 * AssetRequests constructor.
30
+	 *
31
+	 * @param EE_Dependency_Map    $dependency_map
32
+	 * @param LoaderInterface      $loader
33
+	 * @param RequestInterface     $request
34
+	 * @param AssetManifestFactory $manifest_factory
35
+	 */
36
+	public function __construct(
37
+		EE_Dependency_Map $dependency_map,
38
+		LoaderInterface $loader,
39
+		RequestInterface $request,
40
+		AssetManifestFactory $manifest_factory
41
+	) {
42
+		$this->manifest_factory = $manifest_factory;
43
+		parent::__construct($dependency_map, $loader, $request);
44
+	}
45 45
 
46 46
 
47
-    /**
48
-     * returns true if the current request matches this route
49
-     *
50
-     * @return bool
51
-     * @since   $VID:$
52
-     */
53
-    public function matchesCurrentRequest(): bool
54
-    {
55
-        global $pagenow;
56
-        return (
57
-                   $this->request->isGQL()
58
-                   || $this->request->isUnitTesting()
59
-                   || (
60
-                       $this->request->isAdmin()
61
-                       && $this->request->getRequestParam('page') === 'espresso_events'
62
-                       && (
63
-                           $this->request->getRequestParam('action') === 'create_new'
64
-                           || $this->request->getRequestParam('action') === 'edit'
65
-                       )
66
-                   )
67
-                   || (
68
-                       $pagenow
69
-                       && (
70
-                           $pagenow === 'post-new.php'
71
-                           || (
72
-                               $pagenow === 'post.php'
73
-                               && $this->request->getRequestParam('action') === 'edit'
74
-                           )
75
-                       )
76
-                   )
77
-               );
78
-    }
47
+	/**
48
+	 * returns true if the current request matches this route
49
+	 *
50
+	 * @return bool
51
+	 * @since   $VID:$
52
+	 */
53
+	public function matchesCurrentRequest(): bool
54
+	{
55
+		global $pagenow;
56
+		return (
57
+				   $this->request->isGQL()
58
+				   || $this->request->isUnitTesting()
59
+				   || (
60
+					   $this->request->isAdmin()
61
+					   && $this->request->getRequestParam('page') === 'espresso_events'
62
+					   && (
63
+						   $this->request->getRequestParam('action') === 'create_new'
64
+						   || $this->request->getRequestParam('action') === 'edit'
65
+					   )
66
+				   )
67
+				   || (
68
+					   $pagenow
69
+					   && (
70
+						   $pagenow === 'post-new.php'
71
+						   || (
72
+							   $pagenow === 'post.php'
73
+							   && $this->request->getRequestParam('action') === 'edit'
74
+						   )
75
+					   )
76
+				   )
77
+			   );
78
+	}
79 79
 
80 80
 
81
-    /**
82
-     * @since $VID:$
83
-     */
84
-    protected function registerDependencies()
85
-    {
86
-        $this->dependency_map->registerDependencies(
87
-            'EventEspresso\core\services\graphql\GraphQLManager',
88
-            [
89
-                'EventEspresso\core\services\graphql\ConnectionsManager' => EE_Dependency_Map::load_from_cache,
90
-                'EventEspresso\core\services\graphql\DataLoaderManager'  => EE_Dependency_Map::load_from_cache,
91
-                'EventEspresso\core\services\graphql\EnumsManager'       => EE_Dependency_Map::load_from_cache,
92
-                'EventEspresso\core\services\graphql\InputsManager'      => EE_Dependency_Map::load_from_cache,
93
-                'EventEspresso\core\services\graphql\TypesManager'       => EE_Dependency_Map::load_from_cache,
94
-            ]
95
-        );
96
-        $this->dependency_map->registerDependencies(
97
-            'EventEspresso\core\services\graphql\TypesManager',
98
-            [
99
-                'EventEspresso\core\services\graphql\types\TypeCollection' => EE_Dependency_Map::load_from_cache,
100
-            ]
101
-        );
102
-        $this->dependency_map->registerDependencies(
103
-            'EventEspresso\core\services\graphql\InputsManager',
104
-            [
105
-                'EventEspresso\core\services\graphql\inputs\InputCollection' => EE_Dependency_Map::load_from_cache,
106
-            ]
107
-        );
108
-        $this->dependency_map->registerDependencies(
109
-            'EventEspresso\core\services\graphql\EnumsManager',
110
-            [
111
-                'EventEspresso\core\services\graphql\enums\EnumCollection' => EE_Dependency_Map::load_from_cache,
112
-            ]
113
-        );
114
-        $this->dependency_map->registerDependencies(
115
-            'EventEspresso\core\services\graphql\ConnectionsManager',
116
-            [
117
-                'EventEspresso\core\services\graphql\connections\ConnectionCollection' => EE_Dependency_Map::load_from_cache,
118
-            ]
119
-        );
120
-        $this->dependency_map->registerDependencies(
121
-            'EventEspresso\core\services\graphql\DataLoaderManager',
122
-            [
123
-                'EventEspresso\core\services\graphql\loaders\DataLoaderCollection' => EE_Dependency_Map::load_from_cache,
124
-            ]
125
-        );
126
-        $this->dependency_map->registerDependencies(
127
-            'EventEspresso\core\domain\services\graphql\types\Datetime',
128
-            ['EEM_Datetime' => EE_Dependency_Map::load_from_cache]
129
-        );
130
-        $this->dependency_map->registerDependencies(
131
-            'EventEspresso\core\domain\services\graphql\types\Attendee',
132
-            ['EEM_Attendee' => EE_Dependency_Map::load_from_cache]
133
-        );
134
-        $this->dependency_map->registerDependencies(
135
-            'EventEspresso\core\domain\services\graphql\types\Event',
136
-            ['EEM_Event' => EE_Dependency_Map::load_from_cache]
137
-        );
138
-        $this->dependency_map->registerDependencies(
139
-            'EventEspresso\core\domain\services\graphql\types\FormElement',
140
-            ['EEM_Form_Element' => EE_Dependency_Map::load_from_cache]
141
-        );
142
-        $this->dependency_map->registerDependencies(
143
-            'EventEspresso\core\domain\services\graphql\types\FormSection',
144
-            ['EEM_Form_Section' => EE_Dependency_Map::load_from_cache]
145
-        );
146
-        $this->dependency_map->registerDependencies(
147
-            'EventEspresso\core\domain\services\graphql\types\Ticket',
148
-            ['EEM_Ticket' => EE_Dependency_Map::load_from_cache]
149
-        );
150
-        $this->dependency_map->registerDependencies(
151
-            'EventEspresso\core\domain\services\graphql\types\Price',
152
-            ['EEM_Price' => EE_Dependency_Map::load_from_cache]
153
-        );
154
-        $this->dependency_map->registerDependencies(
155
-            'EventEspresso\core\domain\services\graphql\types\PriceType',
156
-            ['EEM_Price_Type' => EE_Dependency_Map::load_from_cache]
157
-        );
158
-        $this->dependency_map->registerDependencies(
159
-            'EventEspresso\core\domain\services\graphql\types\Venue',
160
-            ['EEM_Venue' => EE_Dependency_Map::load_from_cache]
161
-        );
162
-        $this->dependency_map->registerDependencies(
163
-            'EventEspresso\core\domain\services\graphql\types\State',
164
-            ['EEM_State' => EE_Dependency_Map::load_from_cache]
165
-        );
166
-        $this->dependency_map->registerDependencies(
167
-            'EventEspresso\core\domain\services\graphql\types\Country',
168
-            ['EEM_Country' => EE_Dependency_Map::load_from_cache]
169
-        );
170
-        $this->dependency_map->registerDependencies(
171
-            'EventEspresso\core\domain\services\graphql\connections\EventDatetimesConnection',
172
-            ['EEM_Datetime' => EE_Dependency_Map::load_from_cache]
173
-        );
174
-        $this->dependency_map->registerDependencies(
175
-            'EventEspresso\core\domain\services\graphql\connections\RootQueryDatetimesConnection',
176
-            ['EEM_Datetime' => EE_Dependency_Map::load_from_cache]
177
-        );
178
-        $this->dependency_map->registerDependencies(
179
-            'EventEspresso\core\domain\services\graphql\connections\RootQueryAttendeesConnection',
180
-            ['EEM_Attendee' => EE_Dependency_Map::load_from_cache]
181
-        );
182
-        $this->dependency_map->registerDependencies(
183
-            'EventEspresso\core\domain\services\graphql\connections\RootQueryCountriesConnection',
184
-            ['EEM_Country' => EE_Dependency_Map::load_from_cache]
185
-        );
186
-        $this->dependency_map->registerDependencies(
187
-            'EventEspresso\core\domain\services\graphql\connections\RootQueryFormElementsConnection',
188
-            ['EEM_Form_Element' => EE_Dependency_Map::load_from_cache]
189
-        );
190
-        $this->dependency_map->registerDependencies(
191
-            'EventEspresso\core\domain\services\graphql\connections\RootQueryFormSectionsConnection',
192
-            ['EEM_Form_Section' => EE_Dependency_Map::load_from_cache]
193
-        );
194
-        $this->dependency_map->registerDependencies(
195
-            'EventEspresso\core\domain\services\graphql\connections\RootQueryStatesConnection',
196
-            ['EEM_State' => EE_Dependency_Map::load_from_cache]
197
-        );
198
-        $this->dependency_map->registerDependencies(
199
-            'EventEspresso\core\domain\services\graphql\connections\DatetimeTicketsConnection',
200
-            ['EEM_Ticket' => EE_Dependency_Map::load_from_cache]
201
-        );
202
-        $this->dependency_map->registerDependencies(
203
-            'EventEspresso\core\domain\services\graphql\connections\RootQueryTicketsConnection',
204
-            ['EEM_Ticket' => EE_Dependency_Map::load_from_cache]
205
-        );
206
-        $this->dependency_map->registerDependencies(
207
-            'EventEspresso\core\domain\services\graphql\connections\TicketPricesConnection',
208
-            ['EEM_Price' => EE_Dependency_Map::load_from_cache]
209
-        );
210
-        $this->dependency_map->registerDependencies(
211
-            'EventEspresso\core\domain\services\graphql\connections\RootQueryPricesConnection',
212
-            ['EEM_Price' => EE_Dependency_Map::load_from_cache]
213
-        );
214
-        $this->dependency_map->registerDependencies(
215
-            'EventEspresso\core\domain\services\graphql\connections\RootQueryPriceTypesConnection',
216
-            ['EEM_Price_Type' => EE_Dependency_Map::load_from_cache]
217
-        );
218
-        $this->dependency_map->registerDependencies(
219
-            'EventEspresso\core\domain\services\graphql\connections\TicketDatetimesConnection',
220
-            ['EEM_Datetime' => EE_Dependency_Map::load_from_cache]
221
-        );
222
-        $this->dependency_map->registerDependencies(
223
-            'EventEspresso\core\domain\services\graphql\connections\EventVenuesConnection',
224
-            ['EEM_Venue' => EE_Dependency_Map::load_from_cache]
225
-        );
226
-    }
81
+	/**
82
+	 * @since $VID:$
83
+	 */
84
+	protected function registerDependencies()
85
+	{
86
+		$this->dependency_map->registerDependencies(
87
+			'EventEspresso\core\services\graphql\GraphQLManager',
88
+			[
89
+				'EventEspresso\core\services\graphql\ConnectionsManager' => EE_Dependency_Map::load_from_cache,
90
+				'EventEspresso\core\services\graphql\DataLoaderManager'  => EE_Dependency_Map::load_from_cache,
91
+				'EventEspresso\core\services\graphql\EnumsManager'       => EE_Dependency_Map::load_from_cache,
92
+				'EventEspresso\core\services\graphql\InputsManager'      => EE_Dependency_Map::load_from_cache,
93
+				'EventEspresso\core\services\graphql\TypesManager'       => EE_Dependency_Map::load_from_cache,
94
+			]
95
+		);
96
+		$this->dependency_map->registerDependencies(
97
+			'EventEspresso\core\services\graphql\TypesManager',
98
+			[
99
+				'EventEspresso\core\services\graphql\types\TypeCollection' => EE_Dependency_Map::load_from_cache,
100
+			]
101
+		);
102
+		$this->dependency_map->registerDependencies(
103
+			'EventEspresso\core\services\graphql\InputsManager',
104
+			[
105
+				'EventEspresso\core\services\graphql\inputs\InputCollection' => EE_Dependency_Map::load_from_cache,
106
+			]
107
+		);
108
+		$this->dependency_map->registerDependencies(
109
+			'EventEspresso\core\services\graphql\EnumsManager',
110
+			[
111
+				'EventEspresso\core\services\graphql\enums\EnumCollection' => EE_Dependency_Map::load_from_cache,
112
+			]
113
+		);
114
+		$this->dependency_map->registerDependencies(
115
+			'EventEspresso\core\services\graphql\ConnectionsManager',
116
+			[
117
+				'EventEspresso\core\services\graphql\connections\ConnectionCollection' => EE_Dependency_Map::load_from_cache,
118
+			]
119
+		);
120
+		$this->dependency_map->registerDependencies(
121
+			'EventEspresso\core\services\graphql\DataLoaderManager',
122
+			[
123
+				'EventEspresso\core\services\graphql\loaders\DataLoaderCollection' => EE_Dependency_Map::load_from_cache,
124
+			]
125
+		);
126
+		$this->dependency_map->registerDependencies(
127
+			'EventEspresso\core\domain\services\graphql\types\Datetime',
128
+			['EEM_Datetime' => EE_Dependency_Map::load_from_cache]
129
+		);
130
+		$this->dependency_map->registerDependencies(
131
+			'EventEspresso\core\domain\services\graphql\types\Attendee',
132
+			['EEM_Attendee' => EE_Dependency_Map::load_from_cache]
133
+		);
134
+		$this->dependency_map->registerDependencies(
135
+			'EventEspresso\core\domain\services\graphql\types\Event',
136
+			['EEM_Event' => EE_Dependency_Map::load_from_cache]
137
+		);
138
+		$this->dependency_map->registerDependencies(
139
+			'EventEspresso\core\domain\services\graphql\types\FormElement',
140
+			['EEM_Form_Element' => EE_Dependency_Map::load_from_cache]
141
+		);
142
+		$this->dependency_map->registerDependencies(
143
+			'EventEspresso\core\domain\services\graphql\types\FormSection',
144
+			['EEM_Form_Section' => EE_Dependency_Map::load_from_cache]
145
+		);
146
+		$this->dependency_map->registerDependencies(
147
+			'EventEspresso\core\domain\services\graphql\types\Ticket',
148
+			['EEM_Ticket' => EE_Dependency_Map::load_from_cache]
149
+		);
150
+		$this->dependency_map->registerDependencies(
151
+			'EventEspresso\core\domain\services\graphql\types\Price',
152
+			['EEM_Price' => EE_Dependency_Map::load_from_cache]
153
+		);
154
+		$this->dependency_map->registerDependencies(
155
+			'EventEspresso\core\domain\services\graphql\types\PriceType',
156
+			['EEM_Price_Type' => EE_Dependency_Map::load_from_cache]
157
+		);
158
+		$this->dependency_map->registerDependencies(
159
+			'EventEspresso\core\domain\services\graphql\types\Venue',
160
+			['EEM_Venue' => EE_Dependency_Map::load_from_cache]
161
+		);
162
+		$this->dependency_map->registerDependencies(
163
+			'EventEspresso\core\domain\services\graphql\types\State',
164
+			['EEM_State' => EE_Dependency_Map::load_from_cache]
165
+		);
166
+		$this->dependency_map->registerDependencies(
167
+			'EventEspresso\core\domain\services\graphql\types\Country',
168
+			['EEM_Country' => EE_Dependency_Map::load_from_cache]
169
+		);
170
+		$this->dependency_map->registerDependencies(
171
+			'EventEspresso\core\domain\services\graphql\connections\EventDatetimesConnection',
172
+			['EEM_Datetime' => EE_Dependency_Map::load_from_cache]
173
+		);
174
+		$this->dependency_map->registerDependencies(
175
+			'EventEspresso\core\domain\services\graphql\connections\RootQueryDatetimesConnection',
176
+			['EEM_Datetime' => EE_Dependency_Map::load_from_cache]
177
+		);
178
+		$this->dependency_map->registerDependencies(
179
+			'EventEspresso\core\domain\services\graphql\connections\RootQueryAttendeesConnection',
180
+			['EEM_Attendee' => EE_Dependency_Map::load_from_cache]
181
+		);
182
+		$this->dependency_map->registerDependencies(
183
+			'EventEspresso\core\domain\services\graphql\connections\RootQueryCountriesConnection',
184
+			['EEM_Country' => EE_Dependency_Map::load_from_cache]
185
+		);
186
+		$this->dependency_map->registerDependencies(
187
+			'EventEspresso\core\domain\services\graphql\connections\RootQueryFormElementsConnection',
188
+			['EEM_Form_Element' => EE_Dependency_Map::load_from_cache]
189
+		);
190
+		$this->dependency_map->registerDependencies(
191
+			'EventEspresso\core\domain\services\graphql\connections\RootQueryFormSectionsConnection',
192
+			['EEM_Form_Section' => EE_Dependency_Map::load_from_cache]
193
+		);
194
+		$this->dependency_map->registerDependencies(
195
+			'EventEspresso\core\domain\services\graphql\connections\RootQueryStatesConnection',
196
+			['EEM_State' => EE_Dependency_Map::load_from_cache]
197
+		);
198
+		$this->dependency_map->registerDependencies(
199
+			'EventEspresso\core\domain\services\graphql\connections\DatetimeTicketsConnection',
200
+			['EEM_Ticket' => EE_Dependency_Map::load_from_cache]
201
+		);
202
+		$this->dependency_map->registerDependencies(
203
+			'EventEspresso\core\domain\services\graphql\connections\RootQueryTicketsConnection',
204
+			['EEM_Ticket' => EE_Dependency_Map::load_from_cache]
205
+		);
206
+		$this->dependency_map->registerDependencies(
207
+			'EventEspresso\core\domain\services\graphql\connections\TicketPricesConnection',
208
+			['EEM_Price' => EE_Dependency_Map::load_from_cache]
209
+		);
210
+		$this->dependency_map->registerDependencies(
211
+			'EventEspresso\core\domain\services\graphql\connections\RootQueryPricesConnection',
212
+			['EEM_Price' => EE_Dependency_Map::load_from_cache]
213
+		);
214
+		$this->dependency_map->registerDependencies(
215
+			'EventEspresso\core\domain\services\graphql\connections\RootQueryPriceTypesConnection',
216
+			['EEM_Price_Type' => EE_Dependency_Map::load_from_cache]
217
+		);
218
+		$this->dependency_map->registerDependencies(
219
+			'EventEspresso\core\domain\services\graphql\connections\TicketDatetimesConnection',
220
+			['EEM_Datetime' => EE_Dependency_Map::load_from_cache]
221
+		);
222
+		$this->dependency_map->registerDependencies(
223
+			'EventEspresso\core\domain\services\graphql\connections\EventVenuesConnection',
224
+			['EEM_Venue' => EE_Dependency_Map::load_from_cache]
225
+		);
226
+	}
227 227
 
228 228
 
229
-    /**
230
-     * implements logic required to run during request
231
-     *
232
-     * @return bool
233
-     * @since   $VID:$
234
-     */
235
-    protected function requestHandler(): bool
236
-    {
237
-        // load handler for EE GraphQL requests
238
-        $graphQL_manager = $this->loader->getShared(
239
-            'EventEspresso\core\services\graphql\GraphQLManager'
240
-        );
241
-        $graphQL_manager->init();
242
-        $manifest = $this->manifest_factory->createFromDomainObject(DomainFactory::getEventEspressoCoreDomain());
243
-        $manifest->initialize();
244
-        return true;
245
-    }
229
+	/**
230
+	 * implements logic required to run during request
231
+	 *
232
+	 * @return bool
233
+	 * @since   $VID:$
234
+	 */
235
+	protected function requestHandler(): bool
236
+	{
237
+		// load handler for EE GraphQL requests
238
+		$graphQL_manager = $this->loader->getShared(
239
+			'EventEspresso\core\services\graphql\GraphQLManager'
240
+		);
241
+		$graphQL_manager->init();
242
+		$manifest = $this->manifest_factory->createFromDomainObject(DomainFactory::getEventEspressoCoreDomain());
243
+		$manifest->initialize();
244
+		return true;
245
+	}
246 246
 }
Please login to merge, or discard this patch.
core/domain/entities/routing/handlers/admin/ActivationRequests.php 1 patch
Indentation   +35 added lines, -35 removed lines patch added patch discarded remove patch
@@ -14,43 +14,43 @@
 block discarded – undo
14 14
  */
15 15
 class ActivationRequests extends PrimaryRoute
16 16
 {
17
-    /**
18
-     * returns true if the current request matches this route
19
-     *
20
-     * @return bool
21
-     * @since   $VID:$
22
-     */
23
-    public function matchesCurrentRequest(): bool
24
-    {
25
-        return $this->request->isActivation();
26
-    }
17
+	/**
18
+	 * returns true if the current request matches this route
19
+	 *
20
+	 * @return bool
21
+	 * @since   $VID:$
22
+	 */
23
+	public function matchesCurrentRequest(): bool
24
+	{
25
+		return $this->request->isActivation();
26
+	}
27 27
 
28 28
 
29
-    /**
30
-     * @since $VID:$
31
-     */
32
-    protected function registerDependencies()
33
-    {
34
-        $this->dependency_map->registerDependencies(
35
-            'EventEspresso\core\domain\entities\routing\handlers\admin\AdminRoute',
36
-            AdminRoute::getDefaultDependencies()
37
-        );
38
-        $this->dependency_map->registerDependencies(
39
-            'EventEspresso\core\domain\entities\routing\handlers\admin\WordPressPluginsPage',
40
-            AdminRoute::getDefaultDependencies()
41
-        );
42
-    }
29
+	/**
30
+	 * @since $VID:$
31
+	 */
32
+	protected function registerDependencies()
33
+	{
34
+		$this->dependency_map->registerDependencies(
35
+			'EventEspresso\core\domain\entities\routing\handlers\admin\AdminRoute',
36
+			AdminRoute::getDefaultDependencies()
37
+		);
38
+		$this->dependency_map->registerDependencies(
39
+			'EventEspresso\core\domain\entities\routing\handlers\admin\WordPressPluginsPage',
40
+			AdminRoute::getDefaultDependencies()
41
+		);
42
+	}
43 43
 
44 44
 
45
-    /**
46
-     * implements logic required to run during request
47
-     *
48
-     * @return bool
49
-     * @since   $VID:$
50
-     */
51
-    protected function requestHandler(): bool
52
-    {
53
-        $this->setRouteRequestType(PrimaryRoute::ROUTE_REQUEST_TYPE_ACTIVATION);
54
-        return true;
55
-    }
45
+	/**
46
+	 * implements logic required to run during request
47
+	 *
48
+	 * @return bool
49
+	 * @since   $VID:$
50
+	 */
51
+	protected function requestHandler(): bool
52
+	{
53
+		$this->setRouteRequestType(PrimaryRoute::ROUTE_REQUEST_TYPE_ACTIVATION);
54
+		return true;
55
+	}
56 56
 }
Please login to merge, or discard this patch.