Passed
Push — master ( ea4f63...197c27 )
by Paul
20:35 queued 09:52
created

Email::logMailError()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
eloc 2
c 0
b 0
f 0
dl 0
loc 4
ccs 0
cts 3
cp 0
rs 10
cc 1
nc 1
nop 1
crap 2
1
<?php
2
3
namespace GeminiLabs\SiteReviews\Modules;
4
5
use GeminiLabs\SiteReviews\Database\OptionManager;
6
use GeminiLabs\SiteReviews\Defaults\EmailDefaults;
7
use GeminiLabs\SiteReviews\Modules\Html\Template;
8
9
class Email
10
{
11
    /**
12
     * @var array
13
     */
14
    public $attachments;
15
16
    /**
17
     * @var array
18
     */
19
    public $data;
20
21
    /**
22
     * @var array
23
     */
24
    public $email;
25
26
    /**
27
     * @var array
28
     */
29
    public $headers;
30
31
    /**
32
     * @var string
33
     */
34
    public $message;
35
36
    /**
37
     * @var string
38
     */
39
    public $subject;
40
41
    /**
42
     * @var string|array
43
     */
44
    public $to;
45
46
    /**
47
     * @return \GeminiLabs\SiteReviews\Application|\GeminiLabs\SiteReviews\Addons\Addon
48
     */
49 1
    public function app()
50
    {
51 1
        return glsr();
52
    }
53
54
    /**
55
     * @return Email
56
     */
57 1
    public function compose(array $email, array $data = [])
58
    {
59 1
        $this->data = $data;
60 1
        $this->normalize($email);
61 1
        $this->attachments = $this->email['attachments'];
62 1
        $this->headers = $this->buildHeaders();
63 1
        $this->message = $this->buildHtmlMessage();
64 1
        $this->subject = $this->email['subject'];
65 1
        $this->to = $this->email['to'];
66 1
        add_action('phpmailer_init', [$this, 'buildPlainTextMessage']);
67 1
        return $this;
68
    }
69
70
    /**
71
     * @return \GeminiLabs\SiteReviews\Defaults\DefaultsAbstract
72
     */
73 1
    public function defaults()
74
    {
75 1
        return glsr(EmailDefaults::class);
76
    }
77
78
    /**
79
     * @param \WP_Error $error
80
     * @return void
81
     */
82
    public function logMailError($error)
83
    {
84
        glsr_log()->error('Email was not sent (wp_mail failed)')
85
            ->debug(['error' => $error, 'instance' => $this]);
86
    }
87
88
    /**
89
     * @param string $format
90
     * @return string
91
     */
92
    public function read($format = '')
93
    {
94
        if ('plaintext' == $format) {
95
            $message = $this->stripHtmlTags($this->message);
96
            return $this->app()->filterString('email/message', $message, 'text', $this);
97
        }
98
        return $this->message;
99
    }
100
101
    /**
102
     * @return void|bool
103
     */
104 1
    public function send()
105
    {
106 1
        if (!$this->message || !$this->subject || !$this->to) {
107
            glsr_log()->warning('The email was not sent because it is missing either the email address, subject, or message.');
108
            return;
109
        }
110 1
        add_action('wp_mail_failed', [$this, 'logMailError']);
111 1
        $sent = wp_mail(
112 1
            $this->to,
113 1
            $this->subject,
114 1
            $this->message,
115 1
            $this->headers,
116 1
            $this->attachments
117
        );
118 1
        remove_action('wp_mail_failed', [$this, 'logMailError']);
119 1
        $this->reset();
120 1
        return $sent;
121
    }
122
123
    /**
124
     * @return \GeminiLabs\SiteReviews\Contracts\TemplateContract
125
     */
126 1
    public function template()
127
    {
128 1
        return glsr(Template::class);
129
    }
130
131
    /**
132
     * @return void
133
     * @action phpmailer_init
134
     */
135 1
    public function buildPlainTextMessage($phpmailer)
136
    {
137 1
        if (empty($this->email)) {
138
            return;
139
        }
140 1
        if ('text/plain' === $phpmailer->ContentType || !empty($phpmailer->AltBody)) {
141
            return;
142
        }
143 1
        $message = $this->stripHtmlTags($phpmailer->Body);
144 1
        $phpmailer->AltBody = $this->app()->filterString('email/message', $message, 'text', $this);
145 1
    }
146
147
    /**
148
     * @return array
149
     */
150 1
    protected function buildHeaders()
151
    {
152
        $allowed = [
153 1
            'bcc', 'cc', 'from', 'reply-to',
154
        ];
155 1
        $headers = array_intersect_key($this->email, array_flip($allowed));
156 1
        $headers = array_filter($headers);
157 1
        foreach ($headers as $key => $value) {
158 1
            unset($headers[$key]);
159 1
            $headers[] = $key.': '.$value;
160
        }
161 1
        $headers[] = 'Content-Type: text/html';
162 1
        return $this->app()->filterArray('email/headers', $headers, $this);
163
    }
164
165
    /**
166
     * @return string
167
     */
168 1
    protected function buildHtmlMessage()
169
    {
170 1
        $message = $this->buildMessage();
171 1
        $message = $this->email['before'].$message.$this->email['after'];
172 1
        $message = strip_shortcodes($message);
173 1
        $message = wptexturize($message);
174 1
        $message = wpautop($message);
175 1
        $message = str_replace('&lt;&gt; ', '', $message);
176 1
        $message = str_replace(']]>', ']]&gt;', $message);
177 1
        $context = wp_parse_args(['message' => $message], $this->email['template-tags']);
178 1
        $message = $this->template()->build('templates/emails/'.$this->email['template'], [
179 1
            'context' => $context,
180
        ]);
181 1
        return $this->app()->filterString('email/message', stripslashes($message), 'html', $this);
182
    }
183
184
    /**
185
     * @return string
186
     */
187 1
    protected function buildMessage()
188
    {
189 1
        if (!empty($this->email['message'])) {
190
            return $this->email['message'];
191
        }
192 1
        $template = trim(glsr(OptionManager::class)->get('settings.general.notification_message'));
193 1
        if (!empty($template)) {
194 1
            $context = ['context' => $this->email['template-tags']];
195 1
            $templatePathForHook = 'notification_message';
196 1
            return $this->template()->interpolate($template, $templatePathForHook, $context);
197
        }
198
        return '';
199
    }
200
201
    /**
202
     * @return void
203
     */
204 1
    protected function normalize(array $email = [])
205
    {
206 1
        $email = $this->defaults()->restrict($email);
207 1
        $this->email = $this->app()->filterArray('email/compose', $email, $this);
208 1
    }
209
210
    /**
211
     * @return void
212
     */
213 1
    protected function reset()
214
    {
215 1
        $this->attachments = [];
216 1
        $this->data = [];
217 1
        $this->email = [];
218 1
        $this->headers = [];
219 1
        $this->message = '';
220 1
        $this->subject = '';
221 1
        $this->to = '';
222 1
    }
223
224
    /**
225
     * @return string
226
     */
227 1
    protected function stripHtmlTags($string)
228
    {
229
        // remove invisible elements
230 1
        $string = preg_replace('@<(embed|head|noembed|noscript|object|script|style)[^>]*?>.*?</\\1>@siu', '', $string);
231
        // replace certain elements with a line-break
232 1
        $string = preg_replace('@</(div|h[1-9]|p|pre|tr)@iu', "\r\n\$0", $string);
233
        // replace other elements with a space
234 1
        $string = preg_replace('@</(td|th)@iu', ' $0', $string);
235
        // add a placeholder for plain-text bullets to list elements
236 1
        $string = preg_replace('@<(li)[^>]*?>@siu', '$0-o-^-o-', $string);
237
        // strip all remaining HTML tags
238 1
        $string = wp_strip_all_tags($string);
239 1
        $string = wp_specialchars_decode($string, ENT_QUOTES);
240 1
        $string = preg_replace('/\v(?:[\v\h]+){2,}/u', "\r\n\r\n", $string);
241 1
        $string = str_replace('-o-^-o-', ' - ', $string);
242 1
        return html_entity_decode($string, ENT_QUOTES, 'UTF-8');
243
    }
244
}
245