Completed
Branch FET/10339/exit-modal-for-ee-de... (81712e)
by
unknown
29:29 queued 13:19
created

EE_Email_messenger::_headers()   B

Complexity

Conditions 3
Paths 2

Size

Total Lines 25
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 12
nc 2
nop 0
dl 0
loc 25
rs 8.8571
c 0
b 0
f 0
1
<?php
2
3
defined('EVENT_ESPRESSO_VERSION') || exit('No direct access allowed.');
4
5
/**
6
 * This sets up the email messenger for the EE_messages (notifications) subsystem in EE.
7
 */
8
class EE_Email_messenger extends EE_messenger
9
{
10
11
    /**
12
     * To field for email
13
     * @var string
14
     */
15
    protected $_to = '';
16
17
18
    /**
19
     * CC field for email.
20
     * @var string
21
     */
22
    protected $_cc = '';
23
24
    /**
25
     * From field for email
26
     * @var string
27
     */
28
    protected $_from = '';
29
30
31
    /**
32
     * Subject field for email
33
     * @var string
34
     */
35
    protected $_subject = '';
36
37
38
    /**
39
     * Content field for email
40
     * @var string
41
     */
42
    protected $_content = '';
43
44
45
    /**
46
     * constructor
47
     *
48
     * @access public
49
     */
50
    public function __construct()
51
    {
52
        //set name and description properties
53
        $this->name                = 'email';
54
        $this->description         = sprintf(
55
            esc_html__(
56
                'This messenger delivers messages via email using the built-in %s function included with WordPress',
57
                'event_espresso'
58
            ),
59
            '<code>wp_mail</code>'
60
        );
61
        $this->label               = array(
62
            'singular' => esc_html__('email', 'event_espresso'),
63
            'plural'   => esc_html__('emails', 'event_espresso'),
64
        );
65
        $this->activate_on_install = true;
66
67
        //we're using defaults so let's call parent constructor that will take care of setting up all the other
68
        // properties
69
        parent::__construct();
70
    }
71
72
73
    /**
74
     * see abstract declaration in parent class for details.
75
     */
76
    protected function _set_admin_pages()
77
    {
78
        $this->admin_registered_pages = array(
79
            'events_edit' => true,
80
        );
81
    }
82
83
84
    /**
85
     * see abstract declaration in parent class for details
86
     */
87
    protected function _set_valid_shortcodes()
88
    {
89
        //remember by leaving the other fields not set, those fields will inherit the valid shortcodes from the
90
        // message type.
91
        $this->_valid_shortcodes = array(
92
            'to'   => array('email', 'event_author', 'primary_registration_details', 'recipient_details'),
93
            'cc' => array('email', 'event_author', 'primary_registration_details', 'recipient_details'),
94
            'from' => array('email', 'event_author', 'primary_registration_details', 'recipient_details'),
95
        );
96
    }
97
98
99
    /**
100
     * see abstract declaration in parent class for details
101
     *
102
     * @access protected
103
     * @return void
104
     */
105
    protected function _set_validator_config()
106
    {
107
        $valid_shortcodes = $this->get_valid_shortcodes();
108
109
        $this->_validator_config = array(
110
            'to'            => array(
111
                'shortcodes' => $valid_shortcodes['to'],
112
                'type'       => 'email',
113
            ),
114
            'cc' => array(
115
                'shortcodes' => $valid_shortcodes['to'],
116
                'type' => 'email',
117
            ),
118
            'from'          => array(
119
                'shortcodes' => $valid_shortcodes['from'],
120
                'type'       => 'email',
121
            ),
122
            'subject'       => array(
123
                'shortcodes' => array(
124
                    'organization',
125
                    'primary_registration_details',
126
                    'event_author',
127
                    'primary_registration_details',
128
                    'recipient_details',
129
                ),
130
            ),
131
            'content'       => array(
132
                'shortcodes' => array(
133
                    'event_list',
134
                    'attendee_list',
135
                    'ticket_list',
136
                    'organization',
137
                    'primary_registration_details',
138
                    'primary_registration_list',
139
                    'event_author',
140
                    'recipient_details',
141
                    'recipient_list',
142
                    'transaction',
143
                    'messenger',
144
                ),
145
            ),
146
            'attendee_list' => array(
147
                'shortcodes' => array('attendee', 'event_list', 'ticket_list'),
148
                'required'   => array('[ATTENDEE_LIST]'),
149
            ),
150
            'event_list'    => array(
151
                'shortcodes' => array(
152
                    'event',
153
                    'attendee_list',
154
                    'ticket_list',
155
                    'venue',
156
                    'datetime_list',
157
                    'attendee',
158
                    'primary_registration_details',
159
                    'primary_registration_list',
160
                    'event_author',
161
                    'recipient_details',
162
                    'recipient_list',
163
                ),
164
                'required'   => array('[EVENT_LIST]'),
165
            ),
166
            'ticket_list'   => array(
167
                'shortcodes' => array(
168
                    'event_list',
169
                    'attendee_list',
170
                    'ticket',
171
                    'datetime_list',
172
                    'primary_registration_details',
173
                    'recipient_details',
174
                ),
175
                'required'   => array('[TICKET_LIST]'),
176
            ),
177
            'datetime_list' => array(
178
                'shortcodes' => array('datetime'),
179
                'required'   => array('[DATETIME_LIST]'),
180
            ),
181
        );
182
    }
183
184
185
    /**
186
     * @see   parent EE_messenger class for docs
187
     * @since 4.5.0
188
     */
189
    public function do_secondary_messenger_hooks($sending_messenger_name)
190
    {
191
        if ($sending_messenger_name = 'html') {
0 ignored issues
show
Unused Code introduced by
$sending_messenger_name is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
192
            add_filter('FHEE__EE_Messages_Template_Pack__get_variation', array($this, 'add_email_css'), 10, 8);
193
        }
194
    }
195
196
197
    public function add_email_css(
198
        $variation_path,
199
        $messenger,
200
        $message_type,
201
        $type,
202
        $variation,
203
        $file_extension,
204
        $url,
205
        EE_Messages_Template_Pack $template_pack
206
    ) {
207
        //prevent recursion on this callback.
208
        remove_filter('FHEE__EE_Messages_Template_Pack__get_variation', array($this, 'add_email_css'), 10);
209
        $variation = $this->get_variation($template_pack, $message_type, $url, 'main', $variation, false);
210
211
        add_filter('FHEE__EE_Messages_Template_Pack__get_variation', array($this, 'add_email_css'), 10, 8);
212
        return $variation;
213
    }
214
215
216
    /**
217
     * See parent for details
218
     *
219
     * @access protected
220
     * @return void
221
     */
222
    protected function _set_test_settings_fields()
223
    {
224
        $this->_test_settings_fields = array(
225
            'to'      => array(
226
                'input'      => 'text',
227
                'label'      => esc_html__('Send a test email to', 'event_espresso'),
228
                'type'       => 'email',
229
                'required'   => true,
230
                'validation' => true,
231
                'css_class'  => 'large-text',
232
                'format'     => '%s',
233
                'default'    => get_bloginfo('admin_email'),
234
            ),
235
            'subject' => array(
236
                'input'      => 'hidden',
237
                'label'      => '',
238
                'type'       => 'string',
239
                'required'   => false,
240
                'validation' => false,
241
                'format'     => '%s',
242
                'value'      => sprintf(__('Test email sent from %s', 'event_espresso'), get_bloginfo('name')),
243
                'default'    => '',
244
                'css_class'  => '',
245
            ),
246
        );
247
    }
248
249
250
    /**
251
     * _set_template_fields
252
     * This sets up the fields that a messenger requires for the message to go out.
253
     *
254
     * @access  protected
255
     * @return void
256
     */
257
    protected function _set_template_fields()
258
    {
259
        // any extra template fields that are NOT used by the messenger but will get used by a messenger field for
260
        // shortcode replacement get added to the 'extra' key in an associated array indexed by the messenger field
261
        // they relate to.  This is important for the Messages_admin to know what fields to display to the user.
262
        //  Also, notice that the "values" are equal to the field type that messages admin will use to know what
263
        // kind of field to display. The values ALSO have one index labeled "shortcode".  the values in that array
264
        // indicate which ACTUAL SHORTCODE (i.e. [SHORTCODE]) is required in order for this extra field to be
265
        // displayed.  If the required shortcode isn't part of the shortcodes array then the field is not needed and
266
        // will not be displayed/parsed.
267
        $this->_template_fields = array(
268
            'to'      => array(
269
                'input'      => 'text',
270
                'label'      => esc_html_x(
271
                    'To',
272
                    'Label for the "To" field for email addresses',
273
                    'event_espresso'
274
                ),
275
                'type'       => 'string',
276
                'required'   => true,
277
                'validation' => true,
278
                'css_class'  => 'large-text',
279
                'format'     => '%s',
280
            ),
281
            'cc'      => array(
282
                'input'      => 'text',
283
                'label'      => esc_html_x(
284
                    'CC',
285
                    'Label for the "Carbon Copy" field used for additional email addresses',
286
                    'event_espresso'
287
                ),
288
                'type'       => 'string',
289
                'required'   => false,
290
                'validation' => true,
291
                'css_class'  => 'large-text',
292
                'format'     => '%s',
293
            ),
294
            'from'    => array(
295
                'input'      => 'text',
296
                'label'      => esc_html_x(
297
                    'From',
298
                    'Label for the "From" field for email addresses.',
299
                    'event_espresso'
300
                ),
301
                'type'       => 'string',
302
                'required'   => true,
303
                'validation' => true,
304
                'css_class'  => 'large-text',
305
                'format'     => '%s',
306
            ),
307
            'subject' => array(
308
                'input'      => 'text',
309
                'label'      => esc_html_x(
310
                    'Subject',
311
                    'Label for the "Subject" field (short description of contents) for emails.',
312
                    'event_espresso'
313
                ),
314
                'type'       => 'string',
315
                'required'   => true,
316
                'validation' => true,
317
                'css_class'  => 'large-text',
318
                'format'     => '%s',
319
            ),
320
            'content' => '',
321
            //left empty b/c it is in the "extra array" but messenger still needs needs to know this is a field.
322
            'extra'   => array(
323
                'content' => array(
324
                    'main'          => array(
325
                        'input'      => 'wp_editor',
326
                        'label'      => esc_html__('Main Content', 'event_espresso'),
327
                        'type'       => 'string',
328
                        'required'   => true,
329
                        'validation' => true,
330
                        'format'     => '%s',
331
                        'rows'       => '15',
332
                    ),
333
                    'event_list'    => array(
334
                        'input'               => 'wp_editor',
335
                        'label'               => '[EVENT_LIST]',
336
                        'type'                => 'string',
337
                        'required'            => true,
338
                        'validation'          => true,
339
                        'format'              => '%s',
340
                        'rows'                => '15',
341
                        'shortcodes_required' => array('[EVENT_LIST]'),
342
                    ),
343
                    'attendee_list' => array(
344
                        'input'               => 'textarea',
345
                        'label'               => '[ATTENDEE_LIST]',
346
                        'type'                => 'string',
347
                        'required'            => true,
348
                        'validation'          => true,
349
                        'format'              => '%s',
350
                        'css_class'           => 'large-text',
351
                        'rows'                => '5',
352
                        'shortcodes_required' => array('[ATTENDEE_LIST]'),
353
                    ),
354
                    'ticket_list'   => array(
355
                        'input'               => 'textarea',
356
                        'label'               => '[TICKET_LIST]',
357
                        'type'                => 'string',
358
                        'required'            => true,
359
                        'validation'          => true,
360
                        'format'              => '%s',
361
                        'css_class'           => 'large-text',
362
                        'rows'                => '10',
363
                        'shortcodes_required' => array('[TICKET_LIST]'),
364
                    ),
365
                    'datetime_list' => array(
366
                        'input'               => 'textarea',
367
                        'label'               => '[DATETIME_LIST]',
368
                        'type'                => 'string',
369
                        'required'            => true,
370
                        'validation'          => true,
371
                        'format'              => '%s',
372
                        'css_class'           => 'large-text',
373
                        'rows'                => '10',
374
                        'shortcodes_required' => array('[DATETIME_LIST]'),
375
                    ),
376
                ),
377
            ),
378
        );
379
    }
380
381
382
    /**
383
     * See definition of this class in parent
384
     */
385
    protected function _set_default_message_types()
386
    {
387
        $this->_default_message_types = array(
388
            'payment',
389
            'payment_refund',
390
            'registration',
391
            'not_approved_registration',
392
            'pending_approval',
393
        );
394
    }
395
396
397
    /**
398
     * @see   definition of this class in parent
399
     * @since 4.5.0
400
     */
401
    protected function _set_valid_message_types()
402
    {
403
        $this->_valid_message_types = array(
404
            'payment',
405
            'registration',
406
            'not_approved_registration',
407
            'declined_registration',
408
            'cancelled_registration',
409
            'pending_approval',
410
            'registration_summary',
411
            'payment_reminder',
412
            'payment_declined',
413
            'payment_refund',
414
        );
415
    }
416
417
418
    /**
419
     * setting up admin_settings_fields for messenger.
420
     */
421
    protected function _set_admin_settings_fields()
422
    {
423
    }
424
425
    /**
426
     * We just deliver the messages don't kill us!!
427
     *
428
     * @return bool|WP_Error true if message delivered, false if it didn't deliver OR bubble up any error object if
429
     *              present.
430
     * @throws EE_Error
431
     * @throws \TijsVerkoyen\CssToInlineStyles\Exception
432
     */
433
    protected function _send_message()
434
    {
435
        $success = wp_mail(
436
            $this->_to,
437
            //some old values for subject may be expecting HTML entities to be decoded in the subject
438
            //and subjects aren't interpreted as HTML, so there should be no HTML in them
439
            wp_strip_all_tags(wp_specialchars_decode($this->_subject, ENT_QUOTES)),
440
            $this->_body(),
441
            $this->_headers()
442
        );
443
        if (! $success) {
444
            EE_Error::add_error(
445
                sprintf(
446
                    esc_html__(
447
                        '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',
448
                        'event_espresso'
449
                    ),
450
                    $this->_to,
451
                    $this->_from,
452
                    '<br />'
453
                ),
454
                __FILE__,
455
                __FUNCTION__,
456
                __LINE__
457
            );
458
        }
459
        return $success;
460
    }
461
462
463
    /**
464
     * see parent for definition
465
     *
466
     * @return string html body of the message content and the related css.
467
     * @throws EE_Error
468
     * @throws \TijsVerkoyen\CssToInlineStyles\Exception
469
     */
470
    protected function _preview()
471
    {
472
        return $this->_body(true);
473
    }
474
475
476
    /**
477
     * Setup headers for email
478
     *
479
     * @access protected
480
     * @return string formatted header for email
481
     */
482
    protected function _headers()
483
    {
484
        $this->_ensure_has_from_email_address();
485
        $from    = $this->_from;
486
        $headers = array(
487
            'From:' . $from,
488
            'Reply-To:' . $from,
489
            'Content-Type:text/html; charset=utf-8',
490
        );
491
492
        /**
493
         * Second condition added as a result of https://events.codebasehq.com/projects/event-espresso/tickets/11416 to
494
         * cover back compat where there may be users who have saved cc values in their db for the newsletter message
495
         * type which they are no longer able to change.
496
         */
497
        if (! empty($this->_cc) && ! $this->_incoming_message_type instanceof EE_Newsletter_message_type) {
498
            $headers[] = 'cc: ' . $this->_cc;
499
        }
500
501
        //but wait!  Header's for the from is NOT reliable because some plugins don't respect From: as set in the
502
        // header.
503
        add_filter('wp_mail_from', array($this, 'set_from_address'), 100);
504
        add_filter('wp_mail_from_name', array($this, 'set_from_name'), 100);
505
        return apply_filters('FHEE__EE_Email_messenger___headers', $headers, $this->_incoming_message_type, $this);
506
    }
507
508
509
    /**
510
     * This simply ensures that the from address is not empty.  If it is, then we use whatever is set as the site email
511
     * address for the from address to avoid problems with sending emails.
512
     */
513
    protected function _ensure_has_from_email_address()
514
    {
515
        if (empty($this->_from)) {
516
            $this->_from = get_bloginfo('admin_email');
517
        }
518
    }
519
520
521
    /**
522
     * This simply parses whatever is set as the $_from address and determines if it is in the format {name} <{email}>
523
     * or just {email} and returns an array with the "from_name" and "from_email" as the values. Note from_name *MAY*
524
     * be empty
525
     *
526
     * @since 4.3.1
527
     * @return array
528
     */
529
    private function _parse_from()
530
    {
531
        if (strpos($this->_from, '<') !== false) {
532
            $from_name = substr($this->_from, 0, strpos($this->_from, '<') - 1);
533
            $from_name = str_replace('"', '', $from_name);
534
            $from_name = trim($from_name);
535
536
            $from_email = substr($this->_from, strpos($this->_from, '<') + 1);
537
            $from_email = str_replace('>', '', $from_email);
538
            $from_email = trim($from_email);
539
        } elseif (trim($this->_from) !== '') {
540
            $from_name  = '';
541
            $from_email = trim($this->_from);
542
        } else {
543
            $from_name = $from_email = '';
544
        }
545
        return array($from_name, $from_email);
546
    }
547
548
549
    /**
550
     * Callback for the wp_mail_from filter.
551
     *
552
     * @since 4.3.1
553
     * @param string $from_email What the original from_email is.
554
     * @return string
555
     */
556
    public function set_from_address($from_email)
557
    {
558
        $parsed_from = $this->_parse_from();
559
        //includes fallback if the parsing failed.
560
        $from_email = is_array($parsed_from) && ! empty($parsed_from[1])
561
            ? $parsed_from[1]
562
            : get_bloginfo('admin_email');
563
        return $from_email;
564
    }
565
566
567
    /**
568
     * Callback fro the wp_mail_from_name filter.
569
     *
570
     * @since 4.3.1
571
     * @param string $from_name The original from_name.
572
     * @return string
573
     */
574
    public function set_from_name($from_name)
575
    {
576
        $parsed_from = $this->_parse_from();
577
        if (is_array($parsed_from) && ! empty($parsed_from[0])) {
578
            $from_name = $parsed_from[0];
579
        }
580
581
        //if from name is "WordPress" let's sub in the site name instead (more friendly!)
582
        //but realize the default name is HTML entity-encoded
583
        $from_name = $from_name == 'WordPress' ? wp_specialchars_decode(get_bloginfo(), ENT_QUOTES) : $from_name;
584
585
        return $from_name;
586
    }
587
588
589
    /**
590
     * setup body for email
591
     *
592
     * @param bool $preview will determine whether this is preview template or not.
593
     * @return string formatted body for email.
594
     * @throws EE_Error
595
     * @throws \TijsVerkoyen\CssToInlineStyles\Exception
596
     */
597
    protected function _body($preview = false)
598
    {
599
        //setup template args!
600
        $this->_template_args = array(
601
            'subject'   => $this->_subject,
602
            'from'      => $this->_from,
603
            'main_body' => wpautop($this->_content),
604
        );
605
        $body                 = $this->_get_main_template($preview);
606
607
        /**
608
         * This filter allows one to bypass the CSSToInlineStyles tool and leave the body untouched.
609
         *
610
         * @type    bool $preview Indicates whether a preview is being generated or not.
611
         * @return  bool    true  indicates to use the inliner, false bypasses it.
612
         */
613
        if (apply_filters('FHEE__EE_Email_messenger__apply_CSSInliner ', true, $preview)) {
614
            //require CssToInlineStyles library and its dependencies via composer autoloader
615
            require_once EE_THIRD_PARTY . 'cssinliner/vendor/autoload.php';
616
617
            //now if this isn't a preview, let's setup the body so it has inline styles
618
            if (! $preview || ($preview && defined('DOING_AJAX'))) {
619
                $style = file_get_contents(
620
                    $this->get_variation(
621
                        $this->_tmp_pack,
622
                        $this->_incoming_message_type->name,
623
                        false,
624
                        'main',
625
                        $this->_variation
626
                    ),
627
                    true
628
                );
629
                $CSS   = new TijsVerkoyen\CssToInlineStyles\CssToInlineStyles($body, $style);
630
                //for some reason the library has a bracket and new line at the beginning.  This takes care of that.
631
                $body  = ltrim($CSS->convert(true), ">\n");
632
                //see https://events.codebasehq.com/projects/event-espresso/tickets/8609
633
                $body  = ltrim($body, "<?");
634
            }
635
636
        }
637
        return $body;
638
    }
639
640
641
    /**
642
     * This just returns any existing test settings that might be saved in the database
643
     *
644
     * @access public
645
     * @return array
646
     */
647
    public function get_existing_test_settings()
648
    {
649
        $settings = parent::get_existing_test_settings();
650
        //override subject if present because we always want it to be fresh.
651
        if (is_array($settings) && ! empty($settings['subject'])) {
652
            $settings['subject'] = sprintf(__('Test email sent from %s', 'event_espresso'), get_bloginfo('name'));
653
        }
654
        return $settings;
655
    }
656
}
657