Completed
Branch master (c054b3)
by
unknown
07:25
created
core/libraries/messages/messenger/EE_Email_messenger.class.php 1 patch
Indentation   +643 added lines, -643 removed lines patch added patch discarded remove patch
@@ -5,647 +5,647 @@
 block discarded – undo
5 5
  */
6 6
 class EE_Email_messenger extends EE_messenger
7 7
 {
8
-    /**
9
-     * To field for email
10
-     *
11
-     * @var string
12
-     */
13
-    protected $_to = '';
14
-
15
-
16
-    /**
17
-     * CC field for email.
18
-     *
19
-     * @var string
20
-     */
21
-    protected $_cc = '';
22
-
23
-    /**
24
-     * From field for email
25
-     *
26
-     * @var string
27
-     */
28
-    protected $_from = '';
29
-
30
-
31
-    /**
32
-     * Subject field for email
33
-     *
34
-     * @var string
35
-     */
36
-    protected $_subject = '';
37
-
38
-
39
-    /**
40
-     * Content field for email
41
-     *
42
-     * @var string
43
-     */
44
-    protected $_content = '';
45
-
46
-
47
-    /**
48
-     * @throws EE_Error
49
-     * @throws ReflectionException
50
-     */
51
-    public function __construct()
52
-    {
53
-        // set name and description properties
54
-        $this->name                = 'email';
55
-        $this->description         = sprintf(
56
-            esc_html__(
57
-                'This messenger delivers messages via email using the built-in %s function included with WordPress',
58
-                'event_espresso'
59
-            ),
60
-            '<code>wp_mail</code>'
61
-        );
62
-        $this->label               = [
63
-            'singular' => esc_html__('email', 'event_espresso'),
64
-            'plural'   => esc_html__('emails', 'event_espresso'),
65
-        ];
66
-        $this->activate_on_install = true;
67
-
68
-        // we're using defaults so let's call parent constructor that will take care of setting up all the other
69
-        // properties
70
-        parent::__construct();
71
-    }
72
-
73
-
74
-    /**
75
-     * see abstract declaration in parent class for details.
76
-     */
77
-    protected function _set_admin_pages()
78
-    {
79
-        $this->admin_registered_pages = [
80
-            'events_edit' => true,
81
-        ];
82
-    }
83
-
84
-
85
-    /**
86
-     * see abstract declaration in parent class for details
87
-     */
88
-    protected function _set_valid_shortcodes()
89
-    {
90
-        // remember by leaving the other fields not set, those fields will inherit the valid shortcodes from the
91
-        // message type.
92
-        $this->_valid_shortcodes = [
93
-            'to'   => ['email', 'event_author', 'primary_registration_details', 'recipient_details'],
94
-            'cc'   => ['email', 'event_author', 'primary_registration_details', 'recipient_details'],
95
-            'from' => ['email', 'event_author', 'primary_registration_details', 'recipient_details'],
96
-        ];
97
-    }
98
-
99
-
100
-    /**
101
-     * see abstract declaration in parent class for details
102
-     *
103
-     * @access protected
104
-     * @return void
105
-     */
106
-    protected function _set_validator_config()
107
-    {
108
-        $valid_shortcodes = $this->get_valid_shortcodes();
109
-
110
-        $this->_validator_config = [
111
-            'to'            => [
112
-                'shortcodes' => $valid_shortcodes['to'],
113
-                'type'       => 'email',
114
-            ],
115
-            'cc'            => [
116
-                'shortcodes' => $valid_shortcodes['to'],
117
-                'type'       => 'email',
118
-            ],
119
-            'from'          => [
120
-                'shortcodes' => $valid_shortcodes['from'],
121
-                'type'       => 'email',
122
-            ],
123
-            'subject'       => [
124
-                'shortcodes' => [
125
-                    'organization',
126
-                    'primary_registration_details',
127
-                    'event_author',
128
-                    'primary_registration_details',
129
-                    'recipient_details',
130
-                ],
131
-            ],
132
-            'content'       => [
133
-                'shortcodes' => [
134
-                    'event_list',
135
-                    'attendee_list',
136
-                    'ticket_list',
137
-                    'organization',
138
-                    'primary_registration_details',
139
-                    'primary_registration_list',
140
-                    'event_author',
141
-                    'recipient_details',
142
-                    'recipient_list',
143
-                    'transaction',
144
-                    'messenger',
145
-                ],
146
-            ],
147
-            'attendee_list' => [
148
-                'shortcodes' => ['attendee', 'event_list', 'ticket_list'],
149
-                'required'   => ['[ATTENDEE_LIST]'],
150
-            ],
151
-            'event_list'    => [
152
-                'shortcodes' => [
153
-                    'event',
154
-                    'attendee_list',
155
-                    'ticket_list',
156
-                    'venue',
157
-                    'datetime_list',
158
-                    'attendee',
159
-                    'primary_registration_details',
160
-                    'primary_registration_list',
161
-                    'event_author',
162
-                    'recipient_details',
163
-                    'recipient_list',
164
-                ],
165
-                'required'   => ['[EVENT_LIST]'],
166
-            ],
167
-            'ticket_list'   => [
168
-                'shortcodes' => [
169
-                    'event_list',
170
-                    'attendee_list',
171
-                    'ticket',
172
-                    'datetime_list',
173
-                    'primary_registration_details',
174
-                    'recipient_details',
175
-                ],
176
-                'required'   => ['[TICKET_LIST]'],
177
-            ],
178
-            'datetime_list' => [
179
-                'shortcodes' => ['datetime', 'venue'],
180
-                'required'   => ['[DATETIME_LIST]'],
181
-            ],
182
-        ];
183
-    }
184
-
185
-
186
-    /**
187
-     * @see   parent EE_messenger class for docs
188
-     * @since 4.5.0
189
-     */
190
-    public function do_secondary_messenger_hooks($sending_messenger_name)
191
-    {
192
-        if ($sending_messenger_name === 'html') {
193
-            add_filter('FHEE__EE_Messages_Template_Pack__get_variation', [$this, 'add_email_css'], 10, 8);
194
-        }
195
-    }
196
-
197
-
198
-    public function add_email_css(
199
-        $variation_path,
200
-        $messenger,
201
-        $message_type,
202
-        $type,
203
-        $variation,
204
-        $file_extension,
205
-        $url,
206
-        EE_Messages_Template_Pack $template_pack
207
-    ) {
208
-        // prevent recursion on this callback.
209
-        remove_filter('FHEE__EE_Messages_Template_Pack__get_variation', [$this, 'add_email_css'], 10);
210
-        $variation = $this->get_variation($template_pack, $message_type, $url, 'main', $variation, false);
211
-
212
-        add_filter('FHEE__EE_Messages_Template_Pack__get_variation', [$this, 'add_email_css'], 10, 8);
213
-        return $variation;
214
-    }
215
-
216
-
217
-    /**
218
-     * See parent for details
219
-     *
220
-     * @access protected
221
-     * @return void
222
-     */
223
-    protected function _set_test_settings_fields()
224
-    {
225
-        $this->_test_settings_fields = [
226
-            'to'      => [
227
-                'input'      => 'text',
228
-                'label'      => esc_html__('Send a test email to', 'event_espresso'),
229
-                'type'       => 'email',
230
-                'required'   => false,
231
-                'validation' => true,
232
-                'css_class'  => 'ee-input-width--big',
233
-                'format'     => '%s',
234
-                'default'    => get_bloginfo('admin_email'),
235
-            ],
236
-            'subject' => [
237
-                'input'      => 'hidden',
238
-                'label'      => '',
239
-                'type'       => 'string',
240
-                'required'   => false,
241
-                'validation' => false,
242
-                'format'     => '%s',
243
-                'value'      => sprintf(esc_html__('Test email sent from %s', 'event_espresso'), get_bloginfo('name')),
244
-                'default'    => '',
245
-                'css_class'  => '',
246
-            ],
247
-        ];
248
-    }
249
-
250
-
251
-    /**
252
-     * _set_template_fields
253
-     * This sets up the fields that a messenger requires for the message to go out.
254
-     *
255
-     * @access  protected
256
-     * @return void
257
-     */
258
-    protected function _set_template_fields()
259
-    {
260
-        // any extra template fields that are NOT used by the messenger but will get used by a messenger field for
261
-        // shortcode replacement get added to the 'extra' key in an associated array indexed by the messenger field
262
-        // they relate to.  This is important for the Messages_admin to know what fields to display to the user.
263
-        //  Also, notice that the "values" are equal to the field type that messages admin will use to know what
264
-        // kind of field to display. The values ALSO have one index labeled "shortcode".  the values in that array
265
-        // indicate which ACTUAL SHORTCODE (i.e. [SHORTCODE]) is required in order for this extra field to be
266
-        // displayed.  If the required shortcode isn't part of the shortcodes array then the field is not needed and
267
-        // will not be displayed/parsed.
268
-        $this->_template_fields = [
269
-            'to'      => [
270
-                'input'      => 'text',
271
-                'label'      => esc_html_x(
272
-                    'To',
273
-                    'Label for the "To" field for email addresses',
274
-                    'event_espresso'
275
-                ),
276
-                'type'       => 'string',
277
-                'required'   => false,
278
-                'validation' => true,
279
-                'css_class'  => 'large-text',
280
-                'format'     => '%s',
281
-            ],
282
-            'cc'      => [
283
-                'input'      => 'text',
284
-                'label'      => esc_html_x(
285
-                    'CC',
286
-                    'Label for the "Carbon Copy" field used for additional email addresses',
287
-                    'event_espresso'
288
-                ),
289
-                'type'       => 'string',
290
-                'required'   => false,
291
-                'validation' => true,
292
-                'css_class'  => 'large-text',
293
-                'format'     => '%s',
294
-            ],
295
-            'from'    => [
296
-                'input'      => 'text',
297
-                'label'      => esc_html_x(
298
-                    'From',
299
-                    'Label for the "From" field for email addresses.',
300
-                    'event_espresso'
301
-                ),
302
-                'type'       => 'string',
303
-                'required'   => false,
304
-                'validation' => true,
305
-                'css_class'  => 'large-text',
306
-                'format'     => '%s',
307
-            ],
308
-            'subject' => [
309
-                'input'      => 'text',
310
-                'label'      => esc_html_x(
311
-                    'Subject',
312
-                    'Label for the "Subject" field (short description of contents) for emails.',
313
-                    'event_espresso'
314
-                ),
315
-                'type'       => 'string',
316
-                'required'   => true,
317
-                'validation' => true,
318
-                'css_class'  => 'large-text',
319
-                'format'     => '%s',
320
-            ],
321
-            'content' => '',
322
-            // left empty b/c it is in the "extra array" but messenger still needs needs to know this is a field.
323
-            'extra'   => [
324
-                'content' => [
325
-                    'main'          => [
326
-                        'input'      => 'wp_editor',
327
-                        'label'      => esc_html__('Main Content', 'event_espresso'),
328
-                        'type'       => 'string',
329
-                        'required'   => false,
330
-                        'validation' => true,
331
-                        'format'     => '%s',
332
-                        'rows'       => '15',
333
-                    ],
334
-                    'event_list'    => [
335
-                        'input'               => 'wp_editor',
336
-                        'label'               => '[EVENT_LIST]',
337
-                        'type'                => 'string',
338
-                        'required'            => false,
339
-                        'validation'          => true,
340
-                        'format'              => '%s',
341
-                        'rows'                => '15',
342
-                        'shortcodes_required' => ['[EVENT_LIST]'],
343
-                    ],
344
-                    'attendee_list' => [
345
-                        'input'               => 'textarea',
346
-                        'label'               => '[ATTENDEE_LIST]',
347
-                        'type'                => 'string',
348
-                        'required'            => false,
349
-                        'validation'          => true,
350
-                        'format'              => '%s',
351
-                        'css_class'           => 'large-text',
352
-                        'rows'                => '5',
353
-                        'shortcodes_required' => ['[ATTENDEE_LIST]'],
354
-                    ],
355
-                    'ticket_list'   => [
356
-                        'input'               => 'textarea',
357
-                        'label'               => '[TICKET_LIST]',
358
-                        'type'                => 'string',
359
-                        'required'            => false,
360
-                        'validation'          => true,
361
-                        'format'              => '%s',
362
-                        'css_class'           => 'large-text',
363
-                        'rows'                => '10',
364
-                        'shortcodes_required' => ['[TICKET_LIST]'],
365
-                    ],
366
-                    'datetime_list' => [
367
-                        'input'               => 'textarea',
368
-                        'label'               => '[DATETIME_LIST]',
369
-                        'type'                => 'string',
370
-                        'required'            => false,
371
-                        'validation'          => true,
372
-                        'format'              => '%s',
373
-                        'css_class'           => 'large-text',
374
-                        'rows'                => '10',
375
-                        'shortcodes_required' => ['[DATETIME_LIST]'],
376
-                    ],
377
-                ],
378
-            ],
379
-        ];
380
-    }
381
-
382
-
383
-    /**
384
-     * See definition of this class in parent
385
-     */
386
-    protected function _set_default_message_types()
387
-    {
388
-        $this->_default_message_types = [
389
-            'payment',
390
-            'payment_refund',
391
-            'registration',
392
-            'not_approved_registration',
393
-            'pending_approval',
394
-        ];
395
-    }
396
-
397
-
398
-    /**
399
-     * @see   definition of this class in parent
400
-     * @since 4.5.0
401
-     */
402
-    protected function _set_valid_message_types()
403
-    {
404
-        $this->_valid_message_types = [
405
-            'payment',
406
-            'registration',
407
-            'not_approved_registration',
408
-            'declined_registration',
409
-            'cancelled_registration',
410
-            'pending_approval',
411
-            'registration_summary',
412
-            'payment_reminder',
413
-            'payment_declined',
414
-            'payment_refund',
415
-        ];
416
-    }
417
-
418
-
419
-    /**
420
-     * setting up admin_settings_fields for messenger.
421
-     */
422
-    protected function _set_admin_settings_fields()
423
-    {
424
-    }
425
-
426
-
427
-    /**
428
-     * We just deliver the messages don't kill us!!
429
-     *
430
-     * @return bool|WP_Error true if message delivered, false if it didn't deliver OR bubble up any error object if
431
-     *              present.
432
-     * @throws EE_Error
433
-     * @throws Exception
434
-     */
435
-    protected function _send_message()
436
-    {
437
-        $success = wp_mail(
438
-            $this->_to,
439
-            // some old values for subject may be expecting HTML entities to be decoded in the subject
440
-            // and subjects aren't interpreted as HTML, so there should be no HTML in them
441
-            wp_strip_all_tags(wp_specialchars_decode($this->_subject, ENT_QUOTES)),
442
-            $this->_body(),
443
-            $this->_headers()
444
-        );
445
-        if (! $success) {
446
-            EE_Error::add_error(
447
-                sprintf(
448
-                    esc_html__(
449
-                        'The email did not send successfully.%3$sThe WordPress wp_mail function is used for sending mails but does not give any useful information when an email fails to send.%3$sIt is possible the "to" address (%1$s) or "from" address (%2$s) is invalid.%3$s',
450
-                        'event_espresso'
451
-                    ),
452
-                    $this->_to,
453
-                    $this->_from,
454
-                    '<br />'
455
-                ),
456
-                __FILE__,
457
-                __FUNCTION__,
458
-                __LINE__
459
-            );
460
-        }
461
-        return $success;
462
-    }
463
-
464
-
465
-    /**
466
-     * see parent for definition
467
-     *
468
-     * @return string html body of the message content and the related css.
469
-     * @throws EE_Error
470
-     * @throws Exception
471
-     */
472
-    protected function _preview()
473
-    {
474
-        return $this->_body(true);
475
-    }
476
-
477
-
478
-    /**
479
-     * Setup headers for email
480
-     *
481
-     * @access protected
482
-     * @return string formatted header for email
483
-     */
484
-    protected function _headers()
485
-    {
486
-        $this->_ensure_has_from_email_address();
487
-        $from    = $this->_from;
488
-        $headers = [
489
-            'From:' . $from,
490
-            'Reply-To:' . $from,
491
-            'Content-Type:text/html; charset=utf-8',
492
-        ];
493
-
494
-        /**
495
-         * Second condition added as a result of https://events.codebasehq.com/projects/event-espresso/tickets/11416 to
496
-         * cover back compat where there may be users who have saved cc values in their db for the newsletter message
497
-         * type which they are no longer able to change.
498
-         */
499
-        if (! empty($this->_cc) && ! $this->_incoming_message_type instanceof EE_Newsletter_message_type) {
500
-            $headers[] = 'cc: ' . $this->_cc;
501
-        }
502
-
503
-        // but wait!  Header's for the from is NOT reliable because some plugins don't respect From: as set in the
504
-        // header.
505
-        add_filter('wp_mail_from', [$this, 'set_from_address'], 100);
506
-        add_filter('wp_mail_from_name', [$this, 'set_from_name'], 100);
507
-        return apply_filters('FHEE__EE_Email_messenger___headers', $headers, $this->_incoming_message_type, $this);
508
-    }
509
-
510
-
511
-    /**
512
-     * This simply ensures that the from address is not empty.  If it is, then we use whatever is set as the site email
513
-     * address for the from address to avoid problems with sending emails.
514
-     */
515
-    protected function _ensure_has_from_email_address()
516
-    {
517
-        if (empty($this->_from)) {
518
-            $this->_from = get_bloginfo('admin_email');
519
-        }
520
-    }
521
-
522
-
523
-    /**
524
-     * This simply parses whatever is set as the $_from address and determines if it is in the format {name} <{email}>
525
-     * or just {email} and returns an array with the "from_name" and "from_email" as the values. Note from_name *MAY*
526
-     * be empty
527
-     *
528
-     * @return array
529
-     * @since 4.3.1
530
-     */
531
-    private function _parse_from()
532
-    {
533
-        if (strpos($this->_from, '<') !== false) {
534
-            $from_name = substr($this->_from, 0, strpos($this->_from, '<') - 1);
535
-            $from_name = str_replace('"', '', $from_name);
536
-            $from_name = trim($from_name);
537
-
538
-            $from_email = substr($this->_from, strpos($this->_from, '<') + 1);
539
-            $from_email = str_replace('>', '', $from_email);
540
-            $from_email = trim($from_email);
541
-        } elseif (trim($this->_from) !== '') {
542
-            $from_name  = '';
543
-            $from_email = trim($this->_from);
544
-        } else {
545
-            $from_name = $from_email = '';
546
-        }
547
-        return [$from_name, $from_email];
548
-    }
549
-
550
-
551
-    /**
552
-     * Callback for the wp_mail_from filter.
553
-     *
554
-     * @param string $from_email What the original from_email is.
555
-     * @return string
556
-     * @since 4.3.1
557
-     */
558
-    public function set_from_address($from_email)
559
-    {
560
-        $parsed_from = $this->_parse_from();
561
-        // includes fallback if the parsing failed.
562
-        return is_array($parsed_from) && ! empty($parsed_from[1])
563
-            ? $parsed_from[1]
564
-            : get_bloginfo('admin_email');
565
-    }
566
-
567
-
568
-    /**
569
-     * Callback for the wp_mail_from_name filter.
570
-     *
571
-     * @param string $from_name The original from_name.
572
-     * @return string
573
-     * @since 4.3.1
574
-     */
575
-    public function set_from_name($from_name)
576
-    {
577
-        $parsed_from = $this->_parse_from();
578
-        if (is_array($parsed_from) && ! empty($parsed_from[0])) {
579
-            $from_name = $parsed_from[0];
580
-        }
581
-
582
-        // if from name is "WordPress" let's sub in the site name instead (more friendly!)
583
-        // but realize the default name is HTML entity-encoded
584
-        return $from_name == 'WordPress' ? wp_specialchars_decode(get_bloginfo(), ENT_QUOTES) : $from_name;
585
-    }
586
-
587
-
588
-    /**
589
-     * setup body for email
590
-     *
591
-     * @param bool $preview will determine whether this is preview template or not.
592
-     * @return string formatted body for email.
593
-     * @throws EE_Error
594
-     * @throws Exception
595
-     */
596
-    protected function _body($preview = false)
597
-    {
598
-        // setup template args!
599
-        $this->_template_args = [
600
-            'subject'   => $this->_subject,
601
-            'from'      => $this->_from,
602
-            'main_body' => wpautop($this->_content),
603
-        ];
604
-        $body                 = $this->_get_main_template($preview);
605
-
606
-        /**
607
-         * This filter allows one to bypass the CSSToInlineStyles tool and leave the body untouched.
608
-         *
609
-         * @type    bool $preview Indicates whether a preview is being generated or not.
610
-         * @return  bool    true  indicates to use the inliner, false bypasses it.
611
-         */
612
-        if (apply_filters('FHEE__EE_Email_messenger__apply_CSSInliner ', true, $preview)) {
613
-            // now if this isn't a preview, let's set up the body so it has inline styles
614
-            if (! $preview || (defined('DOING_AJAX') && DOING_AJAX)) {
615
-                $style = file_get_contents(
616
-                    $this->get_variation(
617
-                        $this->_tmp_pack,
618
-                        $this->_incoming_message_type->name,
619
-                        false,
620
-                        'main',
621
-                        $this->_variation
622
-                    ),
623
-                    true
624
-                );
625
-                $CSS   = new TijsVerkoyen\CssToInlineStyles\CssToInlineStyles();
626
-                $body  = $CSS->convert($body, $style);
627
-            }
628
-        }
629
-        return $body;
630
-    }
631
-
632
-
633
-    /**
634
-     * This just returns any existing test settings that might be saved in the database
635
-     *
636
-     * @access public
637
-     * @return array
638
-     * @throws EE_Error
639
-     * @throws ReflectionException
640
-     */
641
-    public function get_existing_test_settings()
642
-    {
643
-        $settings = parent::get_existing_test_settings();
644
-        // override subject if present because we always want it to be fresh.
645
-        if (is_array($settings) && ! empty($settings['subject'])) {
646
-            $settings['subject'] =
647
-                sprintf(esc_html__('Test email sent from %s', 'event_espresso'), get_bloginfo('name'));
648
-        }
649
-        return $settings;
650
-    }
8
+	/**
9
+	 * To field for email
10
+	 *
11
+	 * @var string
12
+	 */
13
+	protected $_to = '';
14
+
15
+
16
+	/**
17
+	 * CC field for email.
18
+	 *
19
+	 * @var string
20
+	 */
21
+	protected $_cc = '';
22
+
23
+	/**
24
+	 * From field for email
25
+	 *
26
+	 * @var string
27
+	 */
28
+	protected $_from = '';
29
+
30
+
31
+	/**
32
+	 * Subject field for email
33
+	 *
34
+	 * @var string
35
+	 */
36
+	protected $_subject = '';
37
+
38
+
39
+	/**
40
+	 * Content field for email
41
+	 *
42
+	 * @var string
43
+	 */
44
+	protected $_content = '';
45
+
46
+
47
+	/**
48
+	 * @throws EE_Error
49
+	 * @throws ReflectionException
50
+	 */
51
+	public function __construct()
52
+	{
53
+		// set name and description properties
54
+		$this->name                = 'email';
55
+		$this->description         = sprintf(
56
+			esc_html__(
57
+				'This messenger delivers messages via email using the built-in %s function included with WordPress',
58
+				'event_espresso'
59
+			),
60
+			'<code>wp_mail</code>'
61
+		);
62
+		$this->label               = [
63
+			'singular' => esc_html__('email', 'event_espresso'),
64
+			'plural'   => esc_html__('emails', 'event_espresso'),
65
+		];
66
+		$this->activate_on_install = true;
67
+
68
+		// we're using defaults so let's call parent constructor that will take care of setting up all the other
69
+		// properties
70
+		parent::__construct();
71
+	}
72
+
73
+
74
+	/**
75
+	 * see abstract declaration in parent class for details.
76
+	 */
77
+	protected function _set_admin_pages()
78
+	{
79
+		$this->admin_registered_pages = [
80
+			'events_edit' => true,
81
+		];
82
+	}
83
+
84
+
85
+	/**
86
+	 * see abstract declaration in parent class for details
87
+	 */
88
+	protected function _set_valid_shortcodes()
89
+	{
90
+		// remember by leaving the other fields not set, those fields will inherit the valid shortcodes from the
91
+		// message type.
92
+		$this->_valid_shortcodes = [
93
+			'to'   => ['email', 'event_author', 'primary_registration_details', 'recipient_details'],
94
+			'cc'   => ['email', 'event_author', 'primary_registration_details', 'recipient_details'],
95
+			'from' => ['email', 'event_author', 'primary_registration_details', 'recipient_details'],
96
+		];
97
+	}
98
+
99
+
100
+	/**
101
+	 * see abstract declaration in parent class for details
102
+	 *
103
+	 * @access protected
104
+	 * @return void
105
+	 */
106
+	protected function _set_validator_config()
107
+	{
108
+		$valid_shortcodes = $this->get_valid_shortcodes();
109
+
110
+		$this->_validator_config = [
111
+			'to'            => [
112
+				'shortcodes' => $valid_shortcodes['to'],
113
+				'type'       => 'email',
114
+			],
115
+			'cc'            => [
116
+				'shortcodes' => $valid_shortcodes['to'],
117
+				'type'       => 'email',
118
+			],
119
+			'from'          => [
120
+				'shortcodes' => $valid_shortcodes['from'],
121
+				'type'       => 'email',
122
+			],
123
+			'subject'       => [
124
+				'shortcodes' => [
125
+					'organization',
126
+					'primary_registration_details',
127
+					'event_author',
128
+					'primary_registration_details',
129
+					'recipient_details',
130
+				],
131
+			],
132
+			'content'       => [
133
+				'shortcodes' => [
134
+					'event_list',
135
+					'attendee_list',
136
+					'ticket_list',
137
+					'organization',
138
+					'primary_registration_details',
139
+					'primary_registration_list',
140
+					'event_author',
141
+					'recipient_details',
142
+					'recipient_list',
143
+					'transaction',
144
+					'messenger',
145
+				],
146
+			],
147
+			'attendee_list' => [
148
+				'shortcodes' => ['attendee', 'event_list', 'ticket_list'],
149
+				'required'   => ['[ATTENDEE_LIST]'],
150
+			],
151
+			'event_list'    => [
152
+				'shortcodes' => [
153
+					'event',
154
+					'attendee_list',
155
+					'ticket_list',
156
+					'venue',
157
+					'datetime_list',
158
+					'attendee',
159
+					'primary_registration_details',
160
+					'primary_registration_list',
161
+					'event_author',
162
+					'recipient_details',
163
+					'recipient_list',
164
+				],
165
+				'required'   => ['[EVENT_LIST]'],
166
+			],
167
+			'ticket_list'   => [
168
+				'shortcodes' => [
169
+					'event_list',
170
+					'attendee_list',
171
+					'ticket',
172
+					'datetime_list',
173
+					'primary_registration_details',
174
+					'recipient_details',
175
+				],
176
+				'required'   => ['[TICKET_LIST]'],
177
+			],
178
+			'datetime_list' => [
179
+				'shortcodes' => ['datetime', 'venue'],
180
+				'required'   => ['[DATETIME_LIST]'],
181
+			],
182
+		];
183
+	}
184
+
185
+
186
+	/**
187
+	 * @see   parent EE_messenger class for docs
188
+	 * @since 4.5.0
189
+	 */
190
+	public function do_secondary_messenger_hooks($sending_messenger_name)
191
+	{
192
+		if ($sending_messenger_name === 'html') {
193
+			add_filter('FHEE__EE_Messages_Template_Pack__get_variation', [$this, 'add_email_css'], 10, 8);
194
+		}
195
+	}
196
+
197
+
198
+	public function add_email_css(
199
+		$variation_path,
200
+		$messenger,
201
+		$message_type,
202
+		$type,
203
+		$variation,
204
+		$file_extension,
205
+		$url,
206
+		EE_Messages_Template_Pack $template_pack
207
+	) {
208
+		// prevent recursion on this callback.
209
+		remove_filter('FHEE__EE_Messages_Template_Pack__get_variation', [$this, 'add_email_css'], 10);
210
+		$variation = $this->get_variation($template_pack, $message_type, $url, 'main', $variation, false);
211
+
212
+		add_filter('FHEE__EE_Messages_Template_Pack__get_variation', [$this, 'add_email_css'], 10, 8);
213
+		return $variation;
214
+	}
215
+
216
+
217
+	/**
218
+	 * See parent for details
219
+	 *
220
+	 * @access protected
221
+	 * @return void
222
+	 */
223
+	protected function _set_test_settings_fields()
224
+	{
225
+		$this->_test_settings_fields = [
226
+			'to'      => [
227
+				'input'      => 'text',
228
+				'label'      => esc_html__('Send a test email to', 'event_espresso'),
229
+				'type'       => 'email',
230
+				'required'   => false,
231
+				'validation' => true,
232
+				'css_class'  => 'ee-input-width--big',
233
+				'format'     => '%s',
234
+				'default'    => get_bloginfo('admin_email'),
235
+			],
236
+			'subject' => [
237
+				'input'      => 'hidden',
238
+				'label'      => '',
239
+				'type'       => 'string',
240
+				'required'   => false,
241
+				'validation' => false,
242
+				'format'     => '%s',
243
+				'value'      => sprintf(esc_html__('Test email sent from %s', 'event_espresso'), get_bloginfo('name')),
244
+				'default'    => '',
245
+				'css_class'  => '',
246
+			],
247
+		];
248
+	}
249
+
250
+
251
+	/**
252
+	 * _set_template_fields
253
+	 * This sets up the fields that a messenger requires for the message to go out.
254
+	 *
255
+	 * @access  protected
256
+	 * @return void
257
+	 */
258
+	protected function _set_template_fields()
259
+	{
260
+		// any extra template fields that are NOT used by the messenger but will get used by a messenger field for
261
+		// shortcode replacement get added to the 'extra' key in an associated array indexed by the messenger field
262
+		// they relate to.  This is important for the Messages_admin to know what fields to display to the user.
263
+		//  Also, notice that the "values" are equal to the field type that messages admin will use to know what
264
+		// kind of field to display. The values ALSO have one index labeled "shortcode".  the values in that array
265
+		// indicate which ACTUAL SHORTCODE (i.e. [SHORTCODE]) is required in order for this extra field to be
266
+		// displayed.  If the required shortcode isn't part of the shortcodes array then the field is not needed and
267
+		// will not be displayed/parsed.
268
+		$this->_template_fields = [
269
+			'to'      => [
270
+				'input'      => 'text',
271
+				'label'      => esc_html_x(
272
+					'To',
273
+					'Label for the "To" field for email addresses',
274
+					'event_espresso'
275
+				),
276
+				'type'       => 'string',
277
+				'required'   => false,
278
+				'validation' => true,
279
+				'css_class'  => 'large-text',
280
+				'format'     => '%s',
281
+			],
282
+			'cc'      => [
283
+				'input'      => 'text',
284
+				'label'      => esc_html_x(
285
+					'CC',
286
+					'Label for the "Carbon Copy" field used for additional email addresses',
287
+					'event_espresso'
288
+				),
289
+				'type'       => 'string',
290
+				'required'   => false,
291
+				'validation' => true,
292
+				'css_class'  => 'large-text',
293
+				'format'     => '%s',
294
+			],
295
+			'from'    => [
296
+				'input'      => 'text',
297
+				'label'      => esc_html_x(
298
+					'From',
299
+					'Label for the "From" field for email addresses.',
300
+					'event_espresso'
301
+				),
302
+				'type'       => 'string',
303
+				'required'   => false,
304
+				'validation' => true,
305
+				'css_class'  => 'large-text',
306
+				'format'     => '%s',
307
+			],
308
+			'subject' => [
309
+				'input'      => 'text',
310
+				'label'      => esc_html_x(
311
+					'Subject',
312
+					'Label for the "Subject" field (short description of contents) for emails.',
313
+					'event_espresso'
314
+				),
315
+				'type'       => 'string',
316
+				'required'   => true,
317
+				'validation' => true,
318
+				'css_class'  => 'large-text',
319
+				'format'     => '%s',
320
+			],
321
+			'content' => '',
322
+			// left empty b/c it is in the "extra array" but messenger still needs needs to know this is a field.
323
+			'extra'   => [
324
+				'content' => [
325
+					'main'          => [
326
+						'input'      => 'wp_editor',
327
+						'label'      => esc_html__('Main Content', 'event_espresso'),
328
+						'type'       => 'string',
329
+						'required'   => false,
330
+						'validation' => true,
331
+						'format'     => '%s',
332
+						'rows'       => '15',
333
+					],
334
+					'event_list'    => [
335
+						'input'               => 'wp_editor',
336
+						'label'               => '[EVENT_LIST]',
337
+						'type'                => 'string',
338
+						'required'            => false,
339
+						'validation'          => true,
340
+						'format'              => '%s',
341
+						'rows'                => '15',
342
+						'shortcodes_required' => ['[EVENT_LIST]'],
343
+					],
344
+					'attendee_list' => [
345
+						'input'               => 'textarea',
346
+						'label'               => '[ATTENDEE_LIST]',
347
+						'type'                => 'string',
348
+						'required'            => false,
349
+						'validation'          => true,
350
+						'format'              => '%s',
351
+						'css_class'           => 'large-text',
352
+						'rows'                => '5',
353
+						'shortcodes_required' => ['[ATTENDEE_LIST]'],
354
+					],
355
+					'ticket_list'   => [
356
+						'input'               => 'textarea',
357
+						'label'               => '[TICKET_LIST]',
358
+						'type'                => 'string',
359
+						'required'            => false,
360
+						'validation'          => true,
361
+						'format'              => '%s',
362
+						'css_class'           => 'large-text',
363
+						'rows'                => '10',
364
+						'shortcodes_required' => ['[TICKET_LIST]'],
365
+					],
366
+					'datetime_list' => [
367
+						'input'               => 'textarea',
368
+						'label'               => '[DATETIME_LIST]',
369
+						'type'                => 'string',
370
+						'required'            => false,
371
+						'validation'          => true,
372
+						'format'              => '%s',
373
+						'css_class'           => 'large-text',
374
+						'rows'                => '10',
375
+						'shortcodes_required' => ['[DATETIME_LIST]'],
376
+					],
377
+				],
378
+			],
379
+		];
380
+	}
381
+
382
+
383
+	/**
384
+	 * See definition of this class in parent
385
+	 */
386
+	protected function _set_default_message_types()
387
+	{
388
+		$this->_default_message_types = [
389
+			'payment',
390
+			'payment_refund',
391
+			'registration',
392
+			'not_approved_registration',
393
+			'pending_approval',
394
+		];
395
+	}
396
+
397
+
398
+	/**
399
+	 * @see   definition of this class in parent
400
+	 * @since 4.5.0
401
+	 */
402
+	protected function _set_valid_message_types()
403
+	{
404
+		$this->_valid_message_types = [
405
+			'payment',
406
+			'registration',
407
+			'not_approved_registration',
408
+			'declined_registration',
409
+			'cancelled_registration',
410
+			'pending_approval',
411
+			'registration_summary',
412
+			'payment_reminder',
413
+			'payment_declined',
414
+			'payment_refund',
415
+		];
416
+	}
417
+
418
+
419
+	/**
420
+	 * setting up admin_settings_fields for messenger.
421
+	 */
422
+	protected function _set_admin_settings_fields()
423
+	{
424
+	}
425
+
426
+
427
+	/**
428
+	 * We just deliver the messages don't kill us!!
429
+	 *
430
+	 * @return bool|WP_Error true if message delivered, false if it didn't deliver OR bubble up any error object if
431
+	 *              present.
432
+	 * @throws EE_Error
433
+	 * @throws Exception
434
+	 */
435
+	protected function _send_message()
436
+	{
437
+		$success = wp_mail(
438
+			$this->_to,
439
+			// some old values for subject may be expecting HTML entities to be decoded in the subject
440
+			// and subjects aren't interpreted as HTML, so there should be no HTML in them
441
+			wp_strip_all_tags(wp_specialchars_decode($this->_subject, ENT_QUOTES)),
442
+			$this->_body(),
443
+			$this->_headers()
444
+		);
445
+		if (! $success) {
446
+			EE_Error::add_error(
447
+				sprintf(
448
+					esc_html__(
449
+						'The email did not send successfully.%3$sThe WordPress wp_mail function is used for sending mails but does not give any useful information when an email fails to send.%3$sIt is possible the "to" address (%1$s) or "from" address (%2$s) is invalid.%3$s',
450
+						'event_espresso'
451
+					),
452
+					$this->_to,
453
+					$this->_from,
454
+					'<br />'
455
+				),
456
+				__FILE__,
457
+				__FUNCTION__,
458
+				__LINE__
459
+			);
460
+		}
461
+		return $success;
462
+	}
463
+
464
+
465
+	/**
466
+	 * see parent for definition
467
+	 *
468
+	 * @return string html body of the message content and the related css.
469
+	 * @throws EE_Error
470
+	 * @throws Exception
471
+	 */
472
+	protected function _preview()
473
+	{
474
+		return $this->_body(true);
475
+	}
476
+
477
+
478
+	/**
479
+	 * Setup headers for email
480
+	 *
481
+	 * @access protected
482
+	 * @return string formatted header for email
483
+	 */
484
+	protected function _headers()
485
+	{
486
+		$this->_ensure_has_from_email_address();
487
+		$from    = $this->_from;
488
+		$headers = [
489
+			'From:' . $from,
490
+			'Reply-To:' . $from,
491
+			'Content-Type:text/html; charset=utf-8',
492
+		];
493
+
494
+		/**
495
+		 * Second condition added as a result of https://events.codebasehq.com/projects/event-espresso/tickets/11416 to
496
+		 * cover back compat where there may be users who have saved cc values in their db for the newsletter message
497
+		 * type which they are no longer able to change.
498
+		 */
499
+		if (! empty($this->_cc) && ! $this->_incoming_message_type instanceof EE_Newsletter_message_type) {
500
+			$headers[] = 'cc: ' . $this->_cc;
501
+		}
502
+
503
+		// but wait!  Header's for the from is NOT reliable because some plugins don't respect From: as set in the
504
+		// header.
505
+		add_filter('wp_mail_from', [$this, 'set_from_address'], 100);
506
+		add_filter('wp_mail_from_name', [$this, 'set_from_name'], 100);
507
+		return apply_filters('FHEE__EE_Email_messenger___headers', $headers, $this->_incoming_message_type, $this);
508
+	}
509
+
510
+
511
+	/**
512
+	 * This simply ensures that the from address is not empty.  If it is, then we use whatever is set as the site email
513
+	 * address for the from address to avoid problems with sending emails.
514
+	 */
515
+	protected function _ensure_has_from_email_address()
516
+	{
517
+		if (empty($this->_from)) {
518
+			$this->_from = get_bloginfo('admin_email');
519
+		}
520
+	}
521
+
522
+
523
+	/**
524
+	 * This simply parses whatever is set as the $_from address and determines if it is in the format {name} <{email}>
525
+	 * or just {email} and returns an array with the "from_name" and "from_email" as the values. Note from_name *MAY*
526
+	 * be empty
527
+	 *
528
+	 * @return array
529
+	 * @since 4.3.1
530
+	 */
531
+	private function _parse_from()
532
+	{
533
+		if (strpos($this->_from, '<') !== false) {
534
+			$from_name = substr($this->_from, 0, strpos($this->_from, '<') - 1);
535
+			$from_name = str_replace('"', '', $from_name);
536
+			$from_name = trim($from_name);
537
+
538
+			$from_email = substr($this->_from, strpos($this->_from, '<') + 1);
539
+			$from_email = str_replace('>', '', $from_email);
540
+			$from_email = trim($from_email);
541
+		} elseif (trim($this->_from) !== '') {
542
+			$from_name  = '';
543
+			$from_email = trim($this->_from);
544
+		} else {
545
+			$from_name = $from_email = '';
546
+		}
547
+		return [$from_name, $from_email];
548
+	}
549
+
550
+
551
+	/**
552
+	 * Callback for the wp_mail_from filter.
553
+	 *
554
+	 * @param string $from_email What the original from_email is.
555
+	 * @return string
556
+	 * @since 4.3.1
557
+	 */
558
+	public function set_from_address($from_email)
559
+	{
560
+		$parsed_from = $this->_parse_from();
561
+		// includes fallback if the parsing failed.
562
+		return is_array($parsed_from) && ! empty($parsed_from[1])
563
+			? $parsed_from[1]
564
+			: get_bloginfo('admin_email');
565
+	}
566
+
567
+
568
+	/**
569
+	 * Callback for the wp_mail_from_name filter.
570
+	 *
571
+	 * @param string $from_name The original from_name.
572
+	 * @return string
573
+	 * @since 4.3.1
574
+	 */
575
+	public function set_from_name($from_name)
576
+	{
577
+		$parsed_from = $this->_parse_from();
578
+		if (is_array($parsed_from) && ! empty($parsed_from[0])) {
579
+			$from_name = $parsed_from[0];
580
+		}
581
+
582
+		// if from name is "WordPress" let's sub in the site name instead (more friendly!)
583
+		// but realize the default name is HTML entity-encoded
584
+		return $from_name == 'WordPress' ? wp_specialchars_decode(get_bloginfo(), ENT_QUOTES) : $from_name;
585
+	}
586
+
587
+
588
+	/**
589
+	 * setup body for email
590
+	 *
591
+	 * @param bool $preview will determine whether this is preview template or not.
592
+	 * @return string formatted body for email.
593
+	 * @throws EE_Error
594
+	 * @throws Exception
595
+	 */
596
+	protected function _body($preview = false)
597
+	{
598
+		// setup template args!
599
+		$this->_template_args = [
600
+			'subject'   => $this->_subject,
601
+			'from'      => $this->_from,
602
+			'main_body' => wpautop($this->_content),
603
+		];
604
+		$body                 = $this->_get_main_template($preview);
605
+
606
+		/**
607
+		 * This filter allows one to bypass the CSSToInlineStyles tool and leave the body untouched.
608
+		 *
609
+		 * @type    bool $preview Indicates whether a preview is being generated or not.
610
+		 * @return  bool    true  indicates to use the inliner, false bypasses it.
611
+		 */
612
+		if (apply_filters('FHEE__EE_Email_messenger__apply_CSSInliner ', true, $preview)) {
613
+			// now if this isn't a preview, let's set up the body so it has inline styles
614
+			if (! $preview || (defined('DOING_AJAX') && DOING_AJAX)) {
615
+				$style = file_get_contents(
616
+					$this->get_variation(
617
+						$this->_tmp_pack,
618
+						$this->_incoming_message_type->name,
619
+						false,
620
+						'main',
621
+						$this->_variation
622
+					),
623
+					true
624
+				);
625
+				$CSS   = new TijsVerkoyen\CssToInlineStyles\CssToInlineStyles();
626
+				$body  = $CSS->convert($body, $style);
627
+			}
628
+		}
629
+		return $body;
630
+	}
631
+
632
+
633
+	/**
634
+	 * This just returns any existing test settings that might be saved in the database
635
+	 *
636
+	 * @access public
637
+	 * @return array
638
+	 * @throws EE_Error
639
+	 * @throws ReflectionException
640
+	 */
641
+	public function get_existing_test_settings()
642
+	{
643
+		$settings = parent::get_existing_test_settings();
644
+		// override subject if present because we always want it to be fresh.
645
+		if (is_array($settings) && ! empty($settings['subject'])) {
646
+			$settings['subject'] =
647
+				sprintf(esc_html__('Test email sent from %s', 'event_espresso'), get_bloginfo('name'));
648
+		}
649
+		return $settings;
650
+	}
651 651
 }
Please login to merge, or discard this patch.