Completed
Push — develop ( c337fc...4b8a8e )
by Paul
02:01
created

Email::buildPlainTextMessage()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 1
1
<?php
2
3
namespace GeminiLabs\Castor;
4
5
use GeminiLabs\Castor\Helpers\Template;
6
use GeminiLabs\Castor\Helpers\Utility;
7
8
class Email
9
{
10
	/**
11
	 * @var Template
12
	 */
13
	public $template;
14
15
	/**
16
	 * @var Utility
17
	 */
18
	public $utility;
19
20
	/**
21
	 * @var array
22
	 */
23
	protected $attachments;
24
25
	/**
26
	 * @var array
27
	 */
28
	protected $headers;
29
30
	/**
31
	 * @var string
32
	 */
33
	protected $message;
34
35
	/**
36
	 * @var string
37
	 */
38
	protected $subject;
39
40
	/**
41
	 * @var string
42
	 */
43
	protected $to;
44
45
	public function __construct( Template $template, Utility $utility )
46
	{
47
		$this->template = $template;
48
		$this->utility  = $utility;
49
	}
50
51
	/**
52
	 * @return Email
53
	 */
54
	public function compose( array $email )
55
	{
56
		$email = $this->normalize( $email );
57
58
		$this->attachments = $email['attachments'];
59
		$this->headers     = $this->buildHeaders( $email );
60
		$this->message     = $this->buildHtmlMessage( $email );
61
		$this->subject     = $email['subject'];
62
		$this->to          = $email['to'];
63
64
		add_action( 'phpmailer_init', function( PHPMailer $phpmailer ) {
65
			if( $phpmailer->ContentType === 'text/plain' || !empty( $phpmailer->AltBody ))return;
66
			$phpmailer->AltBody = $this->buildPlainTextMessage( $phpmailer->Body );
67
		});
68
69
		return $this;
70
	}
71
72
	/**
73
	 * @param bool $plaintext
74
	 *
75
	 * @return string|null
76
	 */
77
	public function read( $plaintext = false )
78
	{
79
		return $plaintext
80
			? $this->buildPlainTextMessage( $this->message )
81
			: $this->message;
82
	}
83
84
	/**
85
	 * @return bool|null
86
	 */
87
	public function send()
88
	{
89
		if( !$this->message || !$this->subject || !$this->to )return;
90
91
		$sent = wp_mail(
92
			$this->to,
93
			$this->subject,
94
			$this->message,
95
			$this->headers,
96
			$this->attachments
97
		);
98
99
		$this->reset();
100
101
		return $sent;
102
	}
103
104
	/**
105
	 * @return array
106
	 */
107
	protected function buildHeaders( array $email )
108
	{
109
		$allowed = [
110
			'bcc',
111
			'cc',
112
			'from',
113
			'reply-to',
114
		];
115
116
		$headers = array_intersect_key( $email, array_flip( $allowed ));
117
		$headers = array_filter( $headers );
118
119
		foreach( $headers as $key => $value ) {
120
			unset( $headers[ $key ] );
121
			$headers[] = sprintf( '%s: %s', $key, $value );
122
		}
123
124
		$headers[] = 'Content-Type: text/html';
125
126
		return apply_filters( 'castor/email/headers', $headers, $this );
127
	}
128
129
	/**
130
	 * @return string
131
	 */
132
	protected function buildHtmlMessage( array $email )
133
	{
134
		$body = $this->renderTemplate( 'email' );
135
136
		$message = !empty( $email['template'] )
137
			? $this->renderTemplate( $email['template'], $email['template-tags'] )
138
			: $email['message'];
139
140
		$message = $this->filterHtml( $email['before'] . $message . $email['after'] );
141
		$message = str_replace( '{message}', $message, $body );
142
143
		return apply_filters( 'castor/email/message', $message, 'html', $this );
144
	}
145
146
	/**
147
	 * @param string $message
148
	 *
149
	 * @return string
150
	 */
151
	protected function buildPlainTextMessage( $message )
152
	{
153
		return apply_filters( 'castor/email/message', $this->stripHtmlTags( $message ), 'text', $this );
154
	}
155
156
	/**
157
	 * @param string $message
158
	 *
159
	 * @return string
160
	 */
161
	protected function filterHtml( $message )
162
	{
163
		$message = strip_shortcodes( $message );
164
		$message = wptexturize( $message );
165
		$message = wpautop( $message );
166
		$message = str_replace( ['&lt;&gt; ', ']]>'], ['', ']]&gt;'], $message );
167
		$message = stripslashes( $message );
168
		return $message;
169
	}
170
171
	/**
172
	 * @return array
173
	 */
174
	protected function normalize( $email )
175
	{
176
		$from = sprintf( '%s <%s>',
177
			wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES ),
178
			get_option( 'admin_email' )
179
		);
180
181
		$defaults = [
182
			'after'         => '',
183
			'attachments'   => [],
184
			'bcc'           => '',
185
			'before'        => '',
186
			'cc'            => '',
187
			'from'          => $from,
188
			'message'       => '',
189
			'reply-to'      => '',
190
			'subject'       => '',
191
			'template'      => '',
192
			'template-tags' => [],
193
			'to'            => '',
194
		];
195
196
		$email = shortcode_atts( $defaults, $email );
197
198
		if( empty( $email['reply-to'] )) {
199
			$email['reply-to'] = $email['from'];
200
		}
201
202
		return apply_filters( 'castor/email/compose', $email, $this );
203
	}
204
205
	/**
206
	 * @return void
207
	 */
208
	protected function reset()
209
	{
210
		$this->attachments = [];
211
		$this->headers = [];
212
		$this->message = null;
213
		$this->subject = null;
214
		$this->to = null;
215
	}
216
217
	/**
218
	 * @param string $templatePath
219
	 *
220
	 * @return void|string
221
	 */
222
	protected function renderTemplate( $templatePath, array $args = [] )
223
	{
224
		$file = $this->template->get( sprintf( 'castor/%s', $templatePath ));
225
226
		if( !file_exists( $file )) {
227
			$file = sprintf( '%s/templates/%s.php', dirname( __DIR__ ), $templatePath );
228
		}
229
		if( !file_exists( $file ))return;
230
231
		ob_start();
232
		include $file;
233
		$template = ob_get_clean();
234
235
		return $this->renderTemplateString( $template, $args, $print );
0 ignored issues
show
Bug introduced by
The variable $print does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
Unused Code introduced by
The call to Email::renderTemplateString() has too many arguments starting with $print.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
236
	}
237
238
	/**
239
	 * @param string $template
240
	 *
241
	 * @return string
242
	 */
243
	protected function renderTemplateString( $template, array $args = [] )
244
	{
245
		foreach( $args as $key => $value ) {
246
			$template = str_replace( sprintf( '{%s}', $key ), $value, $template );
247
		}
248
		return trim( $template );
249
	}
250
251
	/**
252
	 * - remove invisible elements
253
	 * - replace certain elements with a line-break
254
	 * - replace certain table elements with a space
255
	 * - add a placeholder for plain-text bullets to list elements
256
	 * - strip all remaining HTML tags
257
	 * @return string
258
	 */
259
	protected function stripHtmlTags( $string )
260
	{
261
		$string = preg_replace( '@<(embed|head|noembed|noscript|object|script|style)[^>]*?>.*?</\\1>@siu', '', $string );
262
		$string = preg_replace( '@</(div|h[1-9]|p|pre|tr)@iu', "\r\n\$0", $string );
263
		$string = preg_replace( '@</(td|th)@iu', " \$0", $string );
264
		$string = preg_replace( '@<(li)[^>]*?>@siu', "\$0-o-^-o-", $string );
265
		$string = wp_strip_all_tags( $string );
266
		$string = wp_specialchars_decode( $string, ENT_QUOTES );
267
		$string = preg_replace( '/\v(?:[\v\h]+){2,}/', "\r\n\r\n", $string );
268
		$string = str_replace( '-o-^-o-', ' - ', $string );
269
		return html_entity_decode( $string, ENT_QUOTES, 'UTF-8' );
270
	}
271
}
272