Completed
Branch master (fbc6d5)
by
unknown
15:54 queued 10:26
created
core/libraries/shortcodes/EE_Transaction_Shortcodes.lib.php 2 patches
Indentation   +798 added lines, -798 removed lines patch added patch discarded remove patch
@@ -16,806 +16,806 @@
 block discarded – undo
16 16
  */
17 17
 class EE_Transaction_Shortcodes extends EE_Shortcodes
18 18
 {
19
-    /**
20
-     * @var EE_Payment_Method|null $_invoice_pm the invoice payment method for use in invoices etc
21
-     */
22
-    protected ?EE_Payment_Method $_invoice_pm = null;
23
-
24
-
25
-    protected function _init_props()
26
-    {
27
-        $this->label       = esc_html__('Transaction Shortcodes', 'event_espresso');
28
-        $this->description = esc_html__('All shortcodes specific to transaction related data', 'event_espresso');
29
-        $this->_shortcodes = [
30
-            '[TXN_ID]'                          => esc_html__('The transaction id for the purchase.', 'event_espresso'),
31
-            '[PAYMENT_URL]'                     => esc_html__(
32
-                'This is a link to make a payment for the event',
33
-                'event_espresso'
34
-            ),
35
-            '[PAYMENT_LINK_IF_NEEDED_*]'        => esc_html__(
36
-                    'This is a special dynamic shortcode that allows one to insert a payment link conditional on there being amount owing on the transaction. Three params are available on this shortcode:',
37
-                    'event_espresso'
38
-                )
39
-                . '<ul>'
40
-                . '<li>'
41
-                . sprintf(
42
-                    esc_html__(
43
-                        '%sclass:%s This can be used to indicate css class is given to the containing css element (default is "callout").',
44
-                        'event_espresso'
45
-                    ),
46
-                    '<strong>',
47
-                    '</strong>'
48
-                )
49
-                . '</li>'
50
-                . '<li>'
51
-                . sprintf(
52
-                    esc_html__(
53
-                        '%scustom_text:%s This should be a sprintf format text string (with %%s for where the hyperlink tags go) that is used for the generated link text (The default is "You can %%smake a payment here »%%s.)',
54
-                        'event_espresso'
55
-                    ),
56
-                    '<strong>',
57
-                    '</strong>'
58
-                )
59
-                . '</li>'
60
-                . '<li>'
61
-                . sprintf(
62
-                    esc_html__(
63
-                        '%scontainer_tag:%s Use this to indicate what container tag you want surrounding the payment link (default is "p").',
64
-                        'event_espresso'
65
-                    ),
66
-                    '<strong>',
67
-                    '</strong>'
68
-                )
69
-                . '</li>'
70
-                . '</ul>',
71
-            '[PAYMENT_DUE_DATE_*]'              => esc_html__(
72
-                    'This is a special dynamic shortcode that allows one to output a payment due date.  It will only result in a date shown if there is money owing.  Three parameters are available on this shortcode:',
73
-                    'event_espresso'
74
-                )
75
-                . '<ul>'
76
-                . '<li>'
77
-                . sprintf(
78
-                    esc_html__(
79
-                        '%sformat:%s This is used to indicate what format the date is in.  Default is whatever is set as date formats for your website.',
80
-                        'event_espresso'
81
-                    ),
82
-                    '<strong>',
83
-                    '</strong>'
84
-                )
85
-                . '</li>'
86
-                . '<li>'
87
-                . sprintf(
88
-                    esc_html__(
89
-                        '%sdays_until_due:%s This is the number of days form the transaction creation date that the payment is due.  Defaults to 30.',
90
-                        'event_espresso'
91
-                    ),
92
-                    '<strong>',
93
-                    '</strong>'
94
-                )
95
-                . '</li>'
96
-                . '<li>'
97
-                . sprintf(
98
-                    esc_html__(
99
-                        '%sprefix_text:%s You can use this to indicate what text will prefix the date string.  Defaults to "Payment in full due by:"',
100
-                        'event_espresso'
101
-                    ),
102
-                    '<strong>',
103
-                    '</strong>'
104
-                )
105
-                . '</li>',
106
-            '[INVOICE_LINK]'                    => esc_html__(
107
-                'This is a full html link to the invoice. Add download=true to link directly to download.',
108
-                'event_espresso'
109
-            ),
110
-            '[INVOICE_URL]'                     => esc_html__(
111
-                'This is just the url for the invoice. Add download=true to link directly to download.',
112
-                'event_espresso'
113
-            ),
114
-            '[INVOICE_LOGO_URL]'                => esc_html__(
115
-                'This returns the url for the logo uploaded via the invoice settings page.',
116
-                'event_espresso'
117
-            ),
118
-            '[INVOICE_LOGO]'                    => esc_html__(
119
-                'This returns the logo uploaded via the invoice settings page wrapped in img_tags and with a "logo screen" classes. The image size is also set in the img tags automatically to match the uploaded logo.',
120
-                'event_espresso'
121
-            ),
122
-            '[INVOICE_PAYEE_NAME]'              => esc_html__(
123
-                'This will parse to either: the value of the "Company Name" field in the invoice payment method settings; if that is blank, then the value of the Company Name in the "Your Organization Settings", if that is blank then an empty string.',
124
-                'event_espresso'
125
-            ),
126
-            '[INVOICE_PAYEE_ADDRESS]'           => esc_html__(
127
-                'This will parse to either: the value of the "Company Address" field in the invoice payment method settings; if that is blank, then the value of the Company Address in the "Your Organization Settings", if that is blank then an empty string.',
128
-                'event_espresso'
129
-            ),
130
-            '[INVOICE_PAYMENT_INSTRUCTIONS]'    => esc_html__(
131
-                'This will parse to the value of the "Payment Instructions" field found on the Invoice payment methods settings page',
132
-                'event_espresso'
133
-            ),
134
-            '[INVOICE_PAYEE_EMAIL]'             => esc_html__(
135
-                'This will parse to either: the value of the "Company Email" field in the invoice payment method settings; if that is blank, then the value of the Company Email in the "Your Organization Settings", if that is blank then an empty string.',
136
-                'event_espresso'
137
-            ),
138
-            '[INVOICE_PAYEE_TAX_NUMBER_*]'      => sprintf(
139
-                esc_html__(
140
-                    'This will parse to either: the value of the "Company Tax Number" field in the invoice payment method settings; if that is blank, then the value of the Company Tax Number in the "Your Organization Settings", if that is blank then an empty string. Note this is also a special dynamic shortcode. You can use the "prefix" parameter to indicate what text you want to use as a prefix before this tax number.  It defaults to "VAT/Tax Number:". To change this prefix you do the following format for this shortcode: %1$s[INVOICE_PAYEE_TAX_NUMBER_* prefix="GST:"]%2$s and that will output: GST: 12345t56.  If you have no tax number in your settings, then no prefix will be output either.',
141
-                    'event_espresso'
142
-                ),
143
-                '<code>',
144
-                '</code>'
145
-            ),
146
-            '[TOTAL_COST]'                      => esc_html__('The total cost for the transaction', 'event_espresso'),
147
-            '[TXN_STATUS]'                      => esc_html__(
148
-                'The transaction status for the transaction.',
149
-                'event_espresso'
150
-            ),
151
-            '[TXN_STATUS_ID]'                   => esc_html__(
152
-                'The ID representing the transaction status as saved in the db.  This tends to be useful for including with css classes for styling certain statuses differently from others.',
153
-                'event_espresso'
154
-            ),
155
-            '[PAYMENT_STATUS]'                  => esc_html__(
156
-                'The transaction status for the transaction. This parses to the same value as the [TXN_STATUS] shortcode and still remains here for legacy support.',
157
-                'event_espresso'
158
-            ),
159
-            '[PAYMENT_GATEWAY]'                 => esc_html__(
160
-                'The payment gateway used for the transaction',
161
-                'event_espresso'
162
-            ),
163
-            '[AMOUNT_PAID]'                     => esc_html__(
164
-                'The amount paid or refunded.  This will only have a value if there was a payment or refund at the time of generating the message.',
165
-                'event_espresso'
166
-            ),
167
-            '[LAST_AMOUNT_PAID]'                => esc_html__(
168
-                'This is the last payment or refund made on the transaction related to the message being generated.',
169
-                'event_espresso'
170
-            ),
171
-            '[TOTAL_AMOUNT_PAID]'               => esc_html__(
172
-                'This parses to the total amount paid over all payments',
173
-                'event_espresso'
174
-            ),
175
-            '[TOTAL_OWING]'                     => esc_html__(
176
-                'The total owing on a transaction with no attributes.',
177
-                'event_espresso'
178
-            ),
179
-            '[TXN_SUBTOTAL]'                    => esc_html__('The subtotal for all txn line items.', 'event_espresso'),
180
-            '[TXN_TAX_SUBTOTAL]'                => esc_html__('The subtotal for all tax line items.', 'event_espresso'),
181
-            '[OWING_STATUS_MESSAGE_*]'          => esc_html__(
182
-                    'A dynamic shortcode for adjusting how total owing gets shown. The acceptable attributes on the shortcode are:',
183
-                    'event_espresso'
184
-                )
185
-                . '<p></ul>'
186
-                . '<li><strong>still_owing</strong>:'
187
-                . esc_html__(
188
-                    'If the transaction is not paid in full, then whatever is set for this attribute is shown (otherwise its just the amount owing). The default is:',
189
-                    'event_espresso'
190
-                )
191
-                . sprintf(
192
-                    esc_html__('%sPlease make a payment.%s', 'event_espresso'),
193
-                    '<a href="[PAYMENT_URL]" class="noPrint">',
194
-                    '</a>'
195
-                )
196
-                . '</li>'
197
-                .
198
-                '<li><strong>none_owing</strong>:'
199
-                . esc_html__(
200
-                    'If the transaction is paid in full, then you can indicate how this gets displayed.  Note, that it defaults to just be the total owing.',
201
-                    'event_espresso'
202
-                )
203
-                . '</li></ul></p>',
204
-            '[TXN_TOTAL_TICKETS]'               => esc_html__(
205
-                'The total number of all tickets purchased in a transaction',
206
-                'event_espresso'
207
-            ),
208
-            '[TKT_QTY_PURCHASED]'               => sprintf(
209
-                esc_html__(
210
-                    'The total number of all tickets purchased in a transaction. %1$sNOTE: This shortcode is good to use in the "[TICKET_LIST]" field but has been deprecated from all other contexts in favor of the more explicit [TXN_TOTAL_TICKETS] shortcode.%2$s',
211
-                    'event_espresso'
212
-                ),
213
-                '<strong>',
214
-                '</strong>'
215
-            ),
216
-            '[TRANSACTION_ADMIN_URL]'           => esc_html__(
217
-                'The url to the admin page for this transaction',
218
-                'event_espresso'
219
-            ),
220
-            '[RECEIPT_URL]'                     => esc_html__(
221
-                'This parses to the generated url for retrieving the receipt for the transaction. Add download=true to link directly to download.',
222
-                'event_espresso'
223
-            ),
224
-            '[INVOICE_RECEIPT_SWITCHER_URL]'    => esc_html__(
225
-                'This parses to the url that will switch to the receipt if an invoice is displayed, and switch to the invoice if receipt is displayed. If a message type OTHER than invoice or receipt is displayed then this will just return the url for the invoice. If the related message type is not active  then will parse to an empty string.',
226
-                'event_espresso'
227
-            ),
228
-            '[INVOICE_RECEIPT_SWITCHER_BUTTON]' => sprintf(
229
-                esc_html__(
230
-                    'The same as %1$s%2$s except this returns the html for a button linked to the invoice or receipt.',
231
-                    'event_espresso'
232
-                ),
233
-                '<code>[INVOICE_RECEIPT_SWITCHER_URL]',
234
-                '</code>'
235
-            ),
236
-            '[LAST_PAYMENT_TRANSACTION_ID]'     => esc_html__(
237
-                'This will output the value of the payment transaction id for the last payment made on the transaction. Note, if a specific payment was included for message generation, that will be used when parsing the shortcode.',
238
-                'event_espresso'
239
-            ),
240
-        ];
241
-    }
242
-
243
-
244
-    /**
245
-     * @param string $shortcode the shortcode to be parsed.
246
-     * @return string parsed shortcode
247
-     * @throws EE_Error
248
-     * @throws InvalidArgumentException
249
-     * @throws ReflectionException
250
-     * @throws InvalidDataTypeException
251
-     * @throws InvalidInterfaceException
252
-     */
253
-    protected function _parser($shortcode)
254
-    {
255
-        // attempt to get the transaction.  Since this is potentially used in more fields, we may have to look in the
256
-        // _extra_data for the transaction.
257
-        $transaction = $this->_data->txn instanceof EE_Transaction ? $this->_data->txn : null;
258
-        $transaction = ! $transaction instanceof EE_Transaction
259
-            && is_array($this->_extra_data)
260
-            && isset($this->_extra_data['data'])
261
-            && $this->_extra_data['data'] instanceof EE_Messages_Addressee
262
-                ? $this->_extra_data['data']->txn
263
-                : $transaction;
264
-        if (! $transaction instanceof EE_Transaction) {
265
-            return '';
266
-        }
267
-        // payment
268
-        $payment = $this->_data->payment instanceof EE_Payment ? $this->_data->payment : null;
269
-        $payment = ! $payment instanceof EE_Payment
270
-            && is_array($this->_extra_data)
271
-            && isset($this->_extra_data['data'])
272
-            && $this->_extra_data['data'] instanceof EE_Messages_Addressee
273
-                ? $this->_extra_data['data']->payment
274
-                : $payment;
275
-
276
-        switch ($shortcode) {
277
-            case '[TXN_ID]':
278
-                return $transaction->ID();
279
-
280
-            case '[PAYMENT_URL]':
281
-                $payment_url = $transaction->payment_overview_url();
282
-                return empty($payment_url)
283
-                    ? esc_html__('http://dummypaymenturlforpreview.com', 'event_espresso')
284
-                    : $payment_url;
285
-
286
-            case strpos($shortcode, '[INVOICE_LINK') !== false :
287
-                // any attributes?
288
-                $attrs = $this->_get_shortcode_attrs($shortcode);
289
-                // downloading PDF or HTML?
290
-                $messenger = isset($attrs['download']) ? 'pdf' : 'html';
291
-                $invoice_url = $transaction->invoice_url($messenger);
292
-                $invoice_url = empty($invoice_url) ? 'http://dummyinvoicelinksforpreview.com' : $invoice_url;
293
-                return sprintf(
294
-                    esc_html__('%sClick here for Invoice%s', 'event_espresso'),
295
-                    '<a href="' . $invoice_url . '">',
296
-                    '</a>'
297
-                );
298
-
299
-            case strpos($shortcode, '[INVOICE_URL') !== false :
300
-                // any attributes?
301
-                $attrs = $this->_get_shortcode_attrs($shortcode);
302
-                // downloading PDF or HTML?
303
-                $messenger = isset($attrs['download']) ? 'pdf' : 'html';
304
-                $invoice_url = $transaction->invoice_url($messenger);
305
-                return empty($invoice_url) ? 'http://dummyinvoicelinksforpreview.com' : $invoice_url;
306
-
307
-            case '[INVOICE_LOGO_URL]':
308
-                return $this->_get_invoice_logo();
309
-
310
-            case '[INVOICE_LOGO]':
311
-                return $this->_get_invoice_logo(true);
312
-
313
-            case '[INVOICE_PAYEE_NAME]':
314
-                return $this->_get_invoice_payee_name();
315
-
316
-            case '[INVOICE_PAYEE_ADDRESS]':
317
-                return $this->_get_invoice_payee_address();
318
-
319
-            case '[INVOICE_PAYMENT_INSTRUCTIONS]':
320
-                return $this->_get_invoice_payment_instructions();
321
-
322
-            case '[INVOICE_PAYEE_EMAIL]':
323
-                return $this->_get_invoice_payee_email();
324
-
325
-            case '[TOTAL_COST]':
326
-                $total = $transaction->total();
327
-                return ! empty($total) ? EEH_Template::format_currency($total) : '';
328
-
329
-            // note the [payment_status] shortcode is kind of misleading because payment status might be different
330
-            // from txn status so I'm adding this here for clarity.
331
-            case '[PAYMENT_STATUS]':
332
-            case '[TXN_STATUS]':
333
-                $status = $transaction->pretty_status();
334
-                return ! empty($status) ? $status : esc_html__('Unknown', 'event_espresso');
335
-
336
-            case '[TXN_STATUS_ID]':
337
-                return $transaction->status_ID();
338
-
339
-            case '[PAYMENT_GATEWAY]':
340
-                return $this->_get_payment_gateway($transaction);
341
-
342
-            case '[AMOUNT_PAID]':
343
-                return $payment instanceof EE_Payment
344
-                    ? EEH_Template::format_currency($payment->amount())
345
-                    : EEH_Template::format_currency(0);
346
-
347
-            case '[LAST_AMOUNT_PAID]':
348
-                $last_payment = $transaction->last_payment();
349
-                return $last_payment instanceof EE_Payment
350
-                    ? EEH_Template::format_currency($last_payment->amount())
351
-                    : EEH_Template::format_currency(0);
352
-
353
-            case '[TOTAL_AMOUNT_PAID]':
354
-                return EEH_Template::format_currency($transaction->paid());
355
-
356
-            case '[TOTAL_OWING]':
357
-                $total_owing = $transaction->remaining();
358
-                return EEH_Template::format_currency($total_owing);
359
-
360
-            case '[TXN_SUBTOTAL]':
361
-                return EEH_Template::format_currency($this->_get_subtotal());
362
-
363
-            case '[TXN_TAX_SUBTOTAL]':
364
-                return EEH_Template::format_currency($this->_get_subtotal(true));
365
-
366
-            case '[TKT_QTY_PURCHASED]':
367
-            case '[TXN_TOTAL_TICKETS]':
368
-                return $this->_data->total_ticket_count;
369
-
370
-            case '[TRANSACTION_ADMIN_URL]':
371
-                require_once EE_CORE . 'admin/EE_Admin_Page.core.php';
372
-                $query_args = [
373
-                    'page'   => 'espresso_transactions',
374
-                    'action' => 'view_transaction',
375
-                    'TXN_ID' => $transaction->ID(),
376
-                ];
377
-                return EE_Admin_Page::add_query_args_and_nonce($query_args, admin_url('admin.php'));
378
-
379
-            case strpos($shortcode, '[RECEIPT_URL') !== false :
380
-                // get primary_registration
381
-                $reg = $this->_data->primary_reg_obj;
382
-                if (! $reg instanceof EE_Registration) {
383
-                    return '';
384
-                }
385
-                // any attributes?
386
-                $attrs = $this->_get_shortcode_attrs($shortcode);
387
-                // downloading PDF or HTML?
388
-                $messenger = isset($attrs['download']) ? 'pdf' : 'html';
389
-                return $reg->receipt_url($messenger);
390
-
391
-            case '[INVOICE_RECEIPT_SWITCHER_URL]':
392
-                return $this->_get_invoice_receipt_switcher(false);
393
-
394
-            case '[INVOICE_RECEIPT_SWITCHER_BUTTON]':
395
-                return $this->_get_invoice_receipt_switcher();
396
-
397
-            case '[LAST_PAYMENT_TRANSACTION_ID]':
398
-                $id      = '';
399
-                $payment = $payment instanceof EE_Payment && $payment->ID() !== 0
400
-                    ? $payment
401
-                    : $transaction->last_payment();
402
-                if ($payment instanceof EE_Payment) {
403
-                    $id = $payment->txn_id_chq_nmbr();
404
-                }
405
-                return $id;
406
-        }
407
-
408
-
409
-        if (strpos($shortcode, '[OWING_STATUS_MESSAGE_*') !== false) {
410
-            return $this->_get_custom_total_owing($shortcode);
411
-        }
412
-        if (strpos($shortcode, '[INVOICE_PAYEE_TAX_NUMBER_*') !== false) {
413
-            return $this->_get_invoice_payee_tax_number($shortcode);
414
-        }
415
-        if (strpos($shortcode, '[PAYMENT_LINK_IF_NEEDED_*') !== false) {
416
-            return $this->_get_payment_link_if_needed($shortcode);
417
-        }
418
-        if (strpos($shortcode, '[PAYMENT_DUE_DATE_*') !== false) {
419
-            return $this->_get_payment_due_date($shortcode, $transaction);
420
-        }
421
-        return '';
422
-    }
423
-
424
-
425
-    /**
426
-     * parser for the [OWING_STATUS_MESSAGE_*] attribute type shortcode
427
-     *
428
-     * @param string $shortcode the incoming shortcode
429
-     * @return string parsed.
430
-     * @throws EE_Error
431
-     * @throws ReflectionException
432
-     * @since 4.5.0
433
-     */
434
-    private function _get_custom_total_owing($shortcode)
435
-    {
436
-        $valid_shortcodes = ['transaction'];
437
-        $attrs            = $this->_get_shortcode_attrs($shortcode);
438
-        // ensure default is set.
439
-        $addressee   = $this->_data instanceof EE_Messages_Addressee ? $this->_data : null;
440
-        $total_owing = $addressee instanceof EE_Messages_Addressee && $addressee->txn instanceof EE_Transaction
441
-            ? $addressee->txn->remaining()
442
-            : 0;
443
-        if ($total_owing > 0) {
444
-            $owing_content = ! empty($attrs['still_owing'])
445
-                ? $attrs['still_owing']
446
-                : sprintf(
447
-                    esc_html__('%sPlease make a payment.%s', 'event_espresso'),
448
-                    '<a href="[PAYMENT_URL]" class="noPrint">',
449
-                    '</a>'
450
-                );
451
-            $owing_content = $this->_shortcode_helper->parse_message_template(
452
-                $owing_content,
453
-                $addressee,
454
-                $valid_shortcodes,
455
-                $this->_message_type,
456
-                $this->_messenger,
457
-                $this->_message
458
-            );
459
-        } else {
460
-            $owing_content = ! empty($attrs['none_owing']) ? $attrs['none_owing'] : '';
461
-        }
462
-        return $owing_content;
463
-    }
464
-
465
-
466
-    /**
467
-     * @param EE_Transaction $transaction
468
-     * @return string
469
-     * @throws EE_Error
470
-     * @throws ReflectionException
471
-     */
472
-    private function _get_payment_gateway($transaction)
473
-    {
474
-        $payment_method = $transaction instanceof EE_Transaction ? $transaction->payment_method() : null;
475
-        return $payment_method instanceof EE_Payment_Method ? $payment_method->name() : '';
476
-    }
477
-
478
-
479
-    /**
480
-     * This retrieves a logo to be used for the invoice from whatever is set on the invoice logo settings page.  If its
481
-     * not present then the organization logo is used if its found (set on the organization settings page).
482
-     *
483
-     * @param bool $img_tags TRUE means to return with the img tag wrappers.  False just returns the url to the image.
484
-     * @return string url or html
485
-     * @throws EE_Error
486
-     * @throws InvalidArgumentException
487
-     * @throws InvalidDataTypeException
488
-     * @throws InvalidInterfaceException
489
-     * @throws ReflectionException
490
-     * @since 4.5.0
491
-     */
492
-    private function _get_invoice_logo(bool $img_tags = false): string
493
-    {
494
-        $invoice_logo_url = '';
495
-        // try to get the invoice payment method's logo for this transaction image first
496
-        $payment_method = $this->_get_invoice_payment_method();
497
-        if ($payment_method instanceof EE_Payment_Method) {
498
-            $invoice_logo_url = $payment_method->get_extra_meta('pdf_logo_image', true);
499
-        }
500
-        if (empty($invoice_logo_url)) {
501
-            $invoice_logo_url = EE_Registry::instance()->CFG->organization->logo_url;
502
-        }
503
-        if (empty($invoice_logo_url)) {
504
-            return '';
505
-        }
506
-        if (! $img_tags) {
507
-            return $invoice_logo_url;
508
-        }
509
-        $invoice_logo_url = esc_url_raw($invoice_logo_url);
510
-        // image tags have been requested.
511
-        $image_size       = @getimagesize($invoice_logo_url);
512
-        $image_width_attr = '';
513
-        // if image is wider than 300px, set the width to 300
514
-        if ($image_size !== false) {
515
-            $image_width      = min($image_size[0], 300);
516
-            $image_width      = esc_attr($image_width);
517
-            $image_width_attr = " width='$image_width'";
518
-        }
519
-        return '<img class="logo screen" src="' . $invoice_logo_url . '"' . $image_width_attr . ' alt="logo" />';
520
-    }
521
-
522
-
523
-    /**
524
-     * Used to retrieve the appropriate content for the invoice payee name shortcode
525
-     *
526
-     * @return string
527
-     * @throws EE_Error
528
-     * @throws InvalidArgumentException
529
-     * @throws InvalidDataTypeException
530
-     * @throws InvalidInterfaceException
531
-     * @throws ReflectionException
532
-     * @since 4.5.0
533
-     */
534
-    private function _get_invoice_payee_name()
535
-    {
536
-        $payment_method = $this->_get_invoice_payment_method();
537
-        $payee_name = $payment_method instanceof EE_Payment_Method
538
-            ? $payment_method->get_extra_meta('pdf_payee_name', true)
539
-            : null;
540
-        return empty($payee_name) ? EE_Registry::instance()->CFG->organization->get_pretty('name') : $payee_name;
541
-    }
542
-
543
-
544
-    /**
545
-     * gets the default invoice payment method, but has a filter so it can be overridden
546
-     *
547
-     * @return EE_Payment_Method|null
548
-     * @throws EE_Error
549
-     * @throws InvalidArgumentException
550
-     * @throws InvalidDataTypeException
551
-     * @throws InvalidInterfaceException
552
-     * @throws ReflectionException
553
-     */
554
-    private function _get_invoice_payment_method()
555
-    {
556
-        if (! $this->_invoice_pm instanceof EE_Payment_Method) {
557
-            $transaction = $this->_data->txn instanceof EE_Transaction ? $this->_data->txn : null;
558
-            $transaction = ! $transaction instanceof EE_Transaction
559
-                && is_array($this->_extra_data)
560
-                && isset($this->_extra_data['data'])
561
-                && $this->_extra_data['data'] instanceof EE_Messages_Addressee
562
-                    ? $this->_extra_data['data']->txn
563
-                    : $transaction;
564
-            // get the invoice payment method, and remember it for the next call too
565
-            $this->_invoice_pm = apply_filters(
566
-                'FHEE__EE_Transaction_Shortcodes__get_payment_method__default',
567
-                EEM_Payment_Method::instance()->get_one_of_type('Invoice'),
568
-                $transaction
569
-            );
570
-        }
571
-        return $this->_invoice_pm;
572
-    }
573
-
574
-
575
-    /**
576
-     * Used to retrieve the appropriate content for the invoice payee email shortcode
577
-     *
578
-     * @return string
579
-     * @throws EE_Error
580
-     * @throws InvalidArgumentException
581
-     * @throws InvalidDataTypeException
582
-     * @throws InvalidInterfaceException
583
-     * @throws ReflectionException
584
-     * @since 4.5.0
585
-     */
586
-    private function _get_invoice_payee_email()
587
-    {
588
-        $payment_method = $this->_get_invoice_payment_method();
589
-        $payee_email    = $payment_method instanceof EE_Payment_Method
590
-            ? $payment_method->get_extra_meta('pdf_payee_email', true)
591
-            : null;
592
-        return empty($payee_email)
593
-            ? EE_Registry::instance()->CFG->organization->get_pretty('email')
594
-            : $payee_email;
595
-    }
596
-
597
-
598
-    /**
599
-     * Used to retrieve the appropriate content for the invoice payee tax number shortcode
600
-     *
601
-     * @param string $shortcode
602
-     * @return string
603
-     * @throws EE_Error
604
-     * @throws InvalidArgumentException
605
-     * @throws InvalidDataTypeException
606
-     * @throws InvalidInterfaceException
607
-     * @throws ReflectionException
608
-     * @since 4.5.0
609
-     */
610
-    private function _get_invoice_payee_tax_number($shortcode)
611
-    {
612
-        $payee_tax_number = null;
613
-        $payment_method   = $this->_get_invoice_payment_method();
614
-        if ($payment_method instanceof EE_Payment_Method) {
615
-            $payee_tax_number = $payment_method->get_extra_meta('pdf_payee_tax_number', true);
616
-        }
617
-        $payee_tax_number = empty($payee_tax_number) ? EE_Registry::instance()->CFG->organization->vat
618
-            : $payee_tax_number;
619
-        if (empty($payee_tax_number)) {
620
-            return '';
621
-        }
622
-        // any attributes?
623
-        $attrs = $this->_get_shortcode_attrs($shortcode);
624
-        // prefix?
625
-        $prefix = $attrs['prefix'] ?? esc_html__('VAT/Tax Number: ', 'event_espresso');
626
-        return $prefix . $payee_tax_number;
627
-    }
628
-
629
-
630
-    /**
631
-     * Used to retrieve the appropriate content for the invoice payee address shortcode.
632
-     *
633
-     * @return string
634
-     * @throws EE_Error
635
-     * @throws InvalidArgumentException
636
-     * @throws ReflectionException
637
-     * @throws InvalidDataTypeException
638
-     * @throws InvalidInterfaceException
639
-     * @since 4.5.0
640
-     */
641
-    private function _get_invoice_payee_address()
642
-    {
643
-        $payee_address  = null;
644
-        $payment_method = $this->_get_invoice_payment_method();
645
-        if ($payment_method instanceof EE_Payment_Method) {
646
-            $payee_address = $payment_method->get_extra_meta('pdf_payee_address', true);
647
-        }
648
-        if (empty($payee_address)) {
649
-            $organization  = EE_Registry::instance()->CFG->organization;
650
-            $payee_address = $organization->get_pretty('address_1') . '<br>';
651
-            $payee_address .= ! empty($organization->address_2)
652
-                ? $organization->get_pretty('address_2') . '<br>'
653
-                : '';
654
-            $payee_address .= $organization->get_pretty('city') . '<br>';
655
-            // state
656
-            $state         = EE_Registry::instance()->load_model('State')->get_one_by_ID($organization->STA_ID);
657
-            $payee_address .= $state instanceof EE_State ? $state->name() : '';
658
-            // Country
659
-            $payee_address .= ! empty($organization->CNT_ISO) ? ', ' . $organization->CNT_ISO . '<br>' : '';
660
-            $payee_address .= ! empty($organization->zip) ? $organization->zip : '';
661
-        }
662
-        return $payee_address;
663
-    }
664
-
665
-
666
-    /**
667
-     * Used to retrieve the appropriate content for the invoice payment instructions shortcode.
668
-     *
669
-     * @return string
670
-     * @throws EE_Error
671
-     * @throws InvalidArgumentException
672
-     * @throws InvalidDataTypeException
673
-     * @throws InvalidInterfaceException
674
-     * @throws ReflectionException
675
-     * @since 4.5.0
676
-     */
677
-    private function _get_invoice_payment_instructions()
678
-    {
679
-        $payment_method = $this->_get_invoice_payment_method();
680
-        return ($payment_method instanceof EE_Payment_Method)
681
-            ? $payment_method->get_extra_meta('pdf_instructions', true)
682
-            : '';
683
-    }
684
-
685
-
686
-    /**
687
-     * get invoice/receipt switch button or url.
688
-     *
689
-     * @param bool $button true (default) returns the html for a button, false just returns the url.
690
-     * @return string
691
-     */
692
-    protected function _get_invoice_receipt_switcher($button = true)
693
-    {
694
-        $reg          = $this->_data->primary_reg_obj;
695
-        $message_type = $this->_extra_data['message_type'] ?? '';
696
-        if (! $reg instanceof EE_Registration || empty($message_type)) {
697
-            return '';
698
-        }
699
-        $switch_to_invoice = ! $message_type instanceof EE_Invoice_message_type;
700
-        $switch_to_label   = $switch_to_invoice && ! $message_type instanceof EE_Receipt_message_type
701
-            ? esc_html__('View Invoice', 'event_espresso')
702
-            : esc_html__('Switch to Invoice', 'event_espresso');
703
-        $switch_to_label   =
704
-            ! $switch_to_invoice ? esc_html__('Switch to Receipt', 'event_espresso') : $switch_to_label;
705
-        $switch_to_url     = $switch_to_invoice ? $reg->invoice_url() : $reg->receipt_url();
706
-        if (! $button) {
707
-            return $switch_to_url;
708
-        }
709
-        if (! empty($switch_to_url)) {
710
-            return '
19
+	/**
20
+	 * @var EE_Payment_Method|null $_invoice_pm the invoice payment method for use in invoices etc
21
+	 */
22
+	protected ?EE_Payment_Method $_invoice_pm = null;
23
+
24
+
25
+	protected function _init_props()
26
+	{
27
+		$this->label       = esc_html__('Transaction Shortcodes', 'event_espresso');
28
+		$this->description = esc_html__('All shortcodes specific to transaction related data', 'event_espresso');
29
+		$this->_shortcodes = [
30
+			'[TXN_ID]'                          => esc_html__('The transaction id for the purchase.', 'event_espresso'),
31
+			'[PAYMENT_URL]'                     => esc_html__(
32
+				'This is a link to make a payment for the event',
33
+				'event_espresso'
34
+			),
35
+			'[PAYMENT_LINK_IF_NEEDED_*]'        => esc_html__(
36
+					'This is a special dynamic shortcode that allows one to insert a payment link conditional on there being amount owing on the transaction. Three params are available on this shortcode:',
37
+					'event_espresso'
38
+				)
39
+				. '<ul>'
40
+				. '<li>'
41
+				. sprintf(
42
+					esc_html__(
43
+						'%sclass:%s This can be used to indicate css class is given to the containing css element (default is "callout").',
44
+						'event_espresso'
45
+					),
46
+					'<strong>',
47
+					'</strong>'
48
+				)
49
+				. '</li>'
50
+				. '<li>'
51
+				. sprintf(
52
+					esc_html__(
53
+						'%scustom_text:%s This should be a sprintf format text string (with %%s for where the hyperlink tags go) that is used for the generated link text (The default is "You can %%smake a payment here »%%s.)',
54
+						'event_espresso'
55
+					),
56
+					'<strong>',
57
+					'</strong>'
58
+				)
59
+				. '</li>'
60
+				. '<li>'
61
+				. sprintf(
62
+					esc_html__(
63
+						'%scontainer_tag:%s Use this to indicate what container tag you want surrounding the payment link (default is "p").',
64
+						'event_espresso'
65
+					),
66
+					'<strong>',
67
+					'</strong>'
68
+				)
69
+				. '</li>'
70
+				. '</ul>',
71
+			'[PAYMENT_DUE_DATE_*]'              => esc_html__(
72
+					'This is a special dynamic shortcode that allows one to output a payment due date.  It will only result in a date shown if there is money owing.  Three parameters are available on this shortcode:',
73
+					'event_espresso'
74
+				)
75
+				. '<ul>'
76
+				. '<li>'
77
+				. sprintf(
78
+					esc_html__(
79
+						'%sformat:%s This is used to indicate what format the date is in.  Default is whatever is set as date formats for your website.',
80
+						'event_espresso'
81
+					),
82
+					'<strong>',
83
+					'</strong>'
84
+				)
85
+				. '</li>'
86
+				. '<li>'
87
+				. sprintf(
88
+					esc_html__(
89
+						'%sdays_until_due:%s This is the number of days form the transaction creation date that the payment is due.  Defaults to 30.',
90
+						'event_espresso'
91
+					),
92
+					'<strong>',
93
+					'</strong>'
94
+				)
95
+				. '</li>'
96
+				. '<li>'
97
+				. sprintf(
98
+					esc_html__(
99
+						'%sprefix_text:%s You can use this to indicate what text will prefix the date string.  Defaults to "Payment in full due by:"',
100
+						'event_espresso'
101
+					),
102
+					'<strong>',
103
+					'</strong>'
104
+				)
105
+				. '</li>',
106
+			'[INVOICE_LINK]'                    => esc_html__(
107
+				'This is a full html link to the invoice. Add download=true to link directly to download.',
108
+				'event_espresso'
109
+			),
110
+			'[INVOICE_URL]'                     => esc_html__(
111
+				'This is just the url for the invoice. Add download=true to link directly to download.',
112
+				'event_espresso'
113
+			),
114
+			'[INVOICE_LOGO_URL]'                => esc_html__(
115
+				'This returns the url for the logo uploaded via the invoice settings page.',
116
+				'event_espresso'
117
+			),
118
+			'[INVOICE_LOGO]'                    => esc_html__(
119
+				'This returns the logo uploaded via the invoice settings page wrapped in img_tags and with a "logo screen" classes. The image size is also set in the img tags automatically to match the uploaded logo.',
120
+				'event_espresso'
121
+			),
122
+			'[INVOICE_PAYEE_NAME]'              => esc_html__(
123
+				'This will parse to either: the value of the "Company Name" field in the invoice payment method settings; if that is blank, then the value of the Company Name in the "Your Organization Settings", if that is blank then an empty string.',
124
+				'event_espresso'
125
+			),
126
+			'[INVOICE_PAYEE_ADDRESS]'           => esc_html__(
127
+				'This will parse to either: the value of the "Company Address" field in the invoice payment method settings; if that is blank, then the value of the Company Address in the "Your Organization Settings", if that is blank then an empty string.',
128
+				'event_espresso'
129
+			),
130
+			'[INVOICE_PAYMENT_INSTRUCTIONS]'    => esc_html__(
131
+				'This will parse to the value of the "Payment Instructions" field found on the Invoice payment methods settings page',
132
+				'event_espresso'
133
+			),
134
+			'[INVOICE_PAYEE_EMAIL]'             => esc_html__(
135
+				'This will parse to either: the value of the "Company Email" field in the invoice payment method settings; if that is blank, then the value of the Company Email in the "Your Organization Settings", if that is blank then an empty string.',
136
+				'event_espresso'
137
+			),
138
+			'[INVOICE_PAYEE_TAX_NUMBER_*]'      => sprintf(
139
+				esc_html__(
140
+					'This will parse to either: the value of the "Company Tax Number" field in the invoice payment method settings; if that is blank, then the value of the Company Tax Number in the "Your Organization Settings", if that is blank then an empty string. Note this is also a special dynamic shortcode. You can use the "prefix" parameter to indicate what text you want to use as a prefix before this tax number.  It defaults to "VAT/Tax Number:". To change this prefix you do the following format for this shortcode: %1$s[INVOICE_PAYEE_TAX_NUMBER_* prefix="GST:"]%2$s and that will output: GST: 12345t56.  If you have no tax number in your settings, then no prefix will be output either.',
141
+					'event_espresso'
142
+				),
143
+				'<code>',
144
+				'</code>'
145
+			),
146
+			'[TOTAL_COST]'                      => esc_html__('The total cost for the transaction', 'event_espresso'),
147
+			'[TXN_STATUS]'                      => esc_html__(
148
+				'The transaction status for the transaction.',
149
+				'event_espresso'
150
+			),
151
+			'[TXN_STATUS_ID]'                   => esc_html__(
152
+				'The ID representing the transaction status as saved in the db.  This tends to be useful for including with css classes for styling certain statuses differently from others.',
153
+				'event_espresso'
154
+			),
155
+			'[PAYMENT_STATUS]'                  => esc_html__(
156
+				'The transaction status for the transaction. This parses to the same value as the [TXN_STATUS] shortcode and still remains here for legacy support.',
157
+				'event_espresso'
158
+			),
159
+			'[PAYMENT_GATEWAY]'                 => esc_html__(
160
+				'The payment gateway used for the transaction',
161
+				'event_espresso'
162
+			),
163
+			'[AMOUNT_PAID]'                     => esc_html__(
164
+				'The amount paid or refunded.  This will only have a value if there was a payment or refund at the time of generating the message.',
165
+				'event_espresso'
166
+			),
167
+			'[LAST_AMOUNT_PAID]'                => esc_html__(
168
+				'This is the last payment or refund made on the transaction related to the message being generated.',
169
+				'event_espresso'
170
+			),
171
+			'[TOTAL_AMOUNT_PAID]'               => esc_html__(
172
+				'This parses to the total amount paid over all payments',
173
+				'event_espresso'
174
+			),
175
+			'[TOTAL_OWING]'                     => esc_html__(
176
+				'The total owing on a transaction with no attributes.',
177
+				'event_espresso'
178
+			),
179
+			'[TXN_SUBTOTAL]'                    => esc_html__('The subtotal for all txn line items.', 'event_espresso'),
180
+			'[TXN_TAX_SUBTOTAL]'                => esc_html__('The subtotal for all tax line items.', 'event_espresso'),
181
+			'[OWING_STATUS_MESSAGE_*]'          => esc_html__(
182
+					'A dynamic shortcode for adjusting how total owing gets shown. The acceptable attributes on the shortcode are:',
183
+					'event_espresso'
184
+				)
185
+				. '<p></ul>'
186
+				. '<li><strong>still_owing</strong>:'
187
+				. esc_html__(
188
+					'If the transaction is not paid in full, then whatever is set for this attribute is shown (otherwise its just the amount owing). The default is:',
189
+					'event_espresso'
190
+				)
191
+				. sprintf(
192
+					esc_html__('%sPlease make a payment.%s', 'event_espresso'),
193
+					'<a href="[PAYMENT_URL]" class="noPrint">',
194
+					'</a>'
195
+				)
196
+				. '</li>'
197
+				.
198
+				'<li><strong>none_owing</strong>:'
199
+				. esc_html__(
200
+					'If the transaction is paid in full, then you can indicate how this gets displayed.  Note, that it defaults to just be the total owing.',
201
+					'event_espresso'
202
+				)
203
+				. '</li></ul></p>',
204
+			'[TXN_TOTAL_TICKETS]'               => esc_html__(
205
+				'The total number of all tickets purchased in a transaction',
206
+				'event_espresso'
207
+			),
208
+			'[TKT_QTY_PURCHASED]'               => sprintf(
209
+				esc_html__(
210
+					'The total number of all tickets purchased in a transaction. %1$sNOTE: This shortcode is good to use in the "[TICKET_LIST]" field but has been deprecated from all other contexts in favor of the more explicit [TXN_TOTAL_TICKETS] shortcode.%2$s',
211
+					'event_espresso'
212
+				),
213
+				'<strong>',
214
+				'</strong>'
215
+			),
216
+			'[TRANSACTION_ADMIN_URL]'           => esc_html__(
217
+				'The url to the admin page for this transaction',
218
+				'event_espresso'
219
+			),
220
+			'[RECEIPT_URL]'                     => esc_html__(
221
+				'This parses to the generated url for retrieving the receipt for the transaction. Add download=true to link directly to download.',
222
+				'event_espresso'
223
+			),
224
+			'[INVOICE_RECEIPT_SWITCHER_URL]'    => esc_html__(
225
+				'This parses to the url that will switch to the receipt if an invoice is displayed, and switch to the invoice if receipt is displayed. If a message type OTHER than invoice or receipt is displayed then this will just return the url for the invoice. If the related message type is not active  then will parse to an empty string.',
226
+				'event_espresso'
227
+			),
228
+			'[INVOICE_RECEIPT_SWITCHER_BUTTON]' => sprintf(
229
+				esc_html__(
230
+					'The same as %1$s%2$s except this returns the html for a button linked to the invoice or receipt.',
231
+					'event_espresso'
232
+				),
233
+				'<code>[INVOICE_RECEIPT_SWITCHER_URL]',
234
+				'</code>'
235
+			),
236
+			'[LAST_PAYMENT_TRANSACTION_ID]'     => esc_html__(
237
+				'This will output the value of the payment transaction id for the last payment made on the transaction. Note, if a specific payment was included for message generation, that will be used when parsing the shortcode.',
238
+				'event_espresso'
239
+			),
240
+		];
241
+	}
242
+
243
+
244
+	/**
245
+	 * @param string $shortcode the shortcode to be parsed.
246
+	 * @return string parsed shortcode
247
+	 * @throws EE_Error
248
+	 * @throws InvalidArgumentException
249
+	 * @throws ReflectionException
250
+	 * @throws InvalidDataTypeException
251
+	 * @throws InvalidInterfaceException
252
+	 */
253
+	protected function _parser($shortcode)
254
+	{
255
+		// attempt to get the transaction.  Since this is potentially used in more fields, we may have to look in the
256
+		// _extra_data for the transaction.
257
+		$transaction = $this->_data->txn instanceof EE_Transaction ? $this->_data->txn : null;
258
+		$transaction = ! $transaction instanceof EE_Transaction
259
+			&& is_array($this->_extra_data)
260
+			&& isset($this->_extra_data['data'])
261
+			&& $this->_extra_data['data'] instanceof EE_Messages_Addressee
262
+				? $this->_extra_data['data']->txn
263
+				: $transaction;
264
+		if (! $transaction instanceof EE_Transaction) {
265
+			return '';
266
+		}
267
+		// payment
268
+		$payment = $this->_data->payment instanceof EE_Payment ? $this->_data->payment : null;
269
+		$payment = ! $payment instanceof EE_Payment
270
+			&& is_array($this->_extra_data)
271
+			&& isset($this->_extra_data['data'])
272
+			&& $this->_extra_data['data'] instanceof EE_Messages_Addressee
273
+				? $this->_extra_data['data']->payment
274
+				: $payment;
275
+
276
+		switch ($shortcode) {
277
+			case '[TXN_ID]':
278
+				return $transaction->ID();
279
+
280
+			case '[PAYMENT_URL]':
281
+				$payment_url = $transaction->payment_overview_url();
282
+				return empty($payment_url)
283
+					? esc_html__('http://dummypaymenturlforpreview.com', 'event_espresso')
284
+					: $payment_url;
285
+
286
+			case strpos($shortcode, '[INVOICE_LINK') !== false :
287
+				// any attributes?
288
+				$attrs = $this->_get_shortcode_attrs($shortcode);
289
+				// downloading PDF or HTML?
290
+				$messenger = isset($attrs['download']) ? 'pdf' : 'html';
291
+				$invoice_url = $transaction->invoice_url($messenger);
292
+				$invoice_url = empty($invoice_url) ? 'http://dummyinvoicelinksforpreview.com' : $invoice_url;
293
+				return sprintf(
294
+					esc_html__('%sClick here for Invoice%s', 'event_espresso'),
295
+					'<a href="' . $invoice_url . '">',
296
+					'</a>'
297
+				);
298
+
299
+			case strpos($shortcode, '[INVOICE_URL') !== false :
300
+				// any attributes?
301
+				$attrs = $this->_get_shortcode_attrs($shortcode);
302
+				// downloading PDF or HTML?
303
+				$messenger = isset($attrs['download']) ? 'pdf' : 'html';
304
+				$invoice_url = $transaction->invoice_url($messenger);
305
+				return empty($invoice_url) ? 'http://dummyinvoicelinksforpreview.com' : $invoice_url;
306
+
307
+			case '[INVOICE_LOGO_URL]':
308
+				return $this->_get_invoice_logo();
309
+
310
+			case '[INVOICE_LOGO]':
311
+				return $this->_get_invoice_logo(true);
312
+
313
+			case '[INVOICE_PAYEE_NAME]':
314
+				return $this->_get_invoice_payee_name();
315
+
316
+			case '[INVOICE_PAYEE_ADDRESS]':
317
+				return $this->_get_invoice_payee_address();
318
+
319
+			case '[INVOICE_PAYMENT_INSTRUCTIONS]':
320
+				return $this->_get_invoice_payment_instructions();
321
+
322
+			case '[INVOICE_PAYEE_EMAIL]':
323
+				return $this->_get_invoice_payee_email();
324
+
325
+			case '[TOTAL_COST]':
326
+				$total = $transaction->total();
327
+				return ! empty($total) ? EEH_Template::format_currency($total) : '';
328
+
329
+			// note the [payment_status] shortcode is kind of misleading because payment status might be different
330
+			// from txn status so I'm adding this here for clarity.
331
+			case '[PAYMENT_STATUS]':
332
+			case '[TXN_STATUS]':
333
+				$status = $transaction->pretty_status();
334
+				return ! empty($status) ? $status : esc_html__('Unknown', 'event_espresso');
335
+
336
+			case '[TXN_STATUS_ID]':
337
+				return $transaction->status_ID();
338
+
339
+			case '[PAYMENT_GATEWAY]':
340
+				return $this->_get_payment_gateway($transaction);
341
+
342
+			case '[AMOUNT_PAID]':
343
+				return $payment instanceof EE_Payment
344
+					? EEH_Template::format_currency($payment->amount())
345
+					: EEH_Template::format_currency(0);
346
+
347
+			case '[LAST_AMOUNT_PAID]':
348
+				$last_payment = $transaction->last_payment();
349
+				return $last_payment instanceof EE_Payment
350
+					? EEH_Template::format_currency($last_payment->amount())
351
+					: EEH_Template::format_currency(0);
352
+
353
+			case '[TOTAL_AMOUNT_PAID]':
354
+				return EEH_Template::format_currency($transaction->paid());
355
+
356
+			case '[TOTAL_OWING]':
357
+				$total_owing = $transaction->remaining();
358
+				return EEH_Template::format_currency($total_owing);
359
+
360
+			case '[TXN_SUBTOTAL]':
361
+				return EEH_Template::format_currency($this->_get_subtotal());
362
+
363
+			case '[TXN_TAX_SUBTOTAL]':
364
+				return EEH_Template::format_currency($this->_get_subtotal(true));
365
+
366
+			case '[TKT_QTY_PURCHASED]':
367
+			case '[TXN_TOTAL_TICKETS]':
368
+				return $this->_data->total_ticket_count;
369
+
370
+			case '[TRANSACTION_ADMIN_URL]':
371
+				require_once EE_CORE . 'admin/EE_Admin_Page.core.php';
372
+				$query_args = [
373
+					'page'   => 'espresso_transactions',
374
+					'action' => 'view_transaction',
375
+					'TXN_ID' => $transaction->ID(),
376
+				];
377
+				return EE_Admin_Page::add_query_args_and_nonce($query_args, admin_url('admin.php'));
378
+
379
+			case strpos($shortcode, '[RECEIPT_URL') !== false :
380
+				// get primary_registration
381
+				$reg = $this->_data->primary_reg_obj;
382
+				if (! $reg instanceof EE_Registration) {
383
+					return '';
384
+				}
385
+				// any attributes?
386
+				$attrs = $this->_get_shortcode_attrs($shortcode);
387
+				// downloading PDF or HTML?
388
+				$messenger = isset($attrs['download']) ? 'pdf' : 'html';
389
+				return $reg->receipt_url($messenger);
390
+
391
+			case '[INVOICE_RECEIPT_SWITCHER_URL]':
392
+				return $this->_get_invoice_receipt_switcher(false);
393
+
394
+			case '[INVOICE_RECEIPT_SWITCHER_BUTTON]':
395
+				return $this->_get_invoice_receipt_switcher();
396
+
397
+			case '[LAST_PAYMENT_TRANSACTION_ID]':
398
+				$id      = '';
399
+				$payment = $payment instanceof EE_Payment && $payment->ID() !== 0
400
+					? $payment
401
+					: $transaction->last_payment();
402
+				if ($payment instanceof EE_Payment) {
403
+					$id = $payment->txn_id_chq_nmbr();
404
+				}
405
+				return $id;
406
+		}
407
+
408
+
409
+		if (strpos($shortcode, '[OWING_STATUS_MESSAGE_*') !== false) {
410
+			return $this->_get_custom_total_owing($shortcode);
411
+		}
412
+		if (strpos($shortcode, '[INVOICE_PAYEE_TAX_NUMBER_*') !== false) {
413
+			return $this->_get_invoice_payee_tax_number($shortcode);
414
+		}
415
+		if (strpos($shortcode, '[PAYMENT_LINK_IF_NEEDED_*') !== false) {
416
+			return $this->_get_payment_link_if_needed($shortcode);
417
+		}
418
+		if (strpos($shortcode, '[PAYMENT_DUE_DATE_*') !== false) {
419
+			return $this->_get_payment_due_date($shortcode, $transaction);
420
+		}
421
+		return '';
422
+	}
423
+
424
+
425
+	/**
426
+	 * parser for the [OWING_STATUS_MESSAGE_*] attribute type shortcode
427
+	 *
428
+	 * @param string $shortcode the incoming shortcode
429
+	 * @return string parsed.
430
+	 * @throws EE_Error
431
+	 * @throws ReflectionException
432
+	 * @since 4.5.0
433
+	 */
434
+	private function _get_custom_total_owing($shortcode)
435
+	{
436
+		$valid_shortcodes = ['transaction'];
437
+		$attrs            = $this->_get_shortcode_attrs($shortcode);
438
+		// ensure default is set.
439
+		$addressee   = $this->_data instanceof EE_Messages_Addressee ? $this->_data : null;
440
+		$total_owing = $addressee instanceof EE_Messages_Addressee && $addressee->txn instanceof EE_Transaction
441
+			? $addressee->txn->remaining()
442
+			: 0;
443
+		if ($total_owing > 0) {
444
+			$owing_content = ! empty($attrs['still_owing'])
445
+				? $attrs['still_owing']
446
+				: sprintf(
447
+					esc_html__('%sPlease make a payment.%s', 'event_espresso'),
448
+					'<a href="[PAYMENT_URL]" class="noPrint">',
449
+					'</a>'
450
+				);
451
+			$owing_content = $this->_shortcode_helper->parse_message_template(
452
+				$owing_content,
453
+				$addressee,
454
+				$valid_shortcodes,
455
+				$this->_message_type,
456
+				$this->_messenger,
457
+				$this->_message
458
+			);
459
+		} else {
460
+			$owing_content = ! empty($attrs['none_owing']) ? $attrs['none_owing'] : '';
461
+		}
462
+		return $owing_content;
463
+	}
464
+
465
+
466
+	/**
467
+	 * @param EE_Transaction $transaction
468
+	 * @return string
469
+	 * @throws EE_Error
470
+	 * @throws ReflectionException
471
+	 */
472
+	private function _get_payment_gateway($transaction)
473
+	{
474
+		$payment_method = $transaction instanceof EE_Transaction ? $transaction->payment_method() : null;
475
+		return $payment_method instanceof EE_Payment_Method ? $payment_method->name() : '';
476
+	}
477
+
478
+
479
+	/**
480
+	 * This retrieves a logo to be used for the invoice from whatever is set on the invoice logo settings page.  If its
481
+	 * not present then the organization logo is used if its found (set on the organization settings page).
482
+	 *
483
+	 * @param bool $img_tags TRUE means to return with the img tag wrappers.  False just returns the url to the image.
484
+	 * @return string url or html
485
+	 * @throws EE_Error
486
+	 * @throws InvalidArgumentException
487
+	 * @throws InvalidDataTypeException
488
+	 * @throws InvalidInterfaceException
489
+	 * @throws ReflectionException
490
+	 * @since 4.5.0
491
+	 */
492
+	private function _get_invoice_logo(bool $img_tags = false): string
493
+	{
494
+		$invoice_logo_url = '';
495
+		// try to get the invoice payment method's logo for this transaction image first
496
+		$payment_method = $this->_get_invoice_payment_method();
497
+		if ($payment_method instanceof EE_Payment_Method) {
498
+			$invoice_logo_url = $payment_method->get_extra_meta('pdf_logo_image', true);
499
+		}
500
+		if (empty($invoice_logo_url)) {
501
+			$invoice_logo_url = EE_Registry::instance()->CFG->organization->logo_url;
502
+		}
503
+		if (empty($invoice_logo_url)) {
504
+			return '';
505
+		}
506
+		if (! $img_tags) {
507
+			return $invoice_logo_url;
508
+		}
509
+		$invoice_logo_url = esc_url_raw($invoice_logo_url);
510
+		// image tags have been requested.
511
+		$image_size       = @getimagesize($invoice_logo_url);
512
+		$image_width_attr = '';
513
+		// if image is wider than 300px, set the width to 300
514
+		if ($image_size !== false) {
515
+			$image_width      = min($image_size[0], 300);
516
+			$image_width      = esc_attr($image_width);
517
+			$image_width_attr = " width='$image_width'";
518
+		}
519
+		return '<img class="logo screen" src="' . $invoice_logo_url . '"' . $image_width_attr . ' alt="logo" />';
520
+	}
521
+
522
+
523
+	/**
524
+	 * Used to retrieve the appropriate content for the invoice payee name shortcode
525
+	 *
526
+	 * @return string
527
+	 * @throws EE_Error
528
+	 * @throws InvalidArgumentException
529
+	 * @throws InvalidDataTypeException
530
+	 * @throws InvalidInterfaceException
531
+	 * @throws ReflectionException
532
+	 * @since 4.5.0
533
+	 */
534
+	private function _get_invoice_payee_name()
535
+	{
536
+		$payment_method = $this->_get_invoice_payment_method();
537
+		$payee_name = $payment_method instanceof EE_Payment_Method
538
+			? $payment_method->get_extra_meta('pdf_payee_name', true)
539
+			: null;
540
+		return empty($payee_name) ? EE_Registry::instance()->CFG->organization->get_pretty('name') : $payee_name;
541
+	}
542
+
543
+
544
+	/**
545
+	 * gets the default invoice payment method, but has a filter so it can be overridden
546
+	 *
547
+	 * @return EE_Payment_Method|null
548
+	 * @throws EE_Error
549
+	 * @throws InvalidArgumentException
550
+	 * @throws InvalidDataTypeException
551
+	 * @throws InvalidInterfaceException
552
+	 * @throws ReflectionException
553
+	 */
554
+	private function _get_invoice_payment_method()
555
+	{
556
+		if (! $this->_invoice_pm instanceof EE_Payment_Method) {
557
+			$transaction = $this->_data->txn instanceof EE_Transaction ? $this->_data->txn : null;
558
+			$transaction = ! $transaction instanceof EE_Transaction
559
+				&& is_array($this->_extra_data)
560
+				&& isset($this->_extra_data['data'])
561
+				&& $this->_extra_data['data'] instanceof EE_Messages_Addressee
562
+					? $this->_extra_data['data']->txn
563
+					: $transaction;
564
+			// get the invoice payment method, and remember it for the next call too
565
+			$this->_invoice_pm = apply_filters(
566
+				'FHEE__EE_Transaction_Shortcodes__get_payment_method__default',
567
+				EEM_Payment_Method::instance()->get_one_of_type('Invoice'),
568
+				$transaction
569
+			);
570
+		}
571
+		return $this->_invoice_pm;
572
+	}
573
+
574
+
575
+	/**
576
+	 * Used to retrieve the appropriate content for the invoice payee email shortcode
577
+	 *
578
+	 * @return string
579
+	 * @throws EE_Error
580
+	 * @throws InvalidArgumentException
581
+	 * @throws InvalidDataTypeException
582
+	 * @throws InvalidInterfaceException
583
+	 * @throws ReflectionException
584
+	 * @since 4.5.0
585
+	 */
586
+	private function _get_invoice_payee_email()
587
+	{
588
+		$payment_method = $this->_get_invoice_payment_method();
589
+		$payee_email    = $payment_method instanceof EE_Payment_Method
590
+			? $payment_method->get_extra_meta('pdf_payee_email', true)
591
+			: null;
592
+		return empty($payee_email)
593
+			? EE_Registry::instance()->CFG->organization->get_pretty('email')
594
+			: $payee_email;
595
+	}
596
+
597
+
598
+	/**
599
+	 * Used to retrieve the appropriate content for the invoice payee tax number shortcode
600
+	 *
601
+	 * @param string $shortcode
602
+	 * @return string
603
+	 * @throws EE_Error
604
+	 * @throws InvalidArgumentException
605
+	 * @throws InvalidDataTypeException
606
+	 * @throws InvalidInterfaceException
607
+	 * @throws ReflectionException
608
+	 * @since 4.5.0
609
+	 */
610
+	private function _get_invoice_payee_tax_number($shortcode)
611
+	{
612
+		$payee_tax_number = null;
613
+		$payment_method   = $this->_get_invoice_payment_method();
614
+		if ($payment_method instanceof EE_Payment_Method) {
615
+			$payee_tax_number = $payment_method->get_extra_meta('pdf_payee_tax_number', true);
616
+		}
617
+		$payee_tax_number = empty($payee_tax_number) ? EE_Registry::instance()->CFG->organization->vat
618
+			: $payee_tax_number;
619
+		if (empty($payee_tax_number)) {
620
+			return '';
621
+		}
622
+		// any attributes?
623
+		$attrs = $this->_get_shortcode_attrs($shortcode);
624
+		// prefix?
625
+		$prefix = $attrs['prefix'] ?? esc_html__('VAT/Tax Number: ', 'event_espresso');
626
+		return $prefix . $payee_tax_number;
627
+	}
628
+
629
+
630
+	/**
631
+	 * Used to retrieve the appropriate content for the invoice payee address shortcode.
632
+	 *
633
+	 * @return string
634
+	 * @throws EE_Error
635
+	 * @throws InvalidArgumentException
636
+	 * @throws ReflectionException
637
+	 * @throws InvalidDataTypeException
638
+	 * @throws InvalidInterfaceException
639
+	 * @since 4.5.0
640
+	 */
641
+	private function _get_invoice_payee_address()
642
+	{
643
+		$payee_address  = null;
644
+		$payment_method = $this->_get_invoice_payment_method();
645
+		if ($payment_method instanceof EE_Payment_Method) {
646
+			$payee_address = $payment_method->get_extra_meta('pdf_payee_address', true);
647
+		}
648
+		if (empty($payee_address)) {
649
+			$organization  = EE_Registry::instance()->CFG->organization;
650
+			$payee_address = $organization->get_pretty('address_1') . '<br>';
651
+			$payee_address .= ! empty($organization->address_2)
652
+				? $organization->get_pretty('address_2') . '<br>'
653
+				: '';
654
+			$payee_address .= $organization->get_pretty('city') . '<br>';
655
+			// state
656
+			$state         = EE_Registry::instance()->load_model('State')->get_one_by_ID($organization->STA_ID);
657
+			$payee_address .= $state instanceof EE_State ? $state->name() : '';
658
+			// Country
659
+			$payee_address .= ! empty($organization->CNT_ISO) ? ', ' . $organization->CNT_ISO . '<br>' : '';
660
+			$payee_address .= ! empty($organization->zip) ? $organization->zip : '';
661
+		}
662
+		return $payee_address;
663
+	}
664
+
665
+
666
+	/**
667
+	 * Used to retrieve the appropriate content for the invoice payment instructions shortcode.
668
+	 *
669
+	 * @return string
670
+	 * @throws EE_Error
671
+	 * @throws InvalidArgumentException
672
+	 * @throws InvalidDataTypeException
673
+	 * @throws InvalidInterfaceException
674
+	 * @throws ReflectionException
675
+	 * @since 4.5.0
676
+	 */
677
+	private function _get_invoice_payment_instructions()
678
+	{
679
+		$payment_method = $this->_get_invoice_payment_method();
680
+		return ($payment_method instanceof EE_Payment_Method)
681
+			? $payment_method->get_extra_meta('pdf_instructions', true)
682
+			: '';
683
+	}
684
+
685
+
686
+	/**
687
+	 * get invoice/receipt switch button or url.
688
+	 *
689
+	 * @param bool $button true (default) returns the html for a button, false just returns the url.
690
+	 * @return string
691
+	 */
692
+	protected function _get_invoice_receipt_switcher($button = true)
693
+	{
694
+		$reg          = $this->_data->primary_reg_obj;
695
+		$message_type = $this->_extra_data['message_type'] ?? '';
696
+		if (! $reg instanceof EE_Registration || empty($message_type)) {
697
+			return '';
698
+		}
699
+		$switch_to_invoice = ! $message_type instanceof EE_Invoice_message_type;
700
+		$switch_to_label   = $switch_to_invoice && ! $message_type instanceof EE_Receipt_message_type
701
+			? esc_html__('View Invoice', 'event_espresso')
702
+			: esc_html__('Switch to Invoice', 'event_espresso');
703
+		$switch_to_label   =
704
+			! $switch_to_invoice ? esc_html__('Switch to Receipt', 'event_espresso') : $switch_to_label;
705
+		$switch_to_url     = $switch_to_invoice ? $reg->invoice_url() : $reg->receipt_url();
706
+		if (! $button) {
707
+			return $switch_to_url;
708
+		}
709
+		if (! empty($switch_to_url)) {
710
+			return '
711 711
 	<form method="post" action="' . $switch_to_url . '" >
712 712
 		<input class="print_button" type="submit" value="' . $switch_to_label . '" />
713 713
 	</form>
714 714
 			';
715
-        }
716
-        return '';
717
-    }
718
-
719
-
720
-    /**
721
-     * This returns a subtotal.
722
-     *
723
-     * @param bool $tax if true then return the subtotal for tax otherwise return subtotal.
724
-     * @return int
725
-     * @throws EE_Error
726
-     * @throws ReflectionException
727
-     */
728
-    private function _get_subtotal($tax = false)
729
-    {
730
-        $grand_total = $this->_data->grand_total_line_item ?? null;
731
-        if (! $grand_total instanceof EE_Line_Item) {
732
-            return 0;
733
-        }
734
-        return $tax ? $grand_total->get_total_tax() : $grand_total->get_items_total();
735
-    }
736
-
737
-
738
-    /**
739
-     * parser for the [PAYMENT_LINK_IF_NEEDED_*] attribute type shortcode
740
-     *
741
-     * @param string $shortcode the incoming shortcode
742
-     * @return string parsed.
743
-     * @throws EE_Error
744
-     * @throws ReflectionException
745
-     * @since 4.7.0
746
-     */
747
-    private function _get_payment_link_if_needed($shortcode)
748
-    {
749
-        $valid_shortcodes = ['transaction'];
750
-        $attrs            = $this->_get_shortcode_attrs($shortcode);
751
-        // ensure default is set.
752
-        $addressee   = $this->_data instanceof EE_Messages_Addressee ? $this->_data : null;
753
-        $total_owing = $addressee instanceof EE_Messages_Addressee && $addressee->txn instanceof EE_Transaction
754
-            ? $addressee->txn->remaining()
755
-            : 0;
756
-        if ($total_owing > 0) {
757
-            $class         = $attrs['class'] ?? 'callout';
758
-            $custom_text   =
759
-                $attrs['custom_text'] ?? 'You can %smake a payment here »%s.';
760
-            $container_tag = $attrs['container_tag'] ?? 'p';
761
-            $opening_tag   = ! empty($container_tag) ? '<' . $container_tag : '';
762
-            $opening_tag   .= ! empty($opening_tag) && ! empty($class) ? ' class="' . $class . '"' : $opening_tag;
763
-            $opening_tag   .= ! empty($opening_tag) ? '>' : $opening_tag;
764
-            $closing_tag   = ! empty($container_tag) ? '</' . $container_tag . '>' : '';
765
-            $content       = $opening_tag . sprintf($custom_text, '<a href="[PAYMENT_URL]">', '</a>') . $closing_tag;
766
-            // we need to re-run this string through the parser to catch any shortcodes that are in it.
767
-            $owing_content = $this->_shortcode_helper->parse_message_template(
768
-                $content,
769
-                $addressee,
770
-                $valid_shortcodes,
771
-                $this->_message_type,
772
-                $this->_messenger,
773
-                $this->_message
774
-            );
775
-        } else {
776
-            return '';
777
-        }
778
-        return $owing_content;
779
-    }
780
-
781
-
782
-    /**
783
-     * Parser for the [PAYMENT_DUE_DATE_*] attribute type shortcode
784
-     *
785
-     * @param string         $shortcode The shortcode being parsed.
786
-     * @param EE_Transaction $transaction
787
-     * @return string
788
-     * @throws EE_Error
789
-     * @throws ReflectionException
790
-     * @since 4.8.28.rc.011
791
-     */
792
-    protected function _get_payment_due_date($shortcode, EE_Transaction $transaction)
793
-    {
794
-        // if transaction is paid in full then we can just return an empty string
795
-        if ($transaction->remaining() == 0) {
796
-            return '';
797
-        }
798
-        $attrs               = $this->_get_shortcode_attrs($shortcode);
799
-        $format              = $attrs['format'] ?? get_option('date_format');
800
-        $days_until_due      = isset($attrs['days_until_due']) ? (int) $attrs['days_until_due'] : 30;
801
-        $prefix_text         = $attrs['prefix_text'] ?? esc_html__('Payment in full due by: ', 'event_espresso');
802
-        $transaction_created = $transaction->get_DateTime_object('TXN_timestamp');
803
-        // setup date due:
804
-        try {
805
-            if ($transaction_created instanceof DateTime) {
806
-                $date_due = $transaction_created->add(
807
-                    new DateInterval('P' . $days_until_due . 'D')
808
-                )->format($format);
809
-            } else {
810
-                throw new Exception();
811
-            }
812
-        } catch (Exception $e) {
813
-            // format was likely invalid.
814
-            $date_due = esc_html__(
815
-                'Unable to calculate date due, likely the format string is invalid.',
816
-                'event_espresso'
817
-            );
818
-        }
819
-        return $prefix_text . $date_due;
820
-    }
715
+		}
716
+		return '';
717
+	}
718
+
719
+
720
+	/**
721
+	 * This returns a subtotal.
722
+	 *
723
+	 * @param bool $tax if true then return the subtotal for tax otherwise return subtotal.
724
+	 * @return int
725
+	 * @throws EE_Error
726
+	 * @throws ReflectionException
727
+	 */
728
+	private function _get_subtotal($tax = false)
729
+	{
730
+		$grand_total = $this->_data->grand_total_line_item ?? null;
731
+		if (! $grand_total instanceof EE_Line_Item) {
732
+			return 0;
733
+		}
734
+		return $tax ? $grand_total->get_total_tax() : $grand_total->get_items_total();
735
+	}
736
+
737
+
738
+	/**
739
+	 * parser for the [PAYMENT_LINK_IF_NEEDED_*] attribute type shortcode
740
+	 *
741
+	 * @param string $shortcode the incoming shortcode
742
+	 * @return string parsed.
743
+	 * @throws EE_Error
744
+	 * @throws ReflectionException
745
+	 * @since 4.7.0
746
+	 */
747
+	private function _get_payment_link_if_needed($shortcode)
748
+	{
749
+		$valid_shortcodes = ['transaction'];
750
+		$attrs            = $this->_get_shortcode_attrs($shortcode);
751
+		// ensure default is set.
752
+		$addressee   = $this->_data instanceof EE_Messages_Addressee ? $this->_data : null;
753
+		$total_owing = $addressee instanceof EE_Messages_Addressee && $addressee->txn instanceof EE_Transaction
754
+			? $addressee->txn->remaining()
755
+			: 0;
756
+		if ($total_owing > 0) {
757
+			$class         = $attrs['class'] ?? 'callout';
758
+			$custom_text   =
759
+				$attrs['custom_text'] ?? 'You can %smake a payment here »%s.';
760
+			$container_tag = $attrs['container_tag'] ?? 'p';
761
+			$opening_tag   = ! empty($container_tag) ? '<' . $container_tag : '';
762
+			$opening_tag   .= ! empty($opening_tag) && ! empty($class) ? ' class="' . $class . '"' : $opening_tag;
763
+			$opening_tag   .= ! empty($opening_tag) ? '>' : $opening_tag;
764
+			$closing_tag   = ! empty($container_tag) ? '</' . $container_tag . '>' : '';
765
+			$content       = $opening_tag . sprintf($custom_text, '<a href="[PAYMENT_URL]">', '</a>') . $closing_tag;
766
+			// we need to re-run this string through the parser to catch any shortcodes that are in it.
767
+			$owing_content = $this->_shortcode_helper->parse_message_template(
768
+				$content,
769
+				$addressee,
770
+				$valid_shortcodes,
771
+				$this->_message_type,
772
+				$this->_messenger,
773
+				$this->_message
774
+			);
775
+		} else {
776
+			return '';
777
+		}
778
+		return $owing_content;
779
+	}
780
+
781
+
782
+	/**
783
+	 * Parser for the [PAYMENT_DUE_DATE_*] attribute type shortcode
784
+	 *
785
+	 * @param string         $shortcode The shortcode being parsed.
786
+	 * @param EE_Transaction $transaction
787
+	 * @return string
788
+	 * @throws EE_Error
789
+	 * @throws ReflectionException
790
+	 * @since 4.8.28.rc.011
791
+	 */
792
+	protected function _get_payment_due_date($shortcode, EE_Transaction $transaction)
793
+	{
794
+		// if transaction is paid in full then we can just return an empty string
795
+		if ($transaction->remaining() == 0) {
796
+			return '';
797
+		}
798
+		$attrs               = $this->_get_shortcode_attrs($shortcode);
799
+		$format              = $attrs['format'] ?? get_option('date_format');
800
+		$days_until_due      = isset($attrs['days_until_due']) ? (int) $attrs['days_until_due'] : 30;
801
+		$prefix_text         = $attrs['prefix_text'] ?? esc_html__('Payment in full due by: ', 'event_espresso');
802
+		$transaction_created = $transaction->get_DateTime_object('TXN_timestamp');
803
+		// setup date due:
804
+		try {
805
+			if ($transaction_created instanceof DateTime) {
806
+				$date_due = $transaction_created->add(
807
+					new DateInterval('P' . $days_until_due . 'D')
808
+				)->format($format);
809
+			} else {
810
+				throw new Exception();
811
+			}
812
+		} catch (Exception $e) {
813
+			// format was likely invalid.
814
+			$date_due = esc_html__(
815
+				'Unable to calculate date due, likely the format string is invalid.',
816
+				'event_espresso'
817
+			);
818
+		}
819
+		return $prefix_text . $date_due;
820
+	}
821 821
 }
Please login to merge, or discard this patch.
Spacing   +25 added lines, -25 removed lines patch added patch discarded remove patch
@@ -261,7 +261,7 @@  discard block
 block discarded – undo
261 261
             && $this->_extra_data['data'] instanceof EE_Messages_Addressee
262 262
                 ? $this->_extra_data['data']->txn
263 263
                 : $transaction;
264
-        if (! $transaction instanceof EE_Transaction) {
264
+        if ( ! $transaction instanceof EE_Transaction) {
265 265
             return '';
266 266
         }
267 267
         // payment
@@ -292,7 +292,7 @@  discard block
 block discarded – undo
292 292
                 $invoice_url = empty($invoice_url) ? 'http://dummyinvoicelinksforpreview.com' : $invoice_url;
293 293
                 return sprintf(
294 294
                     esc_html__('%sClick here for Invoice%s', 'event_espresso'),
295
-                    '<a href="' . $invoice_url . '">',
295
+                    '<a href="'.$invoice_url.'">',
296 296
                     '</a>'
297 297
                 );
298 298
 
@@ -368,7 +368,7 @@  discard block
 block discarded – undo
368 368
                 return $this->_data->total_ticket_count;
369 369
 
370 370
             case '[TRANSACTION_ADMIN_URL]':
371
-                require_once EE_CORE . 'admin/EE_Admin_Page.core.php';
371
+                require_once EE_CORE.'admin/EE_Admin_Page.core.php';
372 372
                 $query_args = [
373 373
                     'page'   => 'espresso_transactions',
374 374
                     'action' => 'view_transaction',
@@ -379,7 +379,7 @@  discard block
 block discarded – undo
379 379
             case strpos($shortcode, '[RECEIPT_URL') !== false :
380 380
                 // get primary_registration
381 381
                 $reg = $this->_data->primary_reg_obj;
382
-                if (! $reg instanceof EE_Registration) {
382
+                if ( ! $reg instanceof EE_Registration) {
383 383
                     return '';
384 384
                 }
385 385
                 // any attributes?
@@ -503,7 +503,7 @@  discard block
 block discarded – undo
503 503
         if (empty($invoice_logo_url)) {
504 504
             return '';
505 505
         }
506
-        if (! $img_tags) {
506
+        if ( ! $img_tags) {
507 507
             return $invoice_logo_url;
508 508
         }
509 509
         $invoice_logo_url = esc_url_raw($invoice_logo_url);
@@ -516,7 +516,7 @@  discard block
 block discarded – undo
516 516
             $image_width      = esc_attr($image_width);
517 517
             $image_width_attr = " width='$image_width'";
518 518
         }
519
-        return '<img class="logo screen" src="' . $invoice_logo_url . '"' . $image_width_attr . ' alt="logo" />';
519
+        return '<img class="logo screen" src="'.$invoice_logo_url.'"'.$image_width_attr.' alt="logo" />';
520 520
     }
521 521
 
522 522
 
@@ -553,7 +553,7 @@  discard block
 block discarded – undo
553 553
      */
554 554
     private function _get_invoice_payment_method()
555 555
     {
556
-        if (! $this->_invoice_pm instanceof EE_Payment_Method) {
556
+        if ( ! $this->_invoice_pm instanceof EE_Payment_Method) {
557 557
             $transaction = $this->_data->txn instanceof EE_Transaction ? $this->_data->txn : null;
558 558
             $transaction = ! $transaction instanceof EE_Transaction
559 559
                 && is_array($this->_extra_data)
@@ -623,7 +623,7 @@  discard block
 block discarded – undo
623 623
         $attrs = $this->_get_shortcode_attrs($shortcode);
624 624
         // prefix?
625 625
         $prefix = $attrs['prefix'] ?? esc_html__('VAT/Tax Number: ', 'event_espresso');
626
-        return $prefix . $payee_tax_number;
626
+        return $prefix.$payee_tax_number;
627 627
     }
628 628
 
629 629
 
@@ -647,16 +647,16 @@  discard block
 block discarded – undo
647 647
         }
648 648
         if (empty($payee_address)) {
649 649
             $organization  = EE_Registry::instance()->CFG->organization;
650
-            $payee_address = $organization->get_pretty('address_1') . '<br>';
650
+            $payee_address = $organization->get_pretty('address_1').'<br>';
651 651
             $payee_address .= ! empty($organization->address_2)
652
-                ? $organization->get_pretty('address_2') . '<br>'
652
+                ? $organization->get_pretty('address_2').'<br>'
653 653
                 : '';
654
-            $payee_address .= $organization->get_pretty('city') . '<br>';
654
+            $payee_address .= $organization->get_pretty('city').'<br>';
655 655
             // state
656
-            $state         = EE_Registry::instance()->load_model('State')->get_one_by_ID($organization->STA_ID);
656
+            $state = EE_Registry::instance()->load_model('State')->get_one_by_ID($organization->STA_ID);
657 657
             $payee_address .= $state instanceof EE_State ? $state->name() : '';
658 658
             // Country
659
-            $payee_address .= ! empty($organization->CNT_ISO) ? ', ' . $organization->CNT_ISO . '<br>' : '';
659
+            $payee_address .= ! empty($organization->CNT_ISO) ? ', '.$organization->CNT_ISO.'<br>' : '';
660 660
             $payee_address .= ! empty($organization->zip) ? $organization->zip : '';
661 661
         }
662 662
         return $payee_address;
@@ -693,7 +693,7 @@  discard block
 block discarded – undo
693 693
     {
694 694
         $reg          = $this->_data->primary_reg_obj;
695 695
         $message_type = $this->_extra_data['message_type'] ?? '';
696
-        if (! $reg instanceof EE_Registration || empty($message_type)) {
696
+        if ( ! $reg instanceof EE_Registration || empty($message_type)) {
697 697
             return '';
698 698
         }
699 699
         $switch_to_invoice = ! $message_type instanceof EE_Invoice_message_type;
@@ -703,13 +703,13 @@  discard block
 block discarded – undo
703 703
         $switch_to_label   =
704 704
             ! $switch_to_invoice ? esc_html__('Switch to Receipt', 'event_espresso') : $switch_to_label;
705 705
         $switch_to_url     = $switch_to_invoice ? $reg->invoice_url() : $reg->receipt_url();
706
-        if (! $button) {
706
+        if ( ! $button) {
707 707
             return $switch_to_url;
708 708
         }
709
-        if (! empty($switch_to_url)) {
709
+        if ( ! empty($switch_to_url)) {
710 710
             return '
711
-	<form method="post" action="' . $switch_to_url . '" >
712
-		<input class="print_button" type="submit" value="' . $switch_to_label . '" />
711
+	<form method="post" action="' . $switch_to_url.'" >
712
+		<input class="print_button" type="submit" value="' . $switch_to_label.'" />
713 713
 	</form>
714 714
 			';
715 715
         }
@@ -728,7 +728,7 @@  discard block
 block discarded – undo
728 728
     private function _get_subtotal($tax = false)
729 729
     {
730 730
         $grand_total = $this->_data->grand_total_line_item ?? null;
731
-        if (! $grand_total instanceof EE_Line_Item) {
731
+        if ( ! $grand_total instanceof EE_Line_Item) {
732 732
             return 0;
733 733
         }
734 734
         return $tax ? $grand_total->get_total_tax() : $grand_total->get_items_total();
@@ -758,11 +758,11 @@  discard block
 block discarded – undo
758 758
             $custom_text   =
759 759
                 $attrs['custom_text'] ?? 'You can %smake a payment here »%s.';
760 760
             $container_tag = $attrs['container_tag'] ?? 'p';
761
-            $opening_tag   = ! empty($container_tag) ? '<' . $container_tag : '';
762
-            $opening_tag   .= ! empty($opening_tag) && ! empty($class) ? ' class="' . $class . '"' : $opening_tag;
761
+            $opening_tag   = ! empty($container_tag) ? '<'.$container_tag : '';
762
+            $opening_tag   .= ! empty($opening_tag) && ! empty($class) ? ' class="'.$class.'"' : $opening_tag;
763 763
             $opening_tag   .= ! empty($opening_tag) ? '>' : $opening_tag;
764
-            $closing_tag   = ! empty($container_tag) ? '</' . $container_tag . '>' : '';
765
-            $content       = $opening_tag . sprintf($custom_text, '<a href="[PAYMENT_URL]">', '</a>') . $closing_tag;
764
+            $closing_tag   = ! empty($container_tag) ? '</'.$container_tag.'>' : '';
765
+            $content       = $opening_tag.sprintf($custom_text, '<a href="[PAYMENT_URL]">', '</a>').$closing_tag;
766 766
             // we need to re-run this string through the parser to catch any shortcodes that are in it.
767 767
             $owing_content = $this->_shortcode_helper->parse_message_template(
768 768
                 $content,
@@ -804,7 +804,7 @@  discard block
 block discarded – undo
804 804
         try {
805 805
             if ($transaction_created instanceof DateTime) {
806 806
                 $date_due = $transaction_created->add(
807
-                    new DateInterval('P' . $days_until_due . 'D')
807
+                    new DateInterval('P'.$days_until_due.'D')
808 808
                 )->format($format);
809 809
             } else {
810 810
                 throw new Exception();
@@ -816,6 +816,6 @@  discard block
 block discarded – undo
816 816
                 'event_espresso'
817 817
             );
818 818
         }
819
-        return $prefix_text . $date_due;
819
+        return $prefix_text.$date_due;
820 820
     }
821 821
 }
Please login to merge, or discard this patch.
core/libraries/shortcodes/EE_Shortcodes.lib.php 2 patches
Indentation   +478 added lines, -478 removed lines patch added patch discarded remove patch
@@ -15,482 +15,482 @@
 block discarded – undo
15 15
  */
16 16
 abstract class EE_Shortcodes extends EE_Base
17 17
 {
18
-    /**
19
-     * matches a full shortcode including shortcodes with attributes or dynamic shortcodes
20
-     * examples:
21
-     *  [RECIPIENT_LNAME]
22
-     *  [RECEIPT_URL download=true]
23
-     *  [PAYMENT_LINK_IF_NEEDED_* custom_text='pay me now man!']
24
-     */
25
-    public const REGEX_SHORTCODE_FULL = '/(\[.+?])/';
26
-
27
-    /**
28
-     * matches the opening [ plus the shortcode name, but nothing else
29
-     * examples:
30
-     *  [RECIPIENT_LNAME] matches as [RECIPIENT_LNAME
31
-     *  [RECEIPT_URL download=true] matches as [RECEIPT_URL
32
-     *  [PAYMENT_LINK_IF_NEEDED_* custom_text='pay me now man!'] matches as [PAYMENT_LINK_IF_NEEDED_*
33
-     */
34
-    public const REGEX_SHORTCODE_NAME_ONLY = '/\[[A-Z_*]+/';
35
-
36
-    /**
37
-     * matches the opening [ plus the dynamic shortcode name including _*, but nothing else
38
-     * examples:
39
-     *  [RECIPIENT_LNAME] does not match
40
-     *  [RECEIPT_URL download=true] does not match
41
-     *  [PAYMENT_LINK_IF_NEEDED_* custom_text='pay me now man!'] matches as [PAYMENT_LINK_IF_NEEDED_*
42
-     */
43
-    public const REGEX_SHORTCODE_DYNAMIC = '/(\[[A-Z_]+_\*)/';
44
-
45
-
46
-
47
-    /**
48
-     * holds label for library
49
-     * This is used for referencing the library label
50
-     *
51
-     * @var string
52
-     */
53
-    public string $label;
54
-
55
-
56
-    public string $name;
57
-
58
-
59
-    /**
60
-     * This property is used for referencing a short description of the library
61
-     *
62
-     * @var string
63
-     */
64
-    public string $description;
65
-
66
-
67
-    /**
68
-     * This will hold an array of shortcodes with the key as the shortcode ([shortcode]) and the value as a
69
-     * label/description for the shortcode.
70
-     *
71
-     * @var array
72
-     */
73
-    protected array $_shortcodes = [];
74
-
75
-
76
-    /**
77
-     * This will hold the incoming data item sent to the parser method
78
-     *
79
-     * @var array|object
80
-     */
81
-    protected $_data;
82
-
83
-
84
-    /**
85
-     * some shortcodes may require extra data to parse.  This property is provided for that.
86
-     *
87
-     * @var array|EE_Messages_Addressee
88
-     */
89
-    protected $_extra_data;
90
-
91
-
92
-    /**
93
-     * EE_messenger used to generate the template being parsed.
94
-     *
95
-     * @since 4.5.0
96
-     * @var EE_messenger
97
-     */
98
-    protected EE_messenger $_messenger;
99
-
100
-
101
-    /**
102
-     * message type used to generate the template being parsed.
103
-     *
104
-     * @since 4.5.0
105
-     * @var EE_message_type|null
106
-     */
107
-    protected ?EE_message_type $_message_type = null;
108
-
109
-
110
-    /**
111
-     * context used for the template being parsed
112
-     *
113
-     * @since 4.5.0
114
-     * @var string
115
-     */
116
-    protected string $_context;
117
-
118
-
119
-    /**
120
-     * Specific Message Template Group ID
121
-     *
122
-     * @since 4.5.0
123
-     * @var int
124
-     */
125
-    protected int $_GRP_ID;
126
-
127
-
128
-    /**
129
-     * @since 4.9.0
130
-     * @type EE_Message|null
131
-     */
132
-    protected ?EE_Message $_message = null;
133
-
134
-
135
-    /**
136
-     * This will hold an instance of the EEH_Parse_Shortcodes helper that will be used when handling list type
137
-     * shortcodes
138
-     *
139
-     * @var EEH_Parse_Shortcodes
140
-     */
141
-    protected EEH_Parse_Shortcodes $_shortcode_helper;
142
-
143
-
144
-    public function __construct()
145
-    {
146
-        $this->_set_defaults();
147
-        $this->_set_shortcode_helper();
148
-        $this->_init_props();
149
-    }
150
-
151
-
152
-    /**
153
-     * This sets the defaults for the properties.  Child classes will override these properties in their _init_props
154
-     * method
155
-     */
156
-    private function _set_defaults()
157
-    {
158
-        $this->name        = $this->description = '';
159
-        $this->_shortcodes = [];
160
-    }
161
-
162
-
163
-    /**
164
-     * loads an instance of the EE_Shortcode_Parser helper when requested
165
-     */
166
-    protected function _set_shortcode_helper()
167
-    {
168
-        // get shortcode_replace instance - set when _get_messages is called in child...
169
-        $this->_shortcode_helper = new EEH_Parse_Shortcodes();
170
-    }
171
-
172
-
173
-    public function get_shortcode_helper(): EEH_Parse_Shortcodes
174
-    {
175
-        return $this->_shortcode_helper;
176
-    }
177
-
178
-
179
-    /**
180
-     * This is the public method for kicking of the parser included with each child.  It can be overridden by child
181
-     * classes if necessary (see EE_Questions_Answers for example)
182
-     *
183
-     * @param string       $shortcode  incoming shortcode to be parsed
184
-     * @param object|array $data       incoming data to be used for parsing
185
-     * @param object|array $extra_data extra incoming data (usually EE_Messages_Addressee)
186
-     * @return string            parsed shortcode.
187
-     */
188
-    public function parser(string $shortcode, $data, $extra_data = []): string
189
-    {
190
-        // filter setup shortcodes
191
-        $this->_shortcodes = $this->get_shortcodes();
192
-
193
-        // we need to set up any dynamic shortcodes so that they work with the array_key_exists
194
-        preg_match_all(EE_Shortcodes::REGEX_SHORTCODE_NAME_ONLY, $shortcode, $matches);
195
-        $shortcode_to_verify = ! empty($matches[0]) ? $matches[0][0] . ']' : $shortcode;
196
-
197
-        // first we want to make sure this is a valid shortcode
198
-        if (! array_key_exists($shortcode_to_verify, $this->_shortcodes)) {
199
-            // get out, this parser doesn't handle the incoming shortcode.
200
-            return '';
201
-        }
202
-        $this->_data       = $data;
203
-        $this->_extra_data = $extra_data;
204
-        $this->_set_messages_properties();
205
-        $parsed = (string) apply_filters(
206
-            'FHEE__' . get_class($this) . '__parser_after',
207
-            $this->_parser($shortcode),
208
-            $shortcode,
209
-            $data,
210
-            $extra_data,
211
-            $this
212
-        );
213
-
214
-        // note the below filter applies to ALL shortcode parsers... be careful!
215
-        return (string) apply_filters(
216
-            'FHEE__EE_Shortcodes__parser_after',
217
-            $parsed,
218
-            $shortcode,
219
-            $data,
220
-            $extra_data,
221
-            $this
222
-        );
223
-    }
224
-
225
-
226
-    /**
227
-     * This method just returns the shortcodes in the $_shortcodes array property.
228
-     *
229
-     * @return array array of shortcodes => description pairs
230
-     */
231
-    public function get_shortcodes(): array
232
-    {
233
-        $this->_shortcodes = (array) apply_filters(
234
-            'FHEE__' . get_class($this) . '__shortcodes',
235
-            $this->_shortcodes,
236
-            $this
237
-        );
238
-
239
-        // note the below filter applies to ALL shortcode parsers... be careful!
240
-        return (array) apply_filters('FHEE__EE_Shortcodes__shortcodes', $this->_shortcodes, $this);
241
-    }
242
-
243
-
244
-    /**
245
-     * Child classes use this method to set the $name, $description, and $_shortcodes properties.
246
-     *
247
-     * @abstract
248
-     * @return void
249
-     */
250
-    abstract protected function _init_props();
251
-
252
-
253
-    /**
254
-     * This method will give parsing instructions for each shortcode defined in the _shortcodes array.  Child methods
255
-     * will have to take care of handling.
256
-     *
257
-     * @abstract
258
-     * @param string $shortcode    the shortcode to be parsed.
259
-     * @return string parsed shortcode
260
-     */
261
-    abstract protected function _parser($shortcode);
262
-
263
-
264
-    /**
265
-     * This just validates incoming data for list type shortcode parsers (and they call this method) to make sure it
266
-     * meets their requirements
267
-     *
268
-     * @return void If validation fails we'll throw an exception.
269
-     * @throws EE_Error
270
-     */
271
-    protected function _validate_list_requirements()
272
-    {
273
-        // first test to make sure we've got an array!
274
-        if (! is_array($this->_data)) {
275
-            throw new EE_Error(
276
-                sprintf(
277
-                    esc_html__(
278
-                        'Expecting an array for the data sent to %s. Instead it was %s',
279
-                        'event_espresso'
280
-                    ),
281
-                    get_class($this),
282
-                    gettype($this->_data)
283
-                )
284
-            );
285
-        }
286
-
287
-        // next test to make sure we've got the required template in the index!
288
-        if (! isset($this->_data['template'])) {
289
-            throw new EE_Error(
290
-                esc_html__(
291
-                    'The incoming data does not have the required template index in its array',
292
-                    'event_espresso'
293
-                )
294
-            );
295
-        }
296
-
297
-        // next test to make sure we've got a data index in the incoming data array
298
-        if (! isset($this->_data['data'])) {
299
-            throw new EE_Error(
300
-                esc_html__(
301
-                    'The incoming data does not have the required data index in its array',
302
-                    'event_espresso'
303
-                )
304
-            );
305
-        }
306
-
307
-        // all is well let's make sure _extra_data always has the values needed.
308
-        // let's make sure that extra_data includes all templates (for later parsing if necessary)
309
-        if (empty($this->_extra_data) || (empty($this->_extra_data['data']) && empty($this->_extra_data['template']))) {
310
-            $this->_extra_data['data']     = $this->_data['data'];
311
-            $this->_extra_data['template'] = $this->_data['template'];
312
-        }
313
-    }
314
-
315
-
316
-    /**
317
-     * This returns any attributes that may be existing on an EE_Shortcode
318
-     *
319
-     * @param string $shortcode incoming shortcode
320
-     * @return array An array with the attributes
321
-     * @since 4.5.0
322
-     */
323
-    protected function _get_shortcode_attrs(string $shortcode): array
324
-    {
325
-        // make sure the required wp helper function is present
326
-        // require the shortcode file if necessary
327
-        if (! function_exists('shortcode_parse_atts')) {
328
-            require_once(ABSPATH . WPINC . '/shortcodes.php');
329
-        }
330
-
331
-        // let's get any attributes that may be present and set the defaults.
332
-        $shortcode_to_parse = str_replace(['[', ']'], '', $shortcode);
333
-        return shortcode_parse_atts($shortcode_to_parse);
334
-    }
335
-
336
-
337
-    /**
338
-     * Conditional blocks are shortcode patterns with an opening conditional tag `[IF_*]` and a corresponding
339
-     * closing tag (eg `[/IF_*]`).  The content within the tags will be displayed/hidden depending on whatever
340
-     * conditions existed in the opening tag.  This method handles parsing the actual template to show/hide this
341
-     * conditional content.
342
-     *
343
-     * @param string $shortcode This should be the original shortcode as used in the template and passed to the parser.
344
-     * @param bool   $show      true means the opening and closing tags are removed and the content is left showing,
345
-     *                          false means the opening and closing tags and the contained content are removed.
346
-     * @return string     The template for the shortcode is returned.
347
-     * @since 4.9.32
348
-     *
349
-     */
350
-    protected function _mutate_conditional_block_in_template(string $shortcode, bool $show = true): string
351
-    {
352
-        // first let's get all the matches in the template for this particular shortcode.
353
-        preg_match_all('~' . $this->_get_conditional_block_regex($shortcode) . '~', $this->_data['template'], $matches);
354
-
355
-        if ($matches && is_array($matches[0]) && ! empty($matches[0])) {
356
-            // we need to hide all instances of the matches
357
-            foreach ($matches[0] as $index => $content_to_show_or_hide) {
358
-                $content_to_show_or_hide = preg_quote($content_to_show_or_hide);
359
-                $replacement             = $show ? $matches[4][ $index ] : '';
360
-                $this->_data['template'] = preg_replace(
361
-                    '~' . $content_to_show_or_hide . '~',
362
-                    $replacement,
363
-                    $this->_data['template']
364
-                );
365
-            }
366
-        }
367
-        // return $template
368
-        return $this->_data['template'];
369
-    }
370
-
371
-
372
-    /**
373
-     * This returns the regex pattern to use for conditional shortcodes parsing.
374
-     *
375
-     * Note: regex comes in part from the WP `get_shortcode_regex` expression in \wp-includes\shortcodes.php
376
-     *
377
-     * @param string $shortcode
378
-     * @return string
379
-     * @since 4.9.32
380
-     */
381
-    private function _get_conditional_block_regex(string $shortcode): string
382
-    {
383
-        // get just the shortcode tag for the match
384
-        preg_match('@\[([^<>&/\[\]\x00-\x20=]++)@', $shortcode, $shortcode_tag_matches);
385
-        if (empty($shortcode_tag_matches[1])) {
386
-            return $this->_data['template'];
387
-        }
388
-
389
-        $shortcode_tag = $shortcode_tag_matches[1];
390
-        // get attributes_part_of_tag
391
-        $attributes_part = preg_quote(str_replace([$shortcode_tag, '[', ']'], '', $shortcode));
392
-        // escape
393
-        $shortcode_tag = preg_quote($shortcode_tag);
394
-
395
-        return
396
-            '\['                                  // Opening Bracket
397
-            . "($shortcode_tag)$attributes_part"    // 1: Shortcode Name
398
-            . '(?![\w-])'                           // Not followed by word character or hyphen
399
-            . '('                                   // 2: Unroll the loop: Inside the opening shortcode tag
400
-            . '[^\]\/]*'                          // Not a closing bracket or forward slash
401
-            . '(?:'
402
-            . '\/(?!\])'                      // A forward slash not followed by a closing bracket
403
-            . '[^\]\/]*'                      // Not a closing bracket or forward slash.
404
-            . ')*?'
405
-            . ')'
406
-            . '(?:'
407
-            . '(\/)'                              // 3. Self closing tag ...
408
-            . '\]'                                // ... and closing bracket
409
-            . '|'
410
-            . '\]'                                // Closing bracket
411
-            . '(?:'
412
-            . '('                             // 4: Unroll the loop: Optionally, anything between the opening and closing brackets
413
-            . '[^\[]*+'                   // Not an opening bracket
414
-            . '(?:'
415
-            . '\[(?!\/\1\])'          // An opening bracket not followed by the closing shortcode tag.
416
-            . '[^\[]*+'               // Not an opening bracket
417
-            . ')*+'
418
-            . ')'
419
-            . '\[\/\1\]'                      // Closing shortcode tag
420
-            . ')?'
421
-            . ')';
422
-    }
423
-
424
-
425
-    /**
426
-     * This sets the properties related to the messages system
427
-     *
428
-     * @return void
429
-     * @since 4.5.0
430
-     */
431
-    protected function _set_messages_properties()
432
-    {
433
-        // should be in _extra_data
434
-        if (isset($this->_extra_data['messenger'])) {
435
-            $this->_messenger    = $this->_extra_data['messenger'];
436
-            $this->_message_type = $this->_extra_data['message_type'];
437
-            $this->_context      = $this->_extra_data['message'] instanceof EE_Message
438
-                ? $this->_extra_data['message']->context()
439
-                : '';
440
-            $this->_GRP_ID       = $this->_extra_data['message'] instanceof EE_Message
441
-                ? $this->_extra_data['message']->GRP_ID()
442
-                : 0;
443
-            $this->_message      = $this->_extra_data['message'] instanceof EE_Message
444
-                ? $this->_extra_data['message']
445
-                : null;
446
-        }
447
-    }
448
-
449
-
450
-    /**
451
-     * This returns whatever the set message type object is that was set on this shortcode parser.
452
-     *
453
-     * @return EE_message_type|null
454
-     * @since 4.5.0
455
-     */
456
-    public function get_set_message_type(): ?EE_message_type
457
-    {
458
-        return $this->_message_type;
459
-    }
460
-
461
-
462
-    /**
463
-     * This returns whatever the set messenger object is that was set on this shortcode parser
464
-     *
465
-     * @return EE_messenger
466
-     * @since 4.5.0
467
-     */
468
-    public function get_set_messenger(): EE_messenger
469
-    {
470
-        return $this->_messenger;
471
-    }
472
-
473
-
474
-    /**
475
-     * This returns whatever the set context string is on this shortcode parser.
476
-     *
477
-     * @return string
478
-     * @since 4.5.0
479
-     */
480
-    public function get_set_context(): string
481
-    {
482
-        return $this->_context;
483
-    }
484
-
485
-
486
-    /**
487
-     * This returns whatever the set EE_Message object is on this shortcode.
488
-     *
489
-     * @return EE_Message|null
490
-     * @since 4.9.0
491
-     */
492
-    public function get_set_message(): ?EE_Message
493
-    {
494
-        return $this->_message;
495
-    }
18
+	/**
19
+	 * matches a full shortcode including shortcodes with attributes or dynamic shortcodes
20
+	 * examples:
21
+	 *  [RECIPIENT_LNAME]
22
+	 *  [RECEIPT_URL download=true]
23
+	 *  [PAYMENT_LINK_IF_NEEDED_* custom_text='pay me now man!']
24
+	 */
25
+	public const REGEX_SHORTCODE_FULL = '/(\[.+?])/';
26
+
27
+	/**
28
+	 * matches the opening [ plus the shortcode name, but nothing else
29
+	 * examples:
30
+	 *  [RECIPIENT_LNAME] matches as [RECIPIENT_LNAME
31
+	 *  [RECEIPT_URL download=true] matches as [RECEIPT_URL
32
+	 *  [PAYMENT_LINK_IF_NEEDED_* custom_text='pay me now man!'] matches as [PAYMENT_LINK_IF_NEEDED_*
33
+	 */
34
+	public const REGEX_SHORTCODE_NAME_ONLY = '/\[[A-Z_*]+/';
35
+
36
+	/**
37
+	 * matches the opening [ plus the dynamic shortcode name including _*, but nothing else
38
+	 * examples:
39
+	 *  [RECIPIENT_LNAME] does not match
40
+	 *  [RECEIPT_URL download=true] does not match
41
+	 *  [PAYMENT_LINK_IF_NEEDED_* custom_text='pay me now man!'] matches as [PAYMENT_LINK_IF_NEEDED_*
42
+	 */
43
+	public const REGEX_SHORTCODE_DYNAMIC = '/(\[[A-Z_]+_\*)/';
44
+
45
+
46
+
47
+	/**
48
+	 * holds label for library
49
+	 * This is used for referencing the library label
50
+	 *
51
+	 * @var string
52
+	 */
53
+	public string $label;
54
+
55
+
56
+	public string $name;
57
+
58
+
59
+	/**
60
+	 * This property is used for referencing a short description of the library
61
+	 *
62
+	 * @var string
63
+	 */
64
+	public string $description;
65
+
66
+
67
+	/**
68
+	 * This will hold an array of shortcodes with the key as the shortcode ([shortcode]) and the value as a
69
+	 * label/description for the shortcode.
70
+	 *
71
+	 * @var array
72
+	 */
73
+	protected array $_shortcodes = [];
74
+
75
+
76
+	/**
77
+	 * This will hold the incoming data item sent to the parser method
78
+	 *
79
+	 * @var array|object
80
+	 */
81
+	protected $_data;
82
+
83
+
84
+	/**
85
+	 * some shortcodes may require extra data to parse.  This property is provided for that.
86
+	 *
87
+	 * @var array|EE_Messages_Addressee
88
+	 */
89
+	protected $_extra_data;
90
+
91
+
92
+	/**
93
+	 * EE_messenger used to generate the template being parsed.
94
+	 *
95
+	 * @since 4.5.0
96
+	 * @var EE_messenger
97
+	 */
98
+	protected EE_messenger $_messenger;
99
+
100
+
101
+	/**
102
+	 * message type used to generate the template being parsed.
103
+	 *
104
+	 * @since 4.5.0
105
+	 * @var EE_message_type|null
106
+	 */
107
+	protected ?EE_message_type $_message_type = null;
108
+
109
+
110
+	/**
111
+	 * context used for the template being parsed
112
+	 *
113
+	 * @since 4.5.0
114
+	 * @var string
115
+	 */
116
+	protected string $_context;
117
+
118
+
119
+	/**
120
+	 * Specific Message Template Group ID
121
+	 *
122
+	 * @since 4.5.0
123
+	 * @var int
124
+	 */
125
+	protected int $_GRP_ID;
126
+
127
+
128
+	/**
129
+	 * @since 4.9.0
130
+	 * @type EE_Message|null
131
+	 */
132
+	protected ?EE_Message $_message = null;
133
+
134
+
135
+	/**
136
+	 * This will hold an instance of the EEH_Parse_Shortcodes helper that will be used when handling list type
137
+	 * shortcodes
138
+	 *
139
+	 * @var EEH_Parse_Shortcodes
140
+	 */
141
+	protected EEH_Parse_Shortcodes $_shortcode_helper;
142
+
143
+
144
+	public function __construct()
145
+	{
146
+		$this->_set_defaults();
147
+		$this->_set_shortcode_helper();
148
+		$this->_init_props();
149
+	}
150
+
151
+
152
+	/**
153
+	 * This sets the defaults for the properties.  Child classes will override these properties in their _init_props
154
+	 * method
155
+	 */
156
+	private function _set_defaults()
157
+	{
158
+		$this->name        = $this->description = '';
159
+		$this->_shortcodes = [];
160
+	}
161
+
162
+
163
+	/**
164
+	 * loads an instance of the EE_Shortcode_Parser helper when requested
165
+	 */
166
+	protected function _set_shortcode_helper()
167
+	{
168
+		// get shortcode_replace instance - set when _get_messages is called in child...
169
+		$this->_shortcode_helper = new EEH_Parse_Shortcodes();
170
+	}
171
+
172
+
173
+	public function get_shortcode_helper(): EEH_Parse_Shortcodes
174
+	{
175
+		return $this->_shortcode_helper;
176
+	}
177
+
178
+
179
+	/**
180
+	 * This is the public method for kicking of the parser included with each child.  It can be overridden by child
181
+	 * classes if necessary (see EE_Questions_Answers for example)
182
+	 *
183
+	 * @param string       $shortcode  incoming shortcode to be parsed
184
+	 * @param object|array $data       incoming data to be used for parsing
185
+	 * @param object|array $extra_data extra incoming data (usually EE_Messages_Addressee)
186
+	 * @return string            parsed shortcode.
187
+	 */
188
+	public function parser(string $shortcode, $data, $extra_data = []): string
189
+	{
190
+		// filter setup shortcodes
191
+		$this->_shortcodes = $this->get_shortcodes();
192
+
193
+		// we need to set up any dynamic shortcodes so that they work with the array_key_exists
194
+		preg_match_all(EE_Shortcodes::REGEX_SHORTCODE_NAME_ONLY, $shortcode, $matches);
195
+		$shortcode_to_verify = ! empty($matches[0]) ? $matches[0][0] . ']' : $shortcode;
196
+
197
+		// first we want to make sure this is a valid shortcode
198
+		if (! array_key_exists($shortcode_to_verify, $this->_shortcodes)) {
199
+			// get out, this parser doesn't handle the incoming shortcode.
200
+			return '';
201
+		}
202
+		$this->_data       = $data;
203
+		$this->_extra_data = $extra_data;
204
+		$this->_set_messages_properties();
205
+		$parsed = (string) apply_filters(
206
+			'FHEE__' . get_class($this) . '__parser_after',
207
+			$this->_parser($shortcode),
208
+			$shortcode,
209
+			$data,
210
+			$extra_data,
211
+			$this
212
+		);
213
+
214
+		// note the below filter applies to ALL shortcode parsers... be careful!
215
+		return (string) apply_filters(
216
+			'FHEE__EE_Shortcodes__parser_after',
217
+			$parsed,
218
+			$shortcode,
219
+			$data,
220
+			$extra_data,
221
+			$this
222
+		);
223
+	}
224
+
225
+
226
+	/**
227
+	 * This method just returns the shortcodes in the $_shortcodes array property.
228
+	 *
229
+	 * @return array array of shortcodes => description pairs
230
+	 */
231
+	public function get_shortcodes(): array
232
+	{
233
+		$this->_shortcodes = (array) apply_filters(
234
+			'FHEE__' . get_class($this) . '__shortcodes',
235
+			$this->_shortcodes,
236
+			$this
237
+		);
238
+
239
+		// note the below filter applies to ALL shortcode parsers... be careful!
240
+		return (array) apply_filters('FHEE__EE_Shortcodes__shortcodes', $this->_shortcodes, $this);
241
+	}
242
+
243
+
244
+	/**
245
+	 * Child classes use this method to set the $name, $description, and $_shortcodes properties.
246
+	 *
247
+	 * @abstract
248
+	 * @return void
249
+	 */
250
+	abstract protected function _init_props();
251
+
252
+
253
+	/**
254
+	 * This method will give parsing instructions for each shortcode defined in the _shortcodes array.  Child methods
255
+	 * will have to take care of handling.
256
+	 *
257
+	 * @abstract
258
+	 * @param string $shortcode    the shortcode to be parsed.
259
+	 * @return string parsed shortcode
260
+	 */
261
+	abstract protected function _parser($shortcode);
262
+
263
+
264
+	/**
265
+	 * This just validates incoming data for list type shortcode parsers (and they call this method) to make sure it
266
+	 * meets their requirements
267
+	 *
268
+	 * @return void If validation fails we'll throw an exception.
269
+	 * @throws EE_Error
270
+	 */
271
+	protected function _validate_list_requirements()
272
+	{
273
+		// first test to make sure we've got an array!
274
+		if (! is_array($this->_data)) {
275
+			throw new EE_Error(
276
+				sprintf(
277
+					esc_html__(
278
+						'Expecting an array for the data sent to %s. Instead it was %s',
279
+						'event_espresso'
280
+					),
281
+					get_class($this),
282
+					gettype($this->_data)
283
+				)
284
+			);
285
+		}
286
+
287
+		// next test to make sure we've got the required template in the index!
288
+		if (! isset($this->_data['template'])) {
289
+			throw new EE_Error(
290
+				esc_html__(
291
+					'The incoming data does not have the required template index in its array',
292
+					'event_espresso'
293
+				)
294
+			);
295
+		}
296
+
297
+		// next test to make sure we've got a data index in the incoming data array
298
+		if (! isset($this->_data['data'])) {
299
+			throw new EE_Error(
300
+				esc_html__(
301
+					'The incoming data does not have the required data index in its array',
302
+					'event_espresso'
303
+				)
304
+			);
305
+		}
306
+
307
+		// all is well let's make sure _extra_data always has the values needed.
308
+		// let's make sure that extra_data includes all templates (for later parsing if necessary)
309
+		if (empty($this->_extra_data) || (empty($this->_extra_data['data']) && empty($this->_extra_data['template']))) {
310
+			$this->_extra_data['data']     = $this->_data['data'];
311
+			$this->_extra_data['template'] = $this->_data['template'];
312
+		}
313
+	}
314
+
315
+
316
+	/**
317
+	 * This returns any attributes that may be existing on an EE_Shortcode
318
+	 *
319
+	 * @param string $shortcode incoming shortcode
320
+	 * @return array An array with the attributes
321
+	 * @since 4.5.0
322
+	 */
323
+	protected function _get_shortcode_attrs(string $shortcode): array
324
+	{
325
+		// make sure the required wp helper function is present
326
+		// require the shortcode file if necessary
327
+		if (! function_exists('shortcode_parse_atts')) {
328
+			require_once(ABSPATH . WPINC . '/shortcodes.php');
329
+		}
330
+
331
+		// let's get any attributes that may be present and set the defaults.
332
+		$shortcode_to_parse = str_replace(['[', ']'], '', $shortcode);
333
+		return shortcode_parse_atts($shortcode_to_parse);
334
+	}
335
+
336
+
337
+	/**
338
+	 * Conditional blocks are shortcode patterns with an opening conditional tag `[IF_*]` and a corresponding
339
+	 * closing tag (eg `[/IF_*]`).  The content within the tags will be displayed/hidden depending on whatever
340
+	 * conditions existed in the opening tag.  This method handles parsing the actual template to show/hide this
341
+	 * conditional content.
342
+	 *
343
+	 * @param string $shortcode This should be the original shortcode as used in the template and passed to the parser.
344
+	 * @param bool   $show      true means the opening and closing tags are removed and the content is left showing,
345
+	 *                          false means the opening and closing tags and the contained content are removed.
346
+	 * @return string     The template for the shortcode is returned.
347
+	 * @since 4.9.32
348
+	 *
349
+	 */
350
+	protected function _mutate_conditional_block_in_template(string $shortcode, bool $show = true): string
351
+	{
352
+		// first let's get all the matches in the template for this particular shortcode.
353
+		preg_match_all('~' . $this->_get_conditional_block_regex($shortcode) . '~', $this->_data['template'], $matches);
354
+
355
+		if ($matches && is_array($matches[0]) && ! empty($matches[0])) {
356
+			// we need to hide all instances of the matches
357
+			foreach ($matches[0] as $index => $content_to_show_or_hide) {
358
+				$content_to_show_or_hide = preg_quote($content_to_show_or_hide);
359
+				$replacement             = $show ? $matches[4][ $index ] : '';
360
+				$this->_data['template'] = preg_replace(
361
+					'~' . $content_to_show_or_hide . '~',
362
+					$replacement,
363
+					$this->_data['template']
364
+				);
365
+			}
366
+		}
367
+		// return $template
368
+		return $this->_data['template'];
369
+	}
370
+
371
+
372
+	/**
373
+	 * This returns the regex pattern to use for conditional shortcodes parsing.
374
+	 *
375
+	 * Note: regex comes in part from the WP `get_shortcode_regex` expression in \wp-includes\shortcodes.php
376
+	 *
377
+	 * @param string $shortcode
378
+	 * @return string
379
+	 * @since 4.9.32
380
+	 */
381
+	private function _get_conditional_block_regex(string $shortcode): string
382
+	{
383
+		// get just the shortcode tag for the match
384
+		preg_match('@\[([^<>&/\[\]\x00-\x20=]++)@', $shortcode, $shortcode_tag_matches);
385
+		if (empty($shortcode_tag_matches[1])) {
386
+			return $this->_data['template'];
387
+		}
388
+
389
+		$shortcode_tag = $shortcode_tag_matches[1];
390
+		// get attributes_part_of_tag
391
+		$attributes_part = preg_quote(str_replace([$shortcode_tag, '[', ']'], '', $shortcode));
392
+		// escape
393
+		$shortcode_tag = preg_quote($shortcode_tag);
394
+
395
+		return
396
+			'\['                                  // Opening Bracket
397
+			. "($shortcode_tag)$attributes_part"    // 1: Shortcode Name
398
+			. '(?![\w-])'                           // Not followed by word character or hyphen
399
+			. '('                                   // 2: Unroll the loop: Inside the opening shortcode tag
400
+			. '[^\]\/]*'                          // Not a closing bracket or forward slash
401
+			. '(?:'
402
+			. '\/(?!\])'                      // A forward slash not followed by a closing bracket
403
+			. '[^\]\/]*'                      // Not a closing bracket or forward slash.
404
+			. ')*?'
405
+			. ')'
406
+			. '(?:'
407
+			. '(\/)'                              // 3. Self closing tag ...
408
+			. '\]'                                // ... and closing bracket
409
+			. '|'
410
+			. '\]'                                // Closing bracket
411
+			. '(?:'
412
+			. '('                             // 4: Unroll the loop: Optionally, anything between the opening and closing brackets
413
+			. '[^\[]*+'                   // Not an opening bracket
414
+			. '(?:'
415
+			. '\[(?!\/\1\])'          // An opening bracket not followed by the closing shortcode tag.
416
+			. '[^\[]*+'               // Not an opening bracket
417
+			. ')*+'
418
+			. ')'
419
+			. '\[\/\1\]'                      // Closing shortcode tag
420
+			. ')?'
421
+			. ')';
422
+	}
423
+
424
+
425
+	/**
426
+	 * This sets the properties related to the messages system
427
+	 *
428
+	 * @return void
429
+	 * @since 4.5.0
430
+	 */
431
+	protected function _set_messages_properties()
432
+	{
433
+		// should be in _extra_data
434
+		if (isset($this->_extra_data['messenger'])) {
435
+			$this->_messenger    = $this->_extra_data['messenger'];
436
+			$this->_message_type = $this->_extra_data['message_type'];
437
+			$this->_context      = $this->_extra_data['message'] instanceof EE_Message
438
+				? $this->_extra_data['message']->context()
439
+				: '';
440
+			$this->_GRP_ID       = $this->_extra_data['message'] instanceof EE_Message
441
+				? $this->_extra_data['message']->GRP_ID()
442
+				: 0;
443
+			$this->_message      = $this->_extra_data['message'] instanceof EE_Message
444
+				? $this->_extra_data['message']
445
+				: null;
446
+		}
447
+	}
448
+
449
+
450
+	/**
451
+	 * This returns whatever the set message type object is that was set on this shortcode parser.
452
+	 *
453
+	 * @return EE_message_type|null
454
+	 * @since 4.5.0
455
+	 */
456
+	public function get_set_message_type(): ?EE_message_type
457
+	{
458
+		return $this->_message_type;
459
+	}
460
+
461
+
462
+	/**
463
+	 * This returns whatever the set messenger object is that was set on this shortcode parser
464
+	 *
465
+	 * @return EE_messenger
466
+	 * @since 4.5.0
467
+	 */
468
+	public function get_set_messenger(): EE_messenger
469
+	{
470
+		return $this->_messenger;
471
+	}
472
+
473
+
474
+	/**
475
+	 * This returns whatever the set context string is on this shortcode parser.
476
+	 *
477
+	 * @return string
478
+	 * @since 4.5.0
479
+	 */
480
+	public function get_set_context(): string
481
+	{
482
+		return $this->_context;
483
+	}
484
+
485
+
486
+	/**
487
+	 * This returns whatever the set EE_Message object is on this shortcode.
488
+	 *
489
+	 * @return EE_Message|null
490
+	 * @since 4.9.0
491
+	 */
492
+	public function get_set_message(): ?EE_Message
493
+	{
494
+		return $this->_message;
495
+	}
496 496
 }
Please login to merge, or discard this patch.
Spacing   +12 added lines, -12 removed lines patch added patch discarded remove patch
@@ -192,10 +192,10 @@  discard block
 block discarded – undo
192 192
 
193 193
         // we need to set up any dynamic shortcodes so that they work with the array_key_exists
194 194
         preg_match_all(EE_Shortcodes::REGEX_SHORTCODE_NAME_ONLY, $shortcode, $matches);
195
-        $shortcode_to_verify = ! empty($matches[0]) ? $matches[0][0] . ']' : $shortcode;
195
+        $shortcode_to_verify = ! empty($matches[0]) ? $matches[0][0].']' : $shortcode;
196 196
 
197 197
         // first we want to make sure this is a valid shortcode
198
-        if (! array_key_exists($shortcode_to_verify, $this->_shortcodes)) {
198
+        if ( ! array_key_exists($shortcode_to_verify, $this->_shortcodes)) {
199 199
             // get out, this parser doesn't handle the incoming shortcode.
200 200
             return '';
201 201
         }
@@ -203,7 +203,7 @@  discard block
 block discarded – undo
203 203
         $this->_extra_data = $extra_data;
204 204
         $this->_set_messages_properties();
205 205
         $parsed = (string) apply_filters(
206
-            'FHEE__' . get_class($this) . '__parser_after',
206
+            'FHEE__'.get_class($this).'__parser_after',
207 207
             $this->_parser($shortcode),
208 208
             $shortcode,
209 209
             $data,
@@ -231,7 +231,7 @@  discard block
 block discarded – undo
231 231
     public function get_shortcodes(): array
232 232
     {
233 233
         $this->_shortcodes = (array) apply_filters(
234
-            'FHEE__' . get_class($this) . '__shortcodes',
234
+            'FHEE__'.get_class($this).'__shortcodes',
235 235
             $this->_shortcodes,
236 236
             $this
237 237
         );
@@ -271,7 +271,7 @@  discard block
 block discarded – undo
271 271
     protected function _validate_list_requirements()
272 272
     {
273 273
         // first test to make sure we've got an array!
274
-        if (! is_array($this->_data)) {
274
+        if ( ! is_array($this->_data)) {
275 275
             throw new EE_Error(
276 276
                 sprintf(
277 277
                     esc_html__(
@@ -285,7 +285,7 @@  discard block
 block discarded – undo
285 285
         }
286 286
 
287 287
         // next test to make sure we've got the required template in the index!
288
-        if (! isset($this->_data['template'])) {
288
+        if ( ! isset($this->_data['template'])) {
289 289
             throw new EE_Error(
290 290
                 esc_html__(
291 291
                     'The incoming data does not have the required template index in its array',
@@ -295,7 +295,7 @@  discard block
 block discarded – undo
295 295
         }
296 296
 
297 297
         // next test to make sure we've got a data index in the incoming data array
298
-        if (! isset($this->_data['data'])) {
298
+        if ( ! isset($this->_data['data'])) {
299 299
             throw new EE_Error(
300 300
                 esc_html__(
301 301
                     'The incoming data does not have the required data index in its array',
@@ -324,8 +324,8 @@  discard block
 block discarded – undo
324 324
     {
325 325
         // make sure the required wp helper function is present
326 326
         // require the shortcode file if necessary
327
-        if (! function_exists('shortcode_parse_atts')) {
328
-            require_once(ABSPATH . WPINC . '/shortcodes.php');
327
+        if ( ! function_exists('shortcode_parse_atts')) {
328
+            require_once(ABSPATH.WPINC.'/shortcodes.php');
329 329
         }
330 330
 
331 331
         // let's get any attributes that may be present and set the defaults.
@@ -350,15 +350,15 @@  discard block
 block discarded – undo
350 350
     protected function _mutate_conditional_block_in_template(string $shortcode, bool $show = true): string
351 351
     {
352 352
         // first let's get all the matches in the template for this particular shortcode.
353
-        preg_match_all('~' . $this->_get_conditional_block_regex($shortcode) . '~', $this->_data['template'], $matches);
353
+        preg_match_all('~'.$this->_get_conditional_block_regex($shortcode).'~', $this->_data['template'], $matches);
354 354
 
355 355
         if ($matches && is_array($matches[0]) && ! empty($matches[0])) {
356 356
             // we need to hide all instances of the matches
357 357
             foreach ($matches[0] as $index => $content_to_show_or_hide) {
358 358
                 $content_to_show_or_hide = preg_quote($content_to_show_or_hide);
359
-                $replacement             = $show ? $matches[4][ $index ] : '';
359
+                $replacement             = $show ? $matches[4][$index] : '';
360 360
                 $this->_data['template'] = preg_replace(
361
-                    '~' . $content_to_show_or_hide . '~',
361
+                    '~'.$content_to_show_or_hide.'~',
362 362
                     $replacement,
363 363
                     $this->_data['template']
364 364
                 );
Please login to merge, or discard this patch.
core/libraries/messages/validators/EE_Messages_Validator.core.php 2 patches
Indentation   +598 added lines, -598 removed lines patch added patch discarded remove patch
@@ -15,602 +15,602 @@
 block discarded – undo
15 15
  */
16 16
 abstract class EE_Messages_Validator extends EE_Base
17 17
 {
18
-    /**
19
-     * These properties just hold the name for the Messenger and Message Type (defined by child classes).
20
-     * These are used for retrieving objects etc.
21
-     *
22
-     * @var string
23
-     */
24
-    protected string $_m_name = '';
25
-
26
-    protected string $_mt_name = '';
27
-
28
-
29
-    /**
30
-     * This will hold any error messages from the validation process.
31
-     * The _errors property holds an associative array of error messages
32
-     * listing the field as the key and the message as the value.
33
-     *
34
-     * @var array
35
-     */
36
-    private array $_errors = [];
37
-
38
-
39
-    /**
40
-     * holds an array of fields being validated
41
-     *
42
-     * @var array
43
-     */
44
-    protected array $_fields = [];
45
-
46
-
47
-    /**
48
-     * this will hold the incoming context
49
-     *
50
-     * @var string
51
-     */
52
-    protected string $_context = '';
53
-
54
-
55
-    /**
56
-     * this holds an array of fields and the relevant validation information
57
-     * that the incoming fields data get validated against.
58
-     * This gets setup in the _set_props() method.
59
-     *
60
-     * @var array
61
-     */
62
-    protected array $_validators = [];
63
-
64
-    protected EE_messenger $_messenger;
65
-
66
-
67
-    protected EE_message_type $_message_type;
68
-
69
-
70
-    /**
71
-     * will hold any valid_shortcode modifications made by the _modify_validator() method.
72
-     *
73
-     * @var array
74
-     */
75
-    protected array $_valid_shortcodes_modifier = [];
76
-
77
-
78
-    /**
79
-     * There may be times when a message type wants to include a shortcode group but exclude specific
80
-     * shortcodes.  If that's the case then it can set this property as an array of shortcodes to exclude and
81
-     * they will not be allowed.
82
-     * Array should be indexed by field and values are an array of specific shortcodes to exclude.
83
-     *
84
-     * @var array
85
-     */
86
-    protected array $_specific_shortcode_excludes = [];
87
-
88
-
89
-    /**
90
-     * Runs the validator using the incoming fields array as the fields/values to check.
91
-     *
92
-     * @param array  $fields The fields sent by the EEM object.
93
-     * @param string $context
94
-     * @throws EE_Error
95
-     * @throws ReflectionException
96
-     */
97
-    public function __construct($fields, $context)
98
-    {
99
-        // checks that child class has set _m_name and _mt_name, otherwise we get out.
100
-        if (empty($this->_m_name) || empty($this->_mt_name)) {
101
-            throw new EE_Error(
102
-                esc_html__(
103
-                    'EE_Messages_Validator child classes MUST set the $_m_name and $_mt_name property.  Check that the child class is doing this',
104
-                    'event_espresso'
105
-                )
106
-            );
107
-        }
108
-        $this->_fields  = (array) $fields;
109
-        $this->_context = (string) $context;
110
-
111
-        $this->loadMessengerAndMessageType();
112
-        // modify any messenger/message_type specific validation instructions.  This is what child classes define.
113
-        $this->_modify_validator();
114
-        // let's set validators property
115
-        $this->setValidators();
116
-    }
117
-
118
-
119
-    /**
120
-     * Child classes instantiate this and use it to modify the _validator_config array property
121
-     * for the messenger using messengers set_validate_config() method.
122
-     * This is so we can specify specific validation instructions for a messenger/message_type combo
123
-     * that aren't handled by the defaults setup in the messenger.
124
-     *
125
-     * @abstract
126
-     * @return void
127
-     */
128
-    abstract protected function _modify_validator();
129
-
130
-
131
-    /**
132
-     * loads all objects used by validator
133
-     *
134
-     * @throws EE_Error
135
-     */
136
-    private function loadMessengerAndMessageType()
137
-    {
138
-        // load messenger
139
-        $messenger = ucwords(str_replace('_', ' ', $this->_m_name));
140
-        $messenger = str_replace(' ', '_', $messenger);
141
-        $messenger = 'EE_' . $messenger . '_messenger';
142
-
143
-        if (! class_exists($messenger)) {
144
-            throw new EE_Error(
145
-                sprintf(
146
-                    esc_html__('There is no messenger class for the given string (%s)', 'event_espresso'),
147
-                    $this->_m_name
148
-                )
149
-            );
150
-        }
151
-
152
-        $this->_messenger = new $messenger();
153
-
154
-        // load message type
155
-        $message_type = ucwords(str_replace('_', ' ', $this->_mt_name));
156
-        $message_type = str_replace(' ', '_', $message_type);
157
-        $message_type = 'EE_' . $message_type . '_message_type';
158
-
159
-        if (! class_exists($message_type)) {
160
-            throw new EE_Error(
161
-                sprintf(
162
-                    esc_html__('There is no message type class for the given string (%s)', 'event_espresso'),
163
-                    $this->_mt_name
164
-                )
165
-            );
166
-        }
167
-
168
-        $this->_message_type = new $message_type();
169
-    }
170
-
171
-
172
-    /**
173
-     * used to set the $_validators property
174
-     *
175
-     * @return void
176
-     * @throws ReflectionException
177
-     */
178
-    private function setValidators()
179
-    {
180
-        // let's get all valid shortcodes from mt and message type
181
-        // (messenger will have its set in the _validator_config property for the messenger)
182
-        $mt_codes = $this->_message_type->get_valid_shortcodes();
183
-        // get messenger validator_config
184
-        $msgr_validator = $this->_messenger->get_validator_config();
185
-        // we only want the valid shortcodes for the given context!
186
-        $context  = $this->_context;
187
-        $mt_codes = $mt_codes[ $context ];
188
-        // in this first loop we're just getting all shortcode group indexes from the msgr_validator
189
-        // into a single array (so we can get the appropriate shortcode objects for the groups)
190
-        $shortcode_groups = $mt_codes;
191
-        $groups_per_field = [];
192
-
193
-        foreach ($msgr_validator as $field => $config) {
194
-            if (! isset($config['shortcodes'])) {
195
-                continue;
196
-            }  //Nothing to see here.
197
-            $groups_per_field[ $field ] = array_intersect($config['shortcodes'], $mt_codes);
198
-            $shortcode_groups           = array_merge($config['shortcodes'], $shortcode_groups);
199
-        }
200
-        $shortcode_groups = array_unique($shortcode_groups);
201
-
202
-        // okay now we've got our groups.
203
-        // Let's get the codes from the objects into an array indexed by group for easy retrieval later.
204
-        $codes_from_objs = [];
205
-
206
-        foreach ($shortcode_groups as $group) {
207
-            $ref       = ucwords(str_replace('_', ' ', $group));
208
-            $ref       = str_replace(' ', '_', $ref);
209
-            $classname = 'EE_' . $ref . '_Shortcodes';
210
-            if (class_exists($classname)) {
211
-                $a                         = new ReflectionClass($classname);
212
-                $obj                       = $a->newInstance();
213
-                $codes_from_objs[ $group ] = $obj->get_shortcodes();
214
-            }
215
-        }
216
-
217
-        // let's just replace the $mt shortcode group indexes with the actual shortcodes (unique)
218
-        $final_mt_codes = [];
219
-        foreach ($mt_codes as $group) {
220
-            $final_mt_codes = array_merge($final_mt_codes, $codes_from_objs[ $group ]);
221
-        }
222
-        $mt_codes = $final_mt_codes;
223
-
224
-        // k now in this next loop we're going to loop through $msgr_validator again
225
-        // and set up the _validators property from the data we've setup so far.
226
-        foreach ($msgr_validator as $field => $config) {
227
-            // if required shortcode is not in our list of codes for the given field, then we skip this field.
228
-            $required = isset($config['required'])
229
-                ? array_intersect($config['required'], array_keys($mt_codes))
230
-                : true;
231
-            if (empty($required)) {
232
-                continue;
233
-            }
234
-
235
-            if (isset($this->_valid_shortcodes_modifier[ $context ][ $field ])) {
236
-                // If we have an override then we use it to indicate the codes we want.
237
-                $this->_validators[ $field ]['shortcodes'] = $this->reassembleValidShortcodesFromGroup(
238
-                    $this->_valid_shortcodes_modifier[ $context ][ $field ],
239
-                    $codes_from_objs
240
-                );
241
-            } elseif (isset($groups_per_field[ $field ])) {
242
-                // we have specific shortcodes for a field so we need to use them
243
-                $this->_validators[ $field ]['shortcodes'] = $this->reassembleValidShortcodesFromGroup(
244
-                    $groups_per_field[ $field ],
245
-                    $codes_from_objs
246
-                );
247
-            } elseif (empty($config)) {
248
-                // no config so we're assuming we're just going to use the shortcodes from the message type context
249
-                $this->_validators[ $field ]['shortcodes'] = $mt_codes;
250
-            } elseif (isset($config['specific_shortcodes'])) {
251
-                // we have specific shortcodes so we need to use them
252
-                $this->_validators[ $field ]['shortcodes'] = $config['specific_shortcodes'];
253
-            } else {
254
-                // otherwise the shortcodes are what is set by the messenger for that field
255
-                foreach ($config['shortcodes'] as $group) {
256
-                    $this->_validators[ $field ]['shortcodes'] = isset($this->_validators[ $field ]['shortcodes'])
257
-                        ? array_merge($this->_validators[ $field ]['shortcodes'], $codes_from_objs[ $group ])
258
-                        : $codes_from_objs[ $group ];
259
-                }
260
-            }
261
-
262
-            // now let's just make sure that any excluded specific shortcodes are removed.
263
-            $specific_excludes = $this->get_specific_shortcode_excludes();
264
-            if (isset($specific_excludes[ $field ])) {
265
-                foreach ($specific_excludes[ $field ] as $sex) {
266
-                    if (isset($this->_validators[ $field ]['shortcodes'][ $sex ])) {
267
-                        unset($this->_validators[ $field ]['shortcodes'][ $sex ]);
268
-                    }
269
-                }
270
-            }
271
-
272
-            // hey! don't forget to include the type if present!
273
-            $this->_validators[ $field ]['type'] = $config['type'] ?? null;
274
-        }
275
-    }
276
-
277
-
278
-    /**
279
-     * This just returns the validators property that contains information
280
-     * about the various shortcodes and their availability with each field
281
-     *
282
-     * @return array
283
-     */
284
-    public function get_validators(): array
285
-    {
286
-        return $this->_validators;
287
-    }
288
-
289
-
290
-    /**
291
-     * This simply returns the specific shortcode_excludes property that is set.
292
-     *
293
-     * @return array
294
-     * @since 4.5.0
295
-     */
296
-    public function get_specific_shortcode_excludes(): array
297
-    {
298
-        // specific validator filter
299
-        $shortcode_excludes = (array) apply_filters(
300
-            'FHEE__' . get_class($this) . '__get_specific_shortcode_excludes;',
301
-            $this->_specific_shortcode_excludes,
302
-            $this->_context
303
-        );
304
-        // global filter
305
-        return (array) apply_filters(
306
-            'FHEE__EE_Messages_Validator__get_specific_shortcode_excludes',
307
-            $shortcode_excludes,
308
-            $this->_context,
309
-            $this
310
-        );
311
-    }
312
-
313
-
314
-    /**
315
-     * This is the main method that handles validation
316
-     * What it does is loop through the _fields (the ones that get validated)
317
-     * and checks them against the shortcodes array for the field and the 'type' indicated by the
318
-     *
319
-     * @return array|bool if errors present we return the array otherwise true
320
-     */
321
-    public function validate()
322
-    {
323
-        // some defaults
324
-        $template_fields = $this->_messenger->get_template_fields();
325
-        // loop through the fields and check!
326
-        foreach ($this->_fields as $field => $value) {
327
-            $this->_errors[ $field ] = [];
328
-            $err_msg                 = '';
329
-            $field_label             = '';
330
-            // if field is not present in the _validators array then we continue
331
-            if (! isset($this->_validators[ $field ])) {
332
-                unset($this->_errors[ $field ]);
333
-                continue;
334
-            }
335
-
336
-            // get the translated field label!
337
-            // first check if it's in the main fields list
338
-            if (isset($template_fields[ $field ])) {
339
-                // most likely the field is found in the 'extra' array.
340
-                $field_label = ! empty($template_fields[ $field ])
341
-                    ? $template_fields[ $field ]['label']
342
-                    : $field;
343
-            }
344
-
345
-            // if field label is empty OR is equal to the current field
346
-            // then we need to loop through the 'extra' fields in the template_fields config (if present)
347
-            if (isset($template_fields['extra']) && (empty($field_label) || $field_label === $field)) {
348
-                foreach ($template_fields['extra'] as $main_field => $secondary_field) {
349
-                    foreach ($secondary_field as $name => $values) {
350
-                        if ($name === $field) {
351
-                            $field_label = $values['label'];
352
-                        }
353
-
354
-                        // if we've got a 'main' secondary field, let's see if that matches what field we're on
355
-                        // which means it contains the label for this field.
356
-                        if ($name === 'main' && $main_field === $field_label) {
357
-                            $field_label = $values['label'];
358
-                        }
359
-                    }
360
-                }
361
-            }
362
-
363
-            // field is present. Let's validate shortcodes first (but only if shortcodes present).
364
-            if (
365
-                isset($this->_validators[ $field ]['shortcodes'])
366
-                && ! empty($this->_validators[ $field ]['shortcodes'])
367
-            ) {
368
-                $valid_shortcodes   = array_keys((array) $this->_validators[ $field ]['shortcodes']);
369
-                $invalid_shortcodes = $this->findInvalidShortcodes((string) $value, $valid_shortcodes);
370
-                // if true then that means there is a returned error message
371
-                // that we'll need to add to the _errors array for this field.
372
-                if ($invalid_shortcodes) {
373
-                    $v_s     = array_keys($this->_validators[ $field ]['shortcodes']);
374
-                    $err_msg = sprintf(
375
-                        esc_html__(
376
-                            '%3$sThe following shortcodes were found in the "%1$s" field that ARE not valid: %2$s%4$s',
377
-                            'event_espresso'
378
-                        ),
379
-                        '<strong>' . $field_label . '</strong>',
380
-                        $invalid_shortcodes,
381
-                        '<p>',
382
-                        '</p >'
383
-                    );
384
-                    $err_msg .= sprintf(
385
-                        esc_html__('%2$sValid shortcodes for this field are: %1$s%3$s', 'event_espresso'),
386
-                        implode(', ', $v_s),
387
-                        '<strong>',
388
-                        '</strong>'
389
-                    );
390
-                }
391
-            }
392
-
393
-            // if there's a "type" to be validated then let's do that too.
394
-            if (isset($this->_validators[ $field ]['type']) && ! empty($this->_validators[ $field ]['type'])) {
395
-                switch ($this->_validators[ $field ]['type']) {
396
-                    case 'number':
397
-                        if (! is_numeric($value)) {
398
-                            $err_msg .= sprintf(
399
-                                esc_html__(
400
-                                    '%3$sThe %1$s field is supposed to be a number. The value given (%2$s)  is not.  Please double-check and make sure the field contains a number%4$s',
401
-                                    'event_espresso'
402
-                                ),
403
-                                $field_label,
404
-                                $value,
405
-                                '<p>',
406
-                                '</p >'
407
-                            );
408
-                        }
409
-                        break;
410
-                    case 'email':
411
-                        $valid_email = $this->_validate_email((string) $value);
412
-                        if (! $valid_email) {
413
-                            $err_msg .= htmlentities(
414
-                                sprintf(
415
-                                    esc_html__(
416
-                                        'The %1$s field has at least one string that is not a valid email address record.  Valid emails are in the format: "Name <[email protected]>" or "[email protected]" and multiple emails can be separated by a comma.',
417
-                                        'event_espresso'
418
-                                    ),
419
-                                    $field_label
420
-                                )
421
-                            );
422
-                        }
423
-                        break;
424
-                    default:
425
-                        break;
426
-                }
427
-            }
428
-
429
-            // if $err_msg isn't empty, let's set up the _errors array for this field.
430
-            if (! empty($err_msg)) {
431
-                $this->_errors[ $field ]['msg'] = $err_msg;
432
-            } else {
433
-                unset($this->_errors[ $field ]);
434
-            }
435
-        }
436
-
437
-        // if we have ANY errors, then we want to make sure we return the values
438
-        // for ALL the fields so the user doesn't have to retype them all.
439
-        if (! empty($this->_errors)) {
440
-            foreach ($this->_fields as $field => $value) {
441
-                $this->_errors[ $field ]['value'] = stripslashes($value);
442
-            }
443
-        }
444
-
445
-        // return any errors or just TRUE if everything validates
446
-        return empty($this->_errors)
447
-            ? true
448
-            : $this->_errors;
449
-    }
450
-
451
-
452
-    /**
453
-     * Reassembles and returns an array of valid shortcodes
454
-     * given the array of groups and array of shortcodes indexed by group.
455
-     *
456
-     * @param array $groups          array of shortcode groups that we want shortcodes for
457
-     * @param array $codes_from_objs All the codes available.
458
-     * @return array                   an array of actual shortcodes (that will be used for validation).
459
-     */
460
-    private function reassembleValidShortcodesFromGroup(array $groups, array $codes_from_objs): array
461
-    {
462
-        $shortcodes = [];
463
-        foreach ($groups as $group) {
464
-            $shortcodes = array_merge($shortcodes, $codes_from_objs[ $group ]);
465
-        }
466
-        return $shortcodes;
467
-    }
468
-
469
-
470
-    /**
471
-     * Validates a string against a list of accepted shortcodes
472
-     * This function takes in an array of shortcodes
473
-     * and makes sure that the given string ONLY contains shortcodes in that array.
474
-     *
475
-     * @param string $value            string to evaluate
476
-     * @param array  $valid_shortcodes array of shortcodes that are acceptable.
477
-     * @return bool|string  return either a list of invalid shortcodes OR false if the shortcodes validate.
478
-     * @deprecated 5.0.48
479
-     */
480
-    protected function _invalid_shortcodes(string $value, array $valid_shortcodes)
481
-    {
482
-        return $this->findInvalidShortcodes($value, $valid_shortcodes) ?: false;
483
-    }
484
-
485
-
486
-    /**
487
-     * Validates a string against a list of accepted shortcodes
488
-     * This function takes in an array of shortcodes
489
-     * and makes sure that the given string ONLY contains shortcodes in that array.
490
-     *
491
-     * @param string $incoming_text    string to evaluate
492
-     * @param array  $valid_shortcodes array of shortcodes that are acceptable.
493
-     * @return string  return either a list of invalid shortcodes OR false if the shortcodes validate.
494
-     */
495
-    protected function findInvalidShortcodes(string $incoming_text, array $valid_shortcodes): string
496
-    {
497
-        // first we need to go through the string and get ALL the shortcodes in the string
498
-        // matches the opening [ plus the shortcode name, but nothing else
499
-        // examples:
500
-        //  [RECIPIENT_LNAME] matches as [RECIPIENT_LNAME
501
-        //  [RECEIPT_URL download=true] matches as [RECEIPT_URL
502
-        //  [PAYMENT_LINK_IF_NEEDED_* custom_text='pay me now man!'] matches as [PAYMENT_LINK_IF_NEEDED_*
503
-        preg_match_all(EE_Shortcodes::REGEX_SHORTCODE_NAME_ONLY, $incoming_text, $matches);
504
-        $shortcodes_in_text = $matches[0];
505
-        // now all we need to do is add the closing ] to each shortcode to make them "valid"
506
-        $shortcodes_in_text = array_map(fn($shortcode) => rtrim($shortcode) . ']', $shortcodes_in_text);
507
-        // get a diff of the shortcodes in the string vs the valid shortcodes
508
-        $invalid_shortcodes = array_diff($shortcodes_in_text, $valid_shortcodes);
509
-        if (empty($invalid_shortcodes)) {
510
-            return '';
511
-        }
512
-        // made it here? then let's assemble the error message
513
-        return '<strong>' . implode('</strong>,<strong>', $invalid_shortcodes) . '</strong>';
514
-    }
515
-
516
-
517
-    /**
518
-     * Validates an incoming string and makes sure we have valid emails in the string.
519
-     *
520
-     * @param string $value incoming value to validate
521
-     * @return bool        true if the string validates, false if it doesn't
522
-     */
523
-    protected function _validate_email(string $value): bool
524
-    {
525
-        $or_val = $value;
526
-
527
-        // empty strings will validate because this is how a message template
528
-        // for a particular context can be "turned off" (if there is no email then no message)
529
-        if (empty($value)) {
530
-            return true;
531
-        }
532
-
533
-        // first determine if there ARE any shortcodes.
534
-        // If there are shortcodes and then later we find that there were no other valid emails
535
-        // but the field isn't empty...
536
-        // that means we've got extra commas that were left after stripping out shortcodes so probably still valid.
537
-        $has_shortcodes = preg_match(EE_Shortcodes::REGEX_SHORTCODE_FULL, $value);
538
-
539
-        // first we need to strip out all the shortcodes!
540
-        $value = preg_replace(EE_Shortcodes::REGEX_SHORTCODE_FULL, '', $value);
541
-
542
-        // if original value is not empty and new value is, then we've parsed out a shortcode
543
-        // and we now have an empty string which DOES validate.
544
-        // We also validate complete empty field for email because
545
-        // it's possible that this message is being "turned off" for a particular context
546
-
547
-
548
-        if (! empty($or_val) && empty($value)) {
549
-            return true;
550
-        }
551
-
552
-        // trim any commas from beginning and end of string ( after whitespace trimmed );
553
-        $value = trim(trim($value), ',');
554
-
555
-        // next we need to split up the string if it's comma-delimited.
556
-        $emails = explode(',', $value);
557
-        $empty  = false; // used to indicate that there is an empty comma.
558
-        // now let's loop through the emails and do our checks
559
-        foreach ($emails as $email) {
560
-            if (empty($email)) {
561
-                $empty = true;
562
-                continue;
563
-            }
564
-
565
-            // trim whitespace
566
-            $email = trim($email);
567
-            // either its of type "[email protected]", or its of type "fname lname <[email protected]>"
568
-            if (is_email($email)) {
569
-                continue;
570
-            }
571
-            $matches  = [];
572
-            $validate = (bool) preg_match('/(.*)<(.+)>/', $email, $matches);
573
-            if ($validate && is_email($matches[2])) {
574
-                continue;
575
-            }
576
-            return false;
577
-        }
578
-
579
-        return ! ($empty && ! $has_shortcodes);
580
-    }
581
-
582
-
583
-    /**
584
-     * Magic getter
585
-     * Using this to provide back compat with add-ons referencing deprecated properties.
586
-     *
587
-     * @param string $property Property being requested
588
-     * @return mixed
589
-     * @throws Exception
590
-     */
591
-    public function __get($property)
592
-    {
593
-        $expected_properties_map = [
594
-            /**
595
-             * @deprecated 4.9.0
596
-             */
597
-            '_MSGR'   => '_messenger',
598
-            /**
599
-             * @deprecated 4.9.0
600
-             */
601
-            '_MSGTYP' => '_message_type',
602
-        ];
603
-
604
-        if (isset($expected_properties_map[ $property ])) {
605
-            return $this->{$expected_properties_map[ $property ]};
606
-        }
607
-
608
-        throw new Exception(
609
-            sprintf(
610
-                esc_html__('The property %1$s being requested on %2$s does not exist', 'event_espresso'),
611
-                $property,
612
-                get_class($this)
613
-            )
614
-        );
615
-    }
18
+	/**
19
+	 * These properties just hold the name for the Messenger and Message Type (defined by child classes).
20
+	 * These are used for retrieving objects etc.
21
+	 *
22
+	 * @var string
23
+	 */
24
+	protected string $_m_name = '';
25
+
26
+	protected string $_mt_name = '';
27
+
28
+
29
+	/**
30
+	 * This will hold any error messages from the validation process.
31
+	 * The _errors property holds an associative array of error messages
32
+	 * listing the field as the key and the message as the value.
33
+	 *
34
+	 * @var array
35
+	 */
36
+	private array $_errors = [];
37
+
38
+
39
+	/**
40
+	 * holds an array of fields being validated
41
+	 *
42
+	 * @var array
43
+	 */
44
+	protected array $_fields = [];
45
+
46
+
47
+	/**
48
+	 * this will hold the incoming context
49
+	 *
50
+	 * @var string
51
+	 */
52
+	protected string $_context = '';
53
+
54
+
55
+	/**
56
+	 * this holds an array of fields and the relevant validation information
57
+	 * that the incoming fields data get validated against.
58
+	 * This gets setup in the _set_props() method.
59
+	 *
60
+	 * @var array
61
+	 */
62
+	protected array $_validators = [];
63
+
64
+	protected EE_messenger $_messenger;
65
+
66
+
67
+	protected EE_message_type $_message_type;
68
+
69
+
70
+	/**
71
+	 * will hold any valid_shortcode modifications made by the _modify_validator() method.
72
+	 *
73
+	 * @var array
74
+	 */
75
+	protected array $_valid_shortcodes_modifier = [];
76
+
77
+
78
+	/**
79
+	 * There may be times when a message type wants to include a shortcode group but exclude specific
80
+	 * shortcodes.  If that's the case then it can set this property as an array of shortcodes to exclude and
81
+	 * they will not be allowed.
82
+	 * Array should be indexed by field and values are an array of specific shortcodes to exclude.
83
+	 *
84
+	 * @var array
85
+	 */
86
+	protected array $_specific_shortcode_excludes = [];
87
+
88
+
89
+	/**
90
+	 * Runs the validator using the incoming fields array as the fields/values to check.
91
+	 *
92
+	 * @param array  $fields The fields sent by the EEM object.
93
+	 * @param string $context
94
+	 * @throws EE_Error
95
+	 * @throws ReflectionException
96
+	 */
97
+	public function __construct($fields, $context)
98
+	{
99
+		// checks that child class has set _m_name and _mt_name, otherwise we get out.
100
+		if (empty($this->_m_name) || empty($this->_mt_name)) {
101
+			throw new EE_Error(
102
+				esc_html__(
103
+					'EE_Messages_Validator child classes MUST set the $_m_name and $_mt_name property.  Check that the child class is doing this',
104
+					'event_espresso'
105
+				)
106
+			);
107
+		}
108
+		$this->_fields  = (array) $fields;
109
+		$this->_context = (string) $context;
110
+
111
+		$this->loadMessengerAndMessageType();
112
+		// modify any messenger/message_type specific validation instructions.  This is what child classes define.
113
+		$this->_modify_validator();
114
+		// let's set validators property
115
+		$this->setValidators();
116
+	}
117
+
118
+
119
+	/**
120
+	 * Child classes instantiate this and use it to modify the _validator_config array property
121
+	 * for the messenger using messengers set_validate_config() method.
122
+	 * This is so we can specify specific validation instructions for a messenger/message_type combo
123
+	 * that aren't handled by the defaults setup in the messenger.
124
+	 *
125
+	 * @abstract
126
+	 * @return void
127
+	 */
128
+	abstract protected function _modify_validator();
129
+
130
+
131
+	/**
132
+	 * loads all objects used by validator
133
+	 *
134
+	 * @throws EE_Error
135
+	 */
136
+	private function loadMessengerAndMessageType()
137
+	{
138
+		// load messenger
139
+		$messenger = ucwords(str_replace('_', ' ', $this->_m_name));
140
+		$messenger = str_replace(' ', '_', $messenger);
141
+		$messenger = 'EE_' . $messenger . '_messenger';
142
+
143
+		if (! class_exists($messenger)) {
144
+			throw new EE_Error(
145
+				sprintf(
146
+					esc_html__('There is no messenger class for the given string (%s)', 'event_espresso'),
147
+					$this->_m_name
148
+				)
149
+			);
150
+		}
151
+
152
+		$this->_messenger = new $messenger();
153
+
154
+		// load message type
155
+		$message_type = ucwords(str_replace('_', ' ', $this->_mt_name));
156
+		$message_type = str_replace(' ', '_', $message_type);
157
+		$message_type = 'EE_' . $message_type . '_message_type';
158
+
159
+		if (! class_exists($message_type)) {
160
+			throw new EE_Error(
161
+				sprintf(
162
+					esc_html__('There is no message type class for the given string (%s)', 'event_espresso'),
163
+					$this->_mt_name
164
+				)
165
+			);
166
+		}
167
+
168
+		$this->_message_type = new $message_type();
169
+	}
170
+
171
+
172
+	/**
173
+	 * used to set the $_validators property
174
+	 *
175
+	 * @return void
176
+	 * @throws ReflectionException
177
+	 */
178
+	private function setValidators()
179
+	{
180
+		// let's get all valid shortcodes from mt and message type
181
+		// (messenger will have its set in the _validator_config property for the messenger)
182
+		$mt_codes = $this->_message_type->get_valid_shortcodes();
183
+		// get messenger validator_config
184
+		$msgr_validator = $this->_messenger->get_validator_config();
185
+		// we only want the valid shortcodes for the given context!
186
+		$context  = $this->_context;
187
+		$mt_codes = $mt_codes[ $context ];
188
+		// in this first loop we're just getting all shortcode group indexes from the msgr_validator
189
+		// into a single array (so we can get the appropriate shortcode objects for the groups)
190
+		$shortcode_groups = $mt_codes;
191
+		$groups_per_field = [];
192
+
193
+		foreach ($msgr_validator as $field => $config) {
194
+			if (! isset($config['shortcodes'])) {
195
+				continue;
196
+			}  //Nothing to see here.
197
+			$groups_per_field[ $field ] = array_intersect($config['shortcodes'], $mt_codes);
198
+			$shortcode_groups           = array_merge($config['shortcodes'], $shortcode_groups);
199
+		}
200
+		$shortcode_groups = array_unique($shortcode_groups);
201
+
202
+		// okay now we've got our groups.
203
+		// Let's get the codes from the objects into an array indexed by group for easy retrieval later.
204
+		$codes_from_objs = [];
205
+
206
+		foreach ($shortcode_groups as $group) {
207
+			$ref       = ucwords(str_replace('_', ' ', $group));
208
+			$ref       = str_replace(' ', '_', $ref);
209
+			$classname = 'EE_' . $ref . '_Shortcodes';
210
+			if (class_exists($classname)) {
211
+				$a                         = new ReflectionClass($classname);
212
+				$obj                       = $a->newInstance();
213
+				$codes_from_objs[ $group ] = $obj->get_shortcodes();
214
+			}
215
+		}
216
+
217
+		// let's just replace the $mt shortcode group indexes with the actual shortcodes (unique)
218
+		$final_mt_codes = [];
219
+		foreach ($mt_codes as $group) {
220
+			$final_mt_codes = array_merge($final_mt_codes, $codes_from_objs[ $group ]);
221
+		}
222
+		$mt_codes = $final_mt_codes;
223
+
224
+		// k now in this next loop we're going to loop through $msgr_validator again
225
+		// and set up the _validators property from the data we've setup so far.
226
+		foreach ($msgr_validator as $field => $config) {
227
+			// if required shortcode is not in our list of codes for the given field, then we skip this field.
228
+			$required = isset($config['required'])
229
+				? array_intersect($config['required'], array_keys($mt_codes))
230
+				: true;
231
+			if (empty($required)) {
232
+				continue;
233
+			}
234
+
235
+			if (isset($this->_valid_shortcodes_modifier[ $context ][ $field ])) {
236
+				// If we have an override then we use it to indicate the codes we want.
237
+				$this->_validators[ $field ]['shortcodes'] = $this->reassembleValidShortcodesFromGroup(
238
+					$this->_valid_shortcodes_modifier[ $context ][ $field ],
239
+					$codes_from_objs
240
+				);
241
+			} elseif (isset($groups_per_field[ $field ])) {
242
+				// we have specific shortcodes for a field so we need to use them
243
+				$this->_validators[ $field ]['shortcodes'] = $this->reassembleValidShortcodesFromGroup(
244
+					$groups_per_field[ $field ],
245
+					$codes_from_objs
246
+				);
247
+			} elseif (empty($config)) {
248
+				// no config so we're assuming we're just going to use the shortcodes from the message type context
249
+				$this->_validators[ $field ]['shortcodes'] = $mt_codes;
250
+			} elseif (isset($config['specific_shortcodes'])) {
251
+				// we have specific shortcodes so we need to use them
252
+				$this->_validators[ $field ]['shortcodes'] = $config['specific_shortcodes'];
253
+			} else {
254
+				// otherwise the shortcodes are what is set by the messenger for that field
255
+				foreach ($config['shortcodes'] as $group) {
256
+					$this->_validators[ $field ]['shortcodes'] = isset($this->_validators[ $field ]['shortcodes'])
257
+						? array_merge($this->_validators[ $field ]['shortcodes'], $codes_from_objs[ $group ])
258
+						: $codes_from_objs[ $group ];
259
+				}
260
+			}
261
+
262
+			// now let's just make sure that any excluded specific shortcodes are removed.
263
+			$specific_excludes = $this->get_specific_shortcode_excludes();
264
+			if (isset($specific_excludes[ $field ])) {
265
+				foreach ($specific_excludes[ $field ] as $sex) {
266
+					if (isset($this->_validators[ $field ]['shortcodes'][ $sex ])) {
267
+						unset($this->_validators[ $field ]['shortcodes'][ $sex ]);
268
+					}
269
+				}
270
+			}
271
+
272
+			// hey! don't forget to include the type if present!
273
+			$this->_validators[ $field ]['type'] = $config['type'] ?? null;
274
+		}
275
+	}
276
+
277
+
278
+	/**
279
+	 * This just returns the validators property that contains information
280
+	 * about the various shortcodes and their availability with each field
281
+	 *
282
+	 * @return array
283
+	 */
284
+	public function get_validators(): array
285
+	{
286
+		return $this->_validators;
287
+	}
288
+
289
+
290
+	/**
291
+	 * This simply returns the specific shortcode_excludes property that is set.
292
+	 *
293
+	 * @return array
294
+	 * @since 4.5.0
295
+	 */
296
+	public function get_specific_shortcode_excludes(): array
297
+	{
298
+		// specific validator filter
299
+		$shortcode_excludes = (array) apply_filters(
300
+			'FHEE__' . get_class($this) . '__get_specific_shortcode_excludes;',
301
+			$this->_specific_shortcode_excludes,
302
+			$this->_context
303
+		);
304
+		// global filter
305
+		return (array) apply_filters(
306
+			'FHEE__EE_Messages_Validator__get_specific_shortcode_excludes',
307
+			$shortcode_excludes,
308
+			$this->_context,
309
+			$this
310
+		);
311
+	}
312
+
313
+
314
+	/**
315
+	 * This is the main method that handles validation
316
+	 * What it does is loop through the _fields (the ones that get validated)
317
+	 * and checks them against the shortcodes array for the field and the 'type' indicated by the
318
+	 *
319
+	 * @return array|bool if errors present we return the array otherwise true
320
+	 */
321
+	public function validate()
322
+	{
323
+		// some defaults
324
+		$template_fields = $this->_messenger->get_template_fields();
325
+		// loop through the fields and check!
326
+		foreach ($this->_fields as $field => $value) {
327
+			$this->_errors[ $field ] = [];
328
+			$err_msg                 = '';
329
+			$field_label             = '';
330
+			// if field is not present in the _validators array then we continue
331
+			if (! isset($this->_validators[ $field ])) {
332
+				unset($this->_errors[ $field ]);
333
+				continue;
334
+			}
335
+
336
+			// get the translated field label!
337
+			// first check if it's in the main fields list
338
+			if (isset($template_fields[ $field ])) {
339
+				// most likely the field is found in the 'extra' array.
340
+				$field_label = ! empty($template_fields[ $field ])
341
+					? $template_fields[ $field ]['label']
342
+					: $field;
343
+			}
344
+
345
+			// if field label is empty OR is equal to the current field
346
+			// then we need to loop through the 'extra' fields in the template_fields config (if present)
347
+			if (isset($template_fields['extra']) && (empty($field_label) || $field_label === $field)) {
348
+				foreach ($template_fields['extra'] as $main_field => $secondary_field) {
349
+					foreach ($secondary_field as $name => $values) {
350
+						if ($name === $field) {
351
+							$field_label = $values['label'];
352
+						}
353
+
354
+						// if we've got a 'main' secondary field, let's see if that matches what field we're on
355
+						// which means it contains the label for this field.
356
+						if ($name === 'main' && $main_field === $field_label) {
357
+							$field_label = $values['label'];
358
+						}
359
+					}
360
+				}
361
+			}
362
+
363
+			// field is present. Let's validate shortcodes first (but only if shortcodes present).
364
+			if (
365
+				isset($this->_validators[ $field ]['shortcodes'])
366
+				&& ! empty($this->_validators[ $field ]['shortcodes'])
367
+			) {
368
+				$valid_shortcodes   = array_keys((array) $this->_validators[ $field ]['shortcodes']);
369
+				$invalid_shortcodes = $this->findInvalidShortcodes((string) $value, $valid_shortcodes);
370
+				// if true then that means there is a returned error message
371
+				// that we'll need to add to the _errors array for this field.
372
+				if ($invalid_shortcodes) {
373
+					$v_s     = array_keys($this->_validators[ $field ]['shortcodes']);
374
+					$err_msg = sprintf(
375
+						esc_html__(
376
+							'%3$sThe following shortcodes were found in the "%1$s" field that ARE not valid: %2$s%4$s',
377
+							'event_espresso'
378
+						),
379
+						'<strong>' . $field_label . '</strong>',
380
+						$invalid_shortcodes,
381
+						'<p>',
382
+						'</p >'
383
+					);
384
+					$err_msg .= sprintf(
385
+						esc_html__('%2$sValid shortcodes for this field are: %1$s%3$s', 'event_espresso'),
386
+						implode(', ', $v_s),
387
+						'<strong>',
388
+						'</strong>'
389
+					);
390
+				}
391
+			}
392
+
393
+			// if there's a "type" to be validated then let's do that too.
394
+			if (isset($this->_validators[ $field ]['type']) && ! empty($this->_validators[ $field ]['type'])) {
395
+				switch ($this->_validators[ $field ]['type']) {
396
+					case 'number':
397
+						if (! is_numeric($value)) {
398
+							$err_msg .= sprintf(
399
+								esc_html__(
400
+									'%3$sThe %1$s field is supposed to be a number. The value given (%2$s)  is not.  Please double-check and make sure the field contains a number%4$s',
401
+									'event_espresso'
402
+								),
403
+								$field_label,
404
+								$value,
405
+								'<p>',
406
+								'</p >'
407
+							);
408
+						}
409
+						break;
410
+					case 'email':
411
+						$valid_email = $this->_validate_email((string) $value);
412
+						if (! $valid_email) {
413
+							$err_msg .= htmlentities(
414
+								sprintf(
415
+									esc_html__(
416
+										'The %1$s field has at least one string that is not a valid email address record.  Valid emails are in the format: "Name <[email protected]>" or "[email protected]" and multiple emails can be separated by a comma.',
417
+										'event_espresso'
418
+									),
419
+									$field_label
420
+								)
421
+							);
422
+						}
423
+						break;
424
+					default:
425
+						break;
426
+				}
427
+			}
428
+
429
+			// if $err_msg isn't empty, let's set up the _errors array for this field.
430
+			if (! empty($err_msg)) {
431
+				$this->_errors[ $field ]['msg'] = $err_msg;
432
+			} else {
433
+				unset($this->_errors[ $field ]);
434
+			}
435
+		}
436
+
437
+		// if we have ANY errors, then we want to make sure we return the values
438
+		// for ALL the fields so the user doesn't have to retype them all.
439
+		if (! empty($this->_errors)) {
440
+			foreach ($this->_fields as $field => $value) {
441
+				$this->_errors[ $field ]['value'] = stripslashes($value);
442
+			}
443
+		}
444
+
445
+		// return any errors or just TRUE if everything validates
446
+		return empty($this->_errors)
447
+			? true
448
+			: $this->_errors;
449
+	}
450
+
451
+
452
+	/**
453
+	 * Reassembles and returns an array of valid shortcodes
454
+	 * given the array of groups and array of shortcodes indexed by group.
455
+	 *
456
+	 * @param array $groups          array of shortcode groups that we want shortcodes for
457
+	 * @param array $codes_from_objs All the codes available.
458
+	 * @return array                   an array of actual shortcodes (that will be used for validation).
459
+	 */
460
+	private function reassembleValidShortcodesFromGroup(array $groups, array $codes_from_objs): array
461
+	{
462
+		$shortcodes = [];
463
+		foreach ($groups as $group) {
464
+			$shortcodes = array_merge($shortcodes, $codes_from_objs[ $group ]);
465
+		}
466
+		return $shortcodes;
467
+	}
468
+
469
+
470
+	/**
471
+	 * Validates a string against a list of accepted shortcodes
472
+	 * This function takes in an array of shortcodes
473
+	 * and makes sure that the given string ONLY contains shortcodes in that array.
474
+	 *
475
+	 * @param string $value            string to evaluate
476
+	 * @param array  $valid_shortcodes array of shortcodes that are acceptable.
477
+	 * @return bool|string  return either a list of invalid shortcodes OR false if the shortcodes validate.
478
+	 * @deprecated 5.0.48
479
+	 */
480
+	protected function _invalid_shortcodes(string $value, array $valid_shortcodes)
481
+	{
482
+		return $this->findInvalidShortcodes($value, $valid_shortcodes) ?: false;
483
+	}
484
+
485
+
486
+	/**
487
+	 * Validates a string against a list of accepted shortcodes
488
+	 * This function takes in an array of shortcodes
489
+	 * and makes sure that the given string ONLY contains shortcodes in that array.
490
+	 *
491
+	 * @param string $incoming_text    string to evaluate
492
+	 * @param array  $valid_shortcodes array of shortcodes that are acceptable.
493
+	 * @return string  return either a list of invalid shortcodes OR false if the shortcodes validate.
494
+	 */
495
+	protected function findInvalidShortcodes(string $incoming_text, array $valid_shortcodes): string
496
+	{
497
+		// first we need to go through the string and get ALL the shortcodes in the string
498
+		// matches the opening [ plus the shortcode name, but nothing else
499
+		// examples:
500
+		//  [RECIPIENT_LNAME] matches as [RECIPIENT_LNAME
501
+		//  [RECEIPT_URL download=true] matches as [RECEIPT_URL
502
+		//  [PAYMENT_LINK_IF_NEEDED_* custom_text='pay me now man!'] matches as [PAYMENT_LINK_IF_NEEDED_*
503
+		preg_match_all(EE_Shortcodes::REGEX_SHORTCODE_NAME_ONLY, $incoming_text, $matches);
504
+		$shortcodes_in_text = $matches[0];
505
+		// now all we need to do is add the closing ] to each shortcode to make them "valid"
506
+		$shortcodes_in_text = array_map(fn($shortcode) => rtrim($shortcode) . ']', $shortcodes_in_text);
507
+		// get a diff of the shortcodes in the string vs the valid shortcodes
508
+		$invalid_shortcodes = array_diff($shortcodes_in_text, $valid_shortcodes);
509
+		if (empty($invalid_shortcodes)) {
510
+			return '';
511
+		}
512
+		// made it here? then let's assemble the error message
513
+		return '<strong>' . implode('</strong>,<strong>', $invalid_shortcodes) . '</strong>';
514
+	}
515
+
516
+
517
+	/**
518
+	 * Validates an incoming string and makes sure we have valid emails in the string.
519
+	 *
520
+	 * @param string $value incoming value to validate
521
+	 * @return bool        true if the string validates, false if it doesn't
522
+	 */
523
+	protected function _validate_email(string $value): bool
524
+	{
525
+		$or_val = $value;
526
+
527
+		// empty strings will validate because this is how a message template
528
+		// for a particular context can be "turned off" (if there is no email then no message)
529
+		if (empty($value)) {
530
+			return true;
531
+		}
532
+
533
+		// first determine if there ARE any shortcodes.
534
+		// If there are shortcodes and then later we find that there were no other valid emails
535
+		// but the field isn't empty...
536
+		// that means we've got extra commas that were left after stripping out shortcodes so probably still valid.
537
+		$has_shortcodes = preg_match(EE_Shortcodes::REGEX_SHORTCODE_FULL, $value);
538
+
539
+		// first we need to strip out all the shortcodes!
540
+		$value = preg_replace(EE_Shortcodes::REGEX_SHORTCODE_FULL, '', $value);
541
+
542
+		// if original value is not empty and new value is, then we've parsed out a shortcode
543
+		// and we now have an empty string which DOES validate.
544
+		// We also validate complete empty field for email because
545
+		// it's possible that this message is being "turned off" for a particular context
546
+
547
+
548
+		if (! empty($or_val) && empty($value)) {
549
+			return true;
550
+		}
551
+
552
+		// trim any commas from beginning and end of string ( after whitespace trimmed );
553
+		$value = trim(trim($value), ',');
554
+
555
+		// next we need to split up the string if it's comma-delimited.
556
+		$emails = explode(',', $value);
557
+		$empty  = false; // used to indicate that there is an empty comma.
558
+		// now let's loop through the emails and do our checks
559
+		foreach ($emails as $email) {
560
+			if (empty($email)) {
561
+				$empty = true;
562
+				continue;
563
+			}
564
+
565
+			// trim whitespace
566
+			$email = trim($email);
567
+			// either its of type "[email protected]", or its of type "fname lname <[email protected]>"
568
+			if (is_email($email)) {
569
+				continue;
570
+			}
571
+			$matches  = [];
572
+			$validate = (bool) preg_match('/(.*)<(.+)>/', $email, $matches);
573
+			if ($validate && is_email($matches[2])) {
574
+				continue;
575
+			}
576
+			return false;
577
+		}
578
+
579
+		return ! ($empty && ! $has_shortcodes);
580
+	}
581
+
582
+
583
+	/**
584
+	 * Magic getter
585
+	 * Using this to provide back compat with add-ons referencing deprecated properties.
586
+	 *
587
+	 * @param string $property Property being requested
588
+	 * @return mixed
589
+	 * @throws Exception
590
+	 */
591
+	public function __get($property)
592
+	{
593
+		$expected_properties_map = [
594
+			/**
595
+			 * @deprecated 4.9.0
596
+			 */
597
+			'_MSGR'   => '_messenger',
598
+			/**
599
+			 * @deprecated 4.9.0
600
+			 */
601
+			'_MSGTYP' => '_message_type',
602
+		];
603
+
604
+		if (isset($expected_properties_map[ $property ])) {
605
+			return $this->{$expected_properties_map[ $property ]};
606
+		}
607
+
608
+		throw new Exception(
609
+			sprintf(
610
+				esc_html__('The property %1$s being requested on %2$s does not exist', 'event_espresso'),
611
+				$property,
612
+				get_class($this)
613
+			)
614
+		);
615
+	}
616 616
 }
Please login to merge, or discard this patch.
Spacing   +53 added lines, -53 removed lines patch added patch discarded remove patch
@@ -138,9 +138,9 @@  discard block
 block discarded – undo
138 138
         // load messenger
139 139
         $messenger = ucwords(str_replace('_', ' ', $this->_m_name));
140 140
         $messenger = str_replace(' ', '_', $messenger);
141
-        $messenger = 'EE_' . $messenger . '_messenger';
141
+        $messenger = 'EE_'.$messenger.'_messenger';
142 142
 
143
-        if (! class_exists($messenger)) {
143
+        if ( ! class_exists($messenger)) {
144 144
             throw new EE_Error(
145 145
                 sprintf(
146 146
                     esc_html__('There is no messenger class for the given string (%s)', 'event_espresso'),
@@ -154,9 +154,9 @@  discard block
 block discarded – undo
154 154
         // load message type
155 155
         $message_type = ucwords(str_replace('_', ' ', $this->_mt_name));
156 156
         $message_type = str_replace(' ', '_', $message_type);
157
-        $message_type = 'EE_' . $message_type . '_message_type';
157
+        $message_type = 'EE_'.$message_type.'_message_type';
158 158
 
159
-        if (! class_exists($message_type)) {
159
+        if ( ! class_exists($message_type)) {
160 160
             throw new EE_Error(
161 161
                 sprintf(
162 162
                     esc_html__('There is no message type class for the given string (%s)', 'event_espresso'),
@@ -184,17 +184,17 @@  discard block
 block discarded – undo
184 184
         $msgr_validator = $this->_messenger->get_validator_config();
185 185
         // we only want the valid shortcodes for the given context!
186 186
         $context  = $this->_context;
187
-        $mt_codes = $mt_codes[ $context ];
187
+        $mt_codes = $mt_codes[$context];
188 188
         // in this first loop we're just getting all shortcode group indexes from the msgr_validator
189 189
         // into a single array (so we can get the appropriate shortcode objects for the groups)
190 190
         $shortcode_groups = $mt_codes;
191 191
         $groups_per_field = [];
192 192
 
193 193
         foreach ($msgr_validator as $field => $config) {
194
-            if (! isset($config['shortcodes'])) {
194
+            if ( ! isset($config['shortcodes'])) {
195 195
                 continue;
196 196
             }  //Nothing to see here.
197
-            $groups_per_field[ $field ] = array_intersect($config['shortcodes'], $mt_codes);
197
+            $groups_per_field[$field] = array_intersect($config['shortcodes'], $mt_codes);
198 198
             $shortcode_groups           = array_merge($config['shortcodes'], $shortcode_groups);
199 199
         }
200 200
         $shortcode_groups = array_unique($shortcode_groups);
@@ -206,18 +206,18 @@  discard block
 block discarded – undo
206 206
         foreach ($shortcode_groups as $group) {
207 207
             $ref       = ucwords(str_replace('_', ' ', $group));
208 208
             $ref       = str_replace(' ', '_', $ref);
209
-            $classname = 'EE_' . $ref . '_Shortcodes';
209
+            $classname = 'EE_'.$ref.'_Shortcodes';
210 210
             if (class_exists($classname)) {
211 211
                 $a                         = new ReflectionClass($classname);
212 212
                 $obj                       = $a->newInstance();
213
-                $codes_from_objs[ $group ] = $obj->get_shortcodes();
213
+                $codes_from_objs[$group] = $obj->get_shortcodes();
214 214
             }
215 215
         }
216 216
 
217 217
         // let's just replace the $mt shortcode group indexes with the actual shortcodes (unique)
218 218
         $final_mt_codes = [];
219 219
         foreach ($mt_codes as $group) {
220
-            $final_mt_codes = array_merge($final_mt_codes, $codes_from_objs[ $group ]);
220
+            $final_mt_codes = array_merge($final_mt_codes, $codes_from_objs[$group]);
221 221
         }
222 222
         $mt_codes = $final_mt_codes;
223 223
 
@@ -232,45 +232,45 @@  discard block
 block discarded – undo
232 232
                 continue;
233 233
             }
234 234
 
235
-            if (isset($this->_valid_shortcodes_modifier[ $context ][ $field ])) {
235
+            if (isset($this->_valid_shortcodes_modifier[$context][$field])) {
236 236
                 // If we have an override then we use it to indicate the codes we want.
237
-                $this->_validators[ $field ]['shortcodes'] = $this->reassembleValidShortcodesFromGroup(
238
-                    $this->_valid_shortcodes_modifier[ $context ][ $field ],
237
+                $this->_validators[$field]['shortcodes'] = $this->reassembleValidShortcodesFromGroup(
238
+                    $this->_valid_shortcodes_modifier[$context][$field],
239 239
                     $codes_from_objs
240 240
                 );
241
-            } elseif (isset($groups_per_field[ $field ])) {
241
+            } elseif (isset($groups_per_field[$field])) {
242 242
                 // we have specific shortcodes for a field so we need to use them
243
-                $this->_validators[ $field ]['shortcodes'] = $this->reassembleValidShortcodesFromGroup(
244
-                    $groups_per_field[ $field ],
243
+                $this->_validators[$field]['shortcodes'] = $this->reassembleValidShortcodesFromGroup(
244
+                    $groups_per_field[$field],
245 245
                     $codes_from_objs
246 246
                 );
247 247
             } elseif (empty($config)) {
248 248
                 // no config so we're assuming we're just going to use the shortcodes from the message type context
249
-                $this->_validators[ $field ]['shortcodes'] = $mt_codes;
249
+                $this->_validators[$field]['shortcodes'] = $mt_codes;
250 250
             } elseif (isset($config['specific_shortcodes'])) {
251 251
                 // we have specific shortcodes so we need to use them
252
-                $this->_validators[ $field ]['shortcodes'] = $config['specific_shortcodes'];
252
+                $this->_validators[$field]['shortcodes'] = $config['specific_shortcodes'];
253 253
             } else {
254 254
                 // otherwise the shortcodes are what is set by the messenger for that field
255 255
                 foreach ($config['shortcodes'] as $group) {
256
-                    $this->_validators[ $field ]['shortcodes'] = isset($this->_validators[ $field ]['shortcodes'])
257
-                        ? array_merge($this->_validators[ $field ]['shortcodes'], $codes_from_objs[ $group ])
258
-                        : $codes_from_objs[ $group ];
256
+                    $this->_validators[$field]['shortcodes'] = isset($this->_validators[$field]['shortcodes'])
257
+                        ? array_merge($this->_validators[$field]['shortcodes'], $codes_from_objs[$group])
258
+                        : $codes_from_objs[$group];
259 259
                 }
260 260
             }
261 261
 
262 262
             // now let's just make sure that any excluded specific shortcodes are removed.
263 263
             $specific_excludes = $this->get_specific_shortcode_excludes();
264
-            if (isset($specific_excludes[ $field ])) {
265
-                foreach ($specific_excludes[ $field ] as $sex) {
266
-                    if (isset($this->_validators[ $field ]['shortcodes'][ $sex ])) {
267
-                        unset($this->_validators[ $field ]['shortcodes'][ $sex ]);
264
+            if (isset($specific_excludes[$field])) {
265
+                foreach ($specific_excludes[$field] as $sex) {
266
+                    if (isset($this->_validators[$field]['shortcodes'][$sex])) {
267
+                        unset($this->_validators[$field]['shortcodes'][$sex]);
268 268
                     }
269 269
                 }
270 270
             }
271 271
 
272 272
             // hey! don't forget to include the type if present!
273
-            $this->_validators[ $field ]['type'] = $config['type'] ?? null;
273
+            $this->_validators[$field]['type'] = $config['type'] ?? null;
274 274
         }
275 275
     }
276 276
 
@@ -297,7 +297,7 @@  discard block
 block discarded – undo
297 297
     {
298 298
         // specific validator filter
299 299
         $shortcode_excludes = (array) apply_filters(
300
-            'FHEE__' . get_class($this) . '__get_specific_shortcode_excludes;',
300
+            'FHEE__'.get_class($this).'__get_specific_shortcode_excludes;',
301 301
             $this->_specific_shortcode_excludes,
302 302
             $this->_context
303 303
         );
@@ -324,21 +324,21 @@  discard block
 block discarded – undo
324 324
         $template_fields = $this->_messenger->get_template_fields();
325 325
         // loop through the fields and check!
326 326
         foreach ($this->_fields as $field => $value) {
327
-            $this->_errors[ $field ] = [];
327
+            $this->_errors[$field] = [];
328 328
             $err_msg                 = '';
329 329
             $field_label             = '';
330 330
             // if field is not present in the _validators array then we continue
331
-            if (! isset($this->_validators[ $field ])) {
332
-                unset($this->_errors[ $field ]);
331
+            if ( ! isset($this->_validators[$field])) {
332
+                unset($this->_errors[$field]);
333 333
                 continue;
334 334
             }
335 335
 
336 336
             // get the translated field label!
337 337
             // first check if it's in the main fields list
338
-            if (isset($template_fields[ $field ])) {
338
+            if (isset($template_fields[$field])) {
339 339
                 // most likely the field is found in the 'extra' array.
340
-                $field_label = ! empty($template_fields[ $field ])
341
-                    ? $template_fields[ $field ]['label']
340
+                $field_label = ! empty($template_fields[$field])
341
+                    ? $template_fields[$field]['label']
342 342
                     : $field;
343 343
             }
344 344
 
@@ -362,21 +362,21 @@  discard block
 block discarded – undo
362 362
 
363 363
             // field is present. Let's validate shortcodes first (but only if shortcodes present).
364 364
             if (
365
-                isset($this->_validators[ $field ]['shortcodes'])
366
-                && ! empty($this->_validators[ $field ]['shortcodes'])
365
+                isset($this->_validators[$field]['shortcodes'])
366
+                && ! empty($this->_validators[$field]['shortcodes'])
367 367
             ) {
368
-                $valid_shortcodes   = array_keys((array) $this->_validators[ $field ]['shortcodes']);
368
+                $valid_shortcodes   = array_keys((array) $this->_validators[$field]['shortcodes']);
369 369
                 $invalid_shortcodes = $this->findInvalidShortcodes((string) $value, $valid_shortcodes);
370 370
                 // if true then that means there is a returned error message
371 371
                 // that we'll need to add to the _errors array for this field.
372 372
                 if ($invalid_shortcodes) {
373
-                    $v_s     = array_keys($this->_validators[ $field ]['shortcodes']);
373
+                    $v_s     = array_keys($this->_validators[$field]['shortcodes']);
374 374
                     $err_msg = sprintf(
375 375
                         esc_html__(
376 376
                             '%3$sThe following shortcodes were found in the "%1$s" field that ARE not valid: %2$s%4$s',
377 377
                             'event_espresso'
378 378
                         ),
379
-                        '<strong>' . $field_label . '</strong>',
379
+                        '<strong>'.$field_label.'</strong>',
380 380
                         $invalid_shortcodes,
381 381
                         '<p>',
382 382
                         '</p >'
@@ -391,10 +391,10 @@  discard block
 block discarded – undo
391 391
             }
392 392
 
393 393
             // if there's a "type" to be validated then let's do that too.
394
-            if (isset($this->_validators[ $field ]['type']) && ! empty($this->_validators[ $field ]['type'])) {
395
-                switch ($this->_validators[ $field ]['type']) {
394
+            if (isset($this->_validators[$field]['type']) && ! empty($this->_validators[$field]['type'])) {
395
+                switch ($this->_validators[$field]['type']) {
396 396
                     case 'number':
397
-                        if (! is_numeric($value)) {
397
+                        if ( ! is_numeric($value)) {
398 398
                             $err_msg .= sprintf(
399 399
                                 esc_html__(
400 400
                                     '%3$sThe %1$s field is supposed to be a number. The value given (%2$s)  is not.  Please double-check and make sure the field contains a number%4$s',
@@ -409,7 +409,7 @@  discard block
 block discarded – undo
409 409
                         break;
410 410
                     case 'email':
411 411
                         $valid_email = $this->_validate_email((string) $value);
412
-                        if (! $valid_email) {
412
+                        if ( ! $valid_email) {
413 413
                             $err_msg .= htmlentities(
414 414
                                 sprintf(
415 415
                                     esc_html__(
@@ -427,18 +427,18 @@  discard block
 block discarded – undo
427 427
             }
428 428
 
429 429
             // if $err_msg isn't empty, let's set up the _errors array for this field.
430
-            if (! empty($err_msg)) {
431
-                $this->_errors[ $field ]['msg'] = $err_msg;
430
+            if ( ! empty($err_msg)) {
431
+                $this->_errors[$field]['msg'] = $err_msg;
432 432
             } else {
433
-                unset($this->_errors[ $field ]);
433
+                unset($this->_errors[$field]);
434 434
             }
435 435
         }
436 436
 
437 437
         // if we have ANY errors, then we want to make sure we return the values
438 438
         // for ALL the fields so the user doesn't have to retype them all.
439
-        if (! empty($this->_errors)) {
439
+        if ( ! empty($this->_errors)) {
440 440
             foreach ($this->_fields as $field => $value) {
441
-                $this->_errors[ $field ]['value'] = stripslashes($value);
441
+                $this->_errors[$field]['value'] = stripslashes($value);
442 442
             }
443 443
         }
444 444
 
@@ -461,7 +461,7 @@  discard block
 block discarded – undo
461 461
     {
462 462
         $shortcodes = [];
463 463
         foreach ($groups as $group) {
464
-            $shortcodes = array_merge($shortcodes, $codes_from_objs[ $group ]);
464
+            $shortcodes = array_merge($shortcodes, $codes_from_objs[$group]);
465 465
         }
466 466
         return $shortcodes;
467 467
     }
@@ -503,14 +503,14 @@  discard block
 block discarded – undo
503 503
         preg_match_all(EE_Shortcodes::REGEX_SHORTCODE_NAME_ONLY, $incoming_text, $matches);
504 504
         $shortcodes_in_text = $matches[0];
505 505
         // now all we need to do is add the closing ] to each shortcode to make them "valid"
506
-        $shortcodes_in_text = array_map(fn($shortcode) => rtrim($shortcode) . ']', $shortcodes_in_text);
506
+        $shortcodes_in_text = array_map(fn($shortcode) => rtrim($shortcode).']', $shortcodes_in_text);
507 507
         // get a diff of the shortcodes in the string vs the valid shortcodes
508 508
         $invalid_shortcodes = array_diff($shortcodes_in_text, $valid_shortcodes);
509 509
         if (empty($invalid_shortcodes)) {
510 510
             return '';
511 511
         }
512 512
         // made it here? then let's assemble the error message
513
-        return '<strong>' . implode('</strong>,<strong>', $invalid_shortcodes) . '</strong>';
513
+        return '<strong>'.implode('</strong>,<strong>', $invalid_shortcodes).'</strong>';
514 514
     }
515 515
 
516 516
 
@@ -545,7 +545,7 @@  discard block
 block discarded – undo
545 545
         // it's possible that this message is being "turned off" for a particular context
546 546
 
547 547
 
548
-        if (! empty($or_val) && empty($value)) {
548
+        if ( ! empty($or_val) && empty($value)) {
549 549
             return true;
550 550
         }
551 551
 
@@ -601,8 +601,8 @@  discard block
 block discarded – undo
601 601
             '_MSGTYP' => '_message_type',
602 602
         ];
603 603
 
604
-        if (isset($expected_properties_map[ $property ])) {
605
-            return $this->{$expected_properties_map[ $property ]};
604
+        if (isset($expected_properties_map[$property])) {
605
+            return $this->{$expected_properties_map[$property]};
606 606
         }
607 607
 
608 608
         throw new Exception(
Please login to merge, or discard this patch.
core/helpers/EEH_Parse_Shortcodes.helper.php 2 patches
Indentation   +261 added lines, -261 removed lines patch added patch discarded remove patch
@@ -10,265 +10,265 @@
 block discarded – undo
10 10
  */
11 11
 class EEH_Parse_Shortcodes
12 12
 {
13
-    /**
14
-     * holds the template
15
-     *
16
-     * @access private
17
-     * @var mixed (string|array)
18
-     */
19
-    private $_template;
20
-
21
-
22
-    /**
23
-     * holds the incoming data object
24
-     *
25
-     * @access private
26
-     * @var object
27
-     */
28
-    private $_data;
29
-
30
-
31
-    /**
32
-     * will hold an array of EE_Shortcodes library objects.
33
-     *
34
-     * @access private
35
-     * @var EE_Shortcodes[]
36
-     */
37
-    private $_shortcode_objs = array();
38
-
39
-
40
-    /**
41
-     * This kicks off the parsing of shortcodes in message templates
42
-     *
43
-     * @param  string                $template         This is the incoming string to be parsed
44
-     * @param  EE_Messages_Addressee $data             This is the incoming data object
45
-     * @param  array                 $valid_shortcodes An array of strings that correspond to EE_Shortcode libraries
46
-     * @param EE_message_type        $message_type     The message type that called the parser
47
-     * @param EE_messenger           $messenger        The active messenger for this parsing session.
48
-     * @param EE_Message             $message
49
-     * @return string                   The parsed template string
50
-     */
51
-    public function parse_message_template(
52
-        $template,
53
-        EE_Messages_Addressee $data,
54
-        $valid_shortcodes,
55
-        EE_message_type $message_type,
56
-        EE_messenger $messenger,
57
-        EE_Message $message
58
-    ) {
59
-        $extra_data = array(
60
-            'messenger'    => $messenger,
61
-            'message_type' => $message_type,
62
-            'message'      => $message,
63
-        );
64
-        $this->_init_data($template, $data, $valid_shortcodes, $extra_data);
65
-        $this->_template = is_array($template) ? $template['main'] : $template;
66
-        return $this->_parse_message_template();
67
-    }
68
-
69
-
70
-    public function parse_attendee_list_template(
71
-        $template,
72
-        EE_Registration $registration,
73
-        $valid_shortcodes,
74
-        $extra_data = array()
75
-    ) {
76
-        $this->_init_data($template, $registration, $valid_shortcodes, $extra_data);
77
-        $this->_template = is_array($template) ? $template['attendee_list'] : $template;
78
-        return $this->_parse_message_template();
79
-    }
80
-
81
-    public function parse_event_list_template($template, EE_Event $event, $valid_shortcodes, $extra_data = array())
82
-    {
83
-        $this->_init_data($template, $event, $valid_shortcodes, $extra_data);
84
-        $this->_template = is_array($template) ? $template['event_list'] : $template;
85
-        return $this->_parse_message_template();
86
-    }
87
-
88
-
89
-    public function parse_ticket_list_template($template, EE_Ticket $ticket, $valid_shortcodes, $extra_data = array())
90
-    {
91
-        $this->_init_data($template, $ticket, $valid_shortcodes, $extra_data);
92
-        $this->_template = is_array($template) ? $template['ticket_list'] : $template;
93
-        return $this->_parse_message_template();
94
-    }
95
-
96
-
97
-    public function parse_line_item_list_template(
98
-        $template,
99
-        EE_Line_Item $line_item,
100
-        $valid_shortcodes,
101
-        $extra_data = array()
102
-    ) {
103
-        $this->_init_data($template, $line_item, $valid_shortcodes, $extra_data);
104
-        $this->_template = is_array($template) ? $template['ticket_line_item_no_pms'] : $template;
105
-        return $this->_parse_message_template();
106
-    }
107
-
108
-
109
-    public function parse_payment_list_template(
110
-        $template,
111
-        EE_Payment $payment_item,
112
-        $valid_shortcodes,
113
-        $extra_data = array()
114
-    ) {
115
-        $this->_init_data($template, $payment_item, $valid_shortcodes, $extra_data);
116
-        $this->_template = is_array($template) ? $template['payment_list'] : $template;
117
-        return $this->_parse_message_template();
118
-    }
119
-
120
-
121
-    public function parse_datetime_list_template(
122
-        $template,
123
-        EE_Datetime $datetime,
124
-        $valid_shortcodes,
125
-        $extra_data = array()
126
-    ) {
127
-        $this->_init_data($template, $datetime, $valid_shortcodes, $extra_data);
128
-        $this->_template = is_array($template) ? $template['datetime_list'] : $template;
129
-        return $this->_parse_message_template();
130
-    }
131
-
132
-
133
-    public function parse_question_list_template($template, EE_Answer $answer, $valid_shortcodes, $extra_data = array())
134
-    {
135
-        $this->_init_data($template, $answer, $valid_shortcodes, $extra_data);
136
-        $this->_template = is_array($template) ? $template['question_list'] : $template;
137
-        return $this->_parse_message_template();
138
-    }
139
-
140
-
141
-    private function _init_data($template, $data, $valid_shortcodes, $extra_data = array())
142
-    {
143
-        $this->_reset_props();
144
-        $this->_data['template']   = $template;
145
-        $this->_data['data']       = $data;
146
-        $this->_data['extra_data'] = $extra_data;
147
-        $this->_set_shortcodes($valid_shortcodes);
148
-    }
149
-
150
-
151
-    private function _reset_props()
152
-    {
153
-        $this->_template       = $this->_data = null;
154
-        $this->_shortcode_objs = array();
155
-    }
156
-
157
-
158
-    /**
159
-     * takes the given template and parses it with the $_shortcodes property
160
-     *
161
-     * @return string
162
-     */
163
-    private function _parse_message_template(): string
164
-    {
165
-        // now let's get a list of shortcodes that are found in the given template
166
-        preg_match_all(EE_Shortcodes::REGEX_SHORTCODE_FULL, $this->_template, $matches);
167
-        $shortcodes = $matches[0]; // this should be an array of shortcodes in the template string.
168
-
169
-        $matched_code = array();
170
-        $sc_values    = array();
171
-
172
-        $list_type_shortcodes = array(
173
-            '[ATTENDEE_LIST]',
174
-            '[EVENT_LIST]',
175
-            '[TICKET_LIST]',
176
-            '[DATETIME_LIST]',
177
-            '[QUESTION_LIST]',
178
-            '[RECIPIENT_QUESTION_LIST]',
179
-            '[PRIMARY_REGISTRANT_QUESTION_LIST]',
180
-            '[RECIPIENT_TICKET_LIST]',
181
-            '[PRIMARY_REGISTRANT_TICKET_LIST]',
182
-            '[RECIPIENT_DATETIME_LIST]',
183
-            '[PRIMARY_REGISTRANT_DATETIME_LIST]',
184
-            '[TICKET_LINE_ITEM_LIST]',
185
-            '[TAX_LINE_ITEM_LIST]',
186
-            '[ADDITIONAL_LINE_ITEM_LIST]',
187
-            '[PRICE_MODIFIER_LINE_ITEM_LIST]',
188
-            '[PAYMENT_LIST_*]',
189
-        );
190
-
191
-        $list_type_shortcodes = apply_filters(
192
-            'FHEE__EEH_Parse_Shortcodes___parse_message_template__list_type_shortcodes',
193
-            $list_type_shortcodes
194
-        );
195
-
196
-        // now lets go ahead and loop through our parsers for each shortcode and set up the values
197
-        foreach ($shortcodes as $shortcode) {
198
-            // truncate full shortcode to shortcode name only (ie: remove attributes and dynamic portions)
199
-            preg_match_all(EE_Shortcodes::REGEX_SHORTCODE_NAME_ONLY, $shortcode, $matches);
200
-            // ensure shortcode ends with closing ]
201
-            $short_code_name = rtrim(reset($matches[0]), ']') . ']';
202
-
203
-            foreach ($this->_shortcode_objs as $sc_obj) {
204
-                if (! $sc_obj instanceof EE_Shortcodes) {
205
-                    continue;
206
-                }
207
-                // check if the given shortcode is in this object, if not, move on
208
-                if (! array_key_exists($short_code_name, $sc_obj->get_shortcodes())) {
209
-                    continue;
210
-                }
211
-
212
-                // if this isn't  a "list" type shortcode then we'll send along the data vanilla instead of in an array.
213
-                if (! in_array($shortcode, $list_type_shortcodes)) {
214
-                    $data_send = ! is_object($this->_data) && isset($this->_data['data']) ? $this->_data['data'] : $this->_data;
215
-                } else {
216
-                    $data_send = $this->_data;
217
-                }
218
-
219
-                // is this a conditional type shortcode?  If it is then we actually parse the template here.
220
-                if ($this->_is_conditional_shortcode($shortcode)) {
221
-                    // most shortcode parsers are not going to have a match for this shortcode
222
-                    // and will return an empty string so we need to make sure that we're only replacing
223
-                    // the template when there is a non-empty string.
224
-                    $parsed = $sc_obj->parser($shortcode, $data_send, $this->_data['extra_data']);
225
-                    if ($parsed) {
226
-                        $this->_template = $parsed;
227
-                    }
228
-                }
229
-
230
-                $parsed = $sc_obj->parser($shortcode, $data_send, $this->_data['extra_data']);
231
-
232
-                $matched_code[] = $shortcode;
233
-                $sc_values[]    = $parsed;
234
-            }
235
-        }
236
-
237
-        // now we've got parsed values for all the shortcodes in the template so we can go ahead and swap the shortcodes out.
238
-        return str_replace(array_values($matched_code), array_values($sc_values), $this->_template);
239
-    }
240
-
241
-
242
-    /**
243
-     * Simply returns whether the given shortcode matches the structure for a conditional shortcode.
244
-     *
245
-     * Does it match this format: `[IF_`
246
-     *
247
-     * @param $shortcode
248
-     * @return bool
249
-     */
250
-    protected function _is_conditional_shortcode($shortcode): bool
251
-    {
252
-        return strpos($shortcode, '[IF_') === 0;
253
-    }
254
-
255
-
256
-    /**
257
-     * This sets the shortcodes property from the incoming array of valid shortcodes that corresponds to names of
258
-     * various EE_Shortcode library objects
259
-     *
260
-     * @param array $valid_shortcodes an array of strings corresponding to EE_Shortcode Library objects
261
-     * @return void
262
-     */
263
-    private function _set_shortcodes(array $valid_shortcodes)
264
-    {
265
-        foreach ($valid_shortcodes as $shortcode_ref) {
266
-            $ref       = ucwords(str_replace('_', ' ', $shortcode_ref));
267
-            $ref       = str_replace(' ', '_', $ref);
268
-            $classname = 'EE_' . $ref . '_Shortcodes';
269
-            if (class_exists($classname) && ! isset($this->_shortcode_objs[ $classname ])) {
270
-                $this->_shortcode_objs[ $classname ] = new $classname();
271
-            }
272
-        }
273
-    }
13
+	/**
14
+	 * holds the template
15
+	 *
16
+	 * @access private
17
+	 * @var mixed (string|array)
18
+	 */
19
+	private $_template;
20
+
21
+
22
+	/**
23
+	 * holds the incoming data object
24
+	 *
25
+	 * @access private
26
+	 * @var object
27
+	 */
28
+	private $_data;
29
+
30
+
31
+	/**
32
+	 * will hold an array of EE_Shortcodes library objects.
33
+	 *
34
+	 * @access private
35
+	 * @var EE_Shortcodes[]
36
+	 */
37
+	private $_shortcode_objs = array();
38
+
39
+
40
+	/**
41
+	 * This kicks off the parsing of shortcodes in message templates
42
+	 *
43
+	 * @param  string                $template         This is the incoming string to be parsed
44
+	 * @param  EE_Messages_Addressee $data             This is the incoming data object
45
+	 * @param  array                 $valid_shortcodes An array of strings that correspond to EE_Shortcode libraries
46
+	 * @param EE_message_type        $message_type     The message type that called the parser
47
+	 * @param EE_messenger           $messenger        The active messenger for this parsing session.
48
+	 * @param EE_Message             $message
49
+	 * @return string                   The parsed template string
50
+	 */
51
+	public function parse_message_template(
52
+		$template,
53
+		EE_Messages_Addressee $data,
54
+		$valid_shortcodes,
55
+		EE_message_type $message_type,
56
+		EE_messenger $messenger,
57
+		EE_Message $message
58
+	) {
59
+		$extra_data = array(
60
+			'messenger'    => $messenger,
61
+			'message_type' => $message_type,
62
+			'message'      => $message,
63
+		);
64
+		$this->_init_data($template, $data, $valid_shortcodes, $extra_data);
65
+		$this->_template = is_array($template) ? $template['main'] : $template;
66
+		return $this->_parse_message_template();
67
+	}
68
+
69
+
70
+	public function parse_attendee_list_template(
71
+		$template,
72
+		EE_Registration $registration,
73
+		$valid_shortcodes,
74
+		$extra_data = array()
75
+	) {
76
+		$this->_init_data($template, $registration, $valid_shortcodes, $extra_data);
77
+		$this->_template = is_array($template) ? $template['attendee_list'] : $template;
78
+		return $this->_parse_message_template();
79
+	}
80
+
81
+	public function parse_event_list_template($template, EE_Event $event, $valid_shortcodes, $extra_data = array())
82
+	{
83
+		$this->_init_data($template, $event, $valid_shortcodes, $extra_data);
84
+		$this->_template = is_array($template) ? $template['event_list'] : $template;
85
+		return $this->_parse_message_template();
86
+	}
87
+
88
+
89
+	public function parse_ticket_list_template($template, EE_Ticket $ticket, $valid_shortcodes, $extra_data = array())
90
+	{
91
+		$this->_init_data($template, $ticket, $valid_shortcodes, $extra_data);
92
+		$this->_template = is_array($template) ? $template['ticket_list'] : $template;
93
+		return $this->_parse_message_template();
94
+	}
95
+
96
+
97
+	public function parse_line_item_list_template(
98
+		$template,
99
+		EE_Line_Item $line_item,
100
+		$valid_shortcodes,
101
+		$extra_data = array()
102
+	) {
103
+		$this->_init_data($template, $line_item, $valid_shortcodes, $extra_data);
104
+		$this->_template = is_array($template) ? $template['ticket_line_item_no_pms'] : $template;
105
+		return $this->_parse_message_template();
106
+	}
107
+
108
+
109
+	public function parse_payment_list_template(
110
+		$template,
111
+		EE_Payment $payment_item,
112
+		$valid_shortcodes,
113
+		$extra_data = array()
114
+	) {
115
+		$this->_init_data($template, $payment_item, $valid_shortcodes, $extra_data);
116
+		$this->_template = is_array($template) ? $template['payment_list'] : $template;
117
+		return $this->_parse_message_template();
118
+	}
119
+
120
+
121
+	public function parse_datetime_list_template(
122
+		$template,
123
+		EE_Datetime $datetime,
124
+		$valid_shortcodes,
125
+		$extra_data = array()
126
+	) {
127
+		$this->_init_data($template, $datetime, $valid_shortcodes, $extra_data);
128
+		$this->_template = is_array($template) ? $template['datetime_list'] : $template;
129
+		return $this->_parse_message_template();
130
+	}
131
+
132
+
133
+	public function parse_question_list_template($template, EE_Answer $answer, $valid_shortcodes, $extra_data = array())
134
+	{
135
+		$this->_init_data($template, $answer, $valid_shortcodes, $extra_data);
136
+		$this->_template = is_array($template) ? $template['question_list'] : $template;
137
+		return $this->_parse_message_template();
138
+	}
139
+
140
+
141
+	private function _init_data($template, $data, $valid_shortcodes, $extra_data = array())
142
+	{
143
+		$this->_reset_props();
144
+		$this->_data['template']   = $template;
145
+		$this->_data['data']       = $data;
146
+		$this->_data['extra_data'] = $extra_data;
147
+		$this->_set_shortcodes($valid_shortcodes);
148
+	}
149
+
150
+
151
+	private function _reset_props()
152
+	{
153
+		$this->_template       = $this->_data = null;
154
+		$this->_shortcode_objs = array();
155
+	}
156
+
157
+
158
+	/**
159
+	 * takes the given template and parses it with the $_shortcodes property
160
+	 *
161
+	 * @return string
162
+	 */
163
+	private function _parse_message_template(): string
164
+	{
165
+		// now let's get a list of shortcodes that are found in the given template
166
+		preg_match_all(EE_Shortcodes::REGEX_SHORTCODE_FULL, $this->_template, $matches);
167
+		$shortcodes = $matches[0]; // this should be an array of shortcodes in the template string.
168
+
169
+		$matched_code = array();
170
+		$sc_values    = array();
171
+
172
+		$list_type_shortcodes = array(
173
+			'[ATTENDEE_LIST]',
174
+			'[EVENT_LIST]',
175
+			'[TICKET_LIST]',
176
+			'[DATETIME_LIST]',
177
+			'[QUESTION_LIST]',
178
+			'[RECIPIENT_QUESTION_LIST]',
179
+			'[PRIMARY_REGISTRANT_QUESTION_LIST]',
180
+			'[RECIPIENT_TICKET_LIST]',
181
+			'[PRIMARY_REGISTRANT_TICKET_LIST]',
182
+			'[RECIPIENT_DATETIME_LIST]',
183
+			'[PRIMARY_REGISTRANT_DATETIME_LIST]',
184
+			'[TICKET_LINE_ITEM_LIST]',
185
+			'[TAX_LINE_ITEM_LIST]',
186
+			'[ADDITIONAL_LINE_ITEM_LIST]',
187
+			'[PRICE_MODIFIER_LINE_ITEM_LIST]',
188
+			'[PAYMENT_LIST_*]',
189
+		);
190
+
191
+		$list_type_shortcodes = apply_filters(
192
+			'FHEE__EEH_Parse_Shortcodes___parse_message_template__list_type_shortcodes',
193
+			$list_type_shortcodes
194
+		);
195
+
196
+		// now lets go ahead and loop through our parsers for each shortcode and set up the values
197
+		foreach ($shortcodes as $shortcode) {
198
+			// truncate full shortcode to shortcode name only (ie: remove attributes and dynamic portions)
199
+			preg_match_all(EE_Shortcodes::REGEX_SHORTCODE_NAME_ONLY, $shortcode, $matches);
200
+			// ensure shortcode ends with closing ]
201
+			$short_code_name = rtrim(reset($matches[0]), ']') . ']';
202
+
203
+			foreach ($this->_shortcode_objs as $sc_obj) {
204
+				if (! $sc_obj instanceof EE_Shortcodes) {
205
+					continue;
206
+				}
207
+				// check if the given shortcode is in this object, if not, move on
208
+				if (! array_key_exists($short_code_name, $sc_obj->get_shortcodes())) {
209
+					continue;
210
+				}
211
+
212
+				// if this isn't  a "list" type shortcode then we'll send along the data vanilla instead of in an array.
213
+				if (! in_array($shortcode, $list_type_shortcodes)) {
214
+					$data_send = ! is_object($this->_data) && isset($this->_data['data']) ? $this->_data['data'] : $this->_data;
215
+				} else {
216
+					$data_send = $this->_data;
217
+				}
218
+
219
+				// is this a conditional type shortcode?  If it is then we actually parse the template here.
220
+				if ($this->_is_conditional_shortcode($shortcode)) {
221
+					// most shortcode parsers are not going to have a match for this shortcode
222
+					// and will return an empty string so we need to make sure that we're only replacing
223
+					// the template when there is a non-empty string.
224
+					$parsed = $sc_obj->parser($shortcode, $data_send, $this->_data['extra_data']);
225
+					if ($parsed) {
226
+						$this->_template = $parsed;
227
+					}
228
+				}
229
+
230
+				$parsed = $sc_obj->parser($shortcode, $data_send, $this->_data['extra_data']);
231
+
232
+				$matched_code[] = $shortcode;
233
+				$sc_values[]    = $parsed;
234
+			}
235
+		}
236
+
237
+		// now we've got parsed values for all the shortcodes in the template so we can go ahead and swap the shortcodes out.
238
+		return str_replace(array_values($matched_code), array_values($sc_values), $this->_template);
239
+	}
240
+
241
+
242
+	/**
243
+	 * Simply returns whether the given shortcode matches the structure for a conditional shortcode.
244
+	 *
245
+	 * Does it match this format: `[IF_`
246
+	 *
247
+	 * @param $shortcode
248
+	 * @return bool
249
+	 */
250
+	protected function _is_conditional_shortcode($shortcode): bool
251
+	{
252
+		return strpos($shortcode, '[IF_') === 0;
253
+	}
254
+
255
+
256
+	/**
257
+	 * This sets the shortcodes property from the incoming array of valid shortcodes that corresponds to names of
258
+	 * various EE_Shortcode library objects
259
+	 *
260
+	 * @param array $valid_shortcodes an array of strings corresponding to EE_Shortcode Library objects
261
+	 * @return void
262
+	 */
263
+	private function _set_shortcodes(array $valid_shortcodes)
264
+	{
265
+		foreach ($valid_shortcodes as $shortcode_ref) {
266
+			$ref       = ucwords(str_replace('_', ' ', $shortcode_ref));
267
+			$ref       = str_replace(' ', '_', $ref);
268
+			$classname = 'EE_' . $ref . '_Shortcodes';
269
+			if (class_exists($classname) && ! isset($this->_shortcode_objs[ $classname ])) {
270
+				$this->_shortcode_objs[ $classname ] = new $classname();
271
+			}
272
+		}
273
+	}
274 274
 }
Please login to merge, or discard this patch.
Spacing   +7 added lines, -7 removed lines patch added patch discarded remove patch
@@ -198,19 +198,19 @@  discard block
 block discarded – undo
198 198
             // truncate full shortcode to shortcode name only (ie: remove attributes and dynamic portions)
199 199
             preg_match_all(EE_Shortcodes::REGEX_SHORTCODE_NAME_ONLY, $shortcode, $matches);
200 200
             // ensure shortcode ends with closing ]
201
-            $short_code_name = rtrim(reset($matches[0]), ']') . ']';
201
+            $short_code_name = rtrim(reset($matches[0]), ']').']';
202 202
 
203 203
             foreach ($this->_shortcode_objs as $sc_obj) {
204
-                if (! $sc_obj instanceof EE_Shortcodes) {
204
+                if ( ! $sc_obj instanceof EE_Shortcodes) {
205 205
                     continue;
206 206
                 }
207 207
                 // check if the given shortcode is in this object, if not, move on
208
-                if (! array_key_exists($short_code_name, $sc_obj->get_shortcodes())) {
208
+                if ( ! array_key_exists($short_code_name, $sc_obj->get_shortcodes())) {
209 209
                     continue;
210 210
                 }
211 211
 
212 212
                 // if this isn't  a "list" type shortcode then we'll send along the data vanilla instead of in an array.
213
-                if (! in_array($shortcode, $list_type_shortcodes)) {
213
+                if ( ! in_array($shortcode, $list_type_shortcodes)) {
214 214
                     $data_send = ! is_object($this->_data) && isset($this->_data['data']) ? $this->_data['data'] : $this->_data;
215 215
                 } else {
216 216
                     $data_send = $this->_data;
@@ -265,9 +265,9 @@  discard block
 block discarded – undo
265 265
         foreach ($valid_shortcodes as $shortcode_ref) {
266 266
             $ref       = ucwords(str_replace('_', ' ', $shortcode_ref));
267 267
             $ref       = str_replace(' ', '_', $ref);
268
-            $classname = 'EE_' . $ref . '_Shortcodes';
269
-            if (class_exists($classname) && ! isset($this->_shortcode_objs[ $classname ])) {
270
-                $this->_shortcode_objs[ $classname ] = new $classname();
268
+            $classname = 'EE_'.$ref.'_Shortcodes';
269
+            if (class_exists($classname) && ! isset($this->_shortcode_objs[$classname])) {
270
+                $this->_shortcode_objs[$classname] = new $classname();
271 271
             }
272 272
         }
273 273
     }
Please login to merge, or discard this patch.