PluginProbe ʕ •ᴥ•ʔ
WooCommerce / 6.9.2
WooCommerce v6.9.2
10.8.1 10.8.0 10.8.0-rc.1 10.8.0-beta.2 10.8.0-beta.1 7.8.0-beta.1 7.8.0-beta.2 7.8.0-rc.1 7.8.0-rc.2 7.8.1 7.8.2 7.8.3 7.8.4 7.9.0 7.9.0-beta.1 7.9.0-beta.2 7.9.0-rc.2 7.9.0-rc.3 7.9.1 7.9.2 8.0.0 8.0.0-beta.1 8.0.0-beta.2 8.0.0-rc.1 8.0.0-rc.2 8.0.1 8.0.2 8.0.3 8.0.4 8.0.5 8.1.0 8.1.0-beta.1 8.1.0-rc.1 8.1.0-rc.2 8.1.1 8.1.2 8.1.3 8.1.4 8.2.0 8.2.0-beta.1 8.2.0-rc.1 8.2.0-rc.2 8.2.1 8.2.2 8.2.3 8.2.4 8.2.5 8.3.0 8.3.0-beta.1 8.3.0-rc.1 8.3.0-rc.2 8.3.1 8.3.2 8.3.3 8.3.4 8.4.0 8.4.0-beta.1 8.4.0-rc.1 8.4.1 8.4.2 8.4.3 8.5.0 8.5.0-beta.1 8.5.0-rc.1 8.5.1 8.5.2 8.5.3 8.5.4 8.5.5 8.6.0 8.6.0-beta.1 8.6.0-rc.1 8.6.1 8.6.2 8.6.3 8.6.4 8.7.0 8.7.0-beta.1 8.7.0-beta.2 8.7.0-rc.1 8.7.1 8.7.2 8.7.3 8.8.0 8.8.0-beta.1 8.8.0-rc.1 8.8.1 8.8.2 8.8.3 8.8.4 8.8.5 8.8.6 8.8.7 8.9.0 8.9.0-beta.1 8.9.0-rc.1 8.9.1 8.9.2 8.9.3 8.9.4 8.9.5 9.0.0 9.0.0-beta.1 9.0.0-beta.2 9.0.0-rc.1 9.0.1 9.0.2 9.0.3 9.0.4 9.1.0 9.1.0-beta.1 9.1.0-rc.1 9.1.1 9.1.2 9.1.3 9.1.4 9.1.5 9.1.6 9.2.0 9.2.0-beta.1 9.2.0-rc.1 9.2.1 9.2.2 9.2.3 9.2.4 9.2.5 9.3.0 9.3.0-beta.1 9.3.0-rc.1 9.3.1 9.3.2 9.3.3 9.3.4 9.3.5 9.3.6 9.4.0 9.4.0-beta.1 9.4.0-beta.2 9.4.0-rc.1 9.4.0-rc.2 9.4.0-rc.3 9.4.0-rc.4 9.4.1 9.4.2 9.4.3 9.4.4 9.4.5 9.5.0 9.5.0-beta.1 9.5.0-beta.2 9.5.0-rc.1 9.5.1 9.5.2 9.5.3 9.5.4 9.6.0 9.6.0-beta.1 9.6.0-beta.2 9.6.0-rc.1 9.6.1 9.6.2 9.6.3 9.6.4 9.7.0 9.7.0-beta.1 9.7.0-rc.1 9.7.1 9.7.2 9.7.3 9.8.0 9.8.0-beta.1 9.8.0-rc.1 9.8.1 9.8.2 9.8.3 9.8.4 9.8.5 9.8.6 9.8.7 9.9.0 9.9.0-beta.1 9.9.0-rc.1 9.9.1 9.9.2 9.9.3 9.9.4 9.9.5 9.9.6 9.9.7 3.7.3 7.1.2 3.8.0 7.2.0 3.8.0-beta.1 7.2.0-beta.1 3.8.0-rc.1 7.2.0-beta.2 3.8.0-rc.2 7.2.0-rc.1 3.8.1 7.2.0-rc.2 3.8.2 7.2.1 3.8.3 7.2.2 3.9.0 7.2.3 3.9.0-beta.1 7.2.4 3.9.0-beta.2 7.3.0 3.9.0-rc.1 7.3.0-beta.1 3.9.0-rc.2 7.3.0-beta.2 3.9.0-rc.3 7.3.0-rc.1 3.9.0-rc.4 7.3.0-rc.2 3.9.1 7.3.1 3.9.2 7.4.0 3.9.3 7.4.0-beta.1 3.9.4 7.4.0-beta.2 3.9.5 7.4.0-rc.1 4.0.0 7.4.0-rc.2 4.0.0-beta.1 7.4.1 4.0.0-rc.1 7.4.2 4.0.0-rc.2 7.5.0 4.0.1 7.5.0-beta.1 4.0.2 7.5.0-beta.2 4.0.3 7.5.0-rc.1 4.0.4 7.5.1 4.1.0 7.5.2 4.1.0-beta.1 7.6.0 4.1.0-beta.2 7.6.0-beta.1 4.1.0-rc.1 7.6.0-beta.2 4.1.0-rc.2 7.6.0-rc.1 4.1.1 7.6.0-rc.2 4.1.2 7.6.0-rc.3 4.1.3 7.6.1 4.1.4 7.6.2 4.2.0 7.7.0 4.2.0-RC.1 7.7.0-beta.1 4.2.0-RC.2 7.7.0-beta.2 4.2.0-beta.1 7.7.0-rc.1 4.2.1 7.7.1 4.2.2 7.7.2 4.2.3 7.7.3 4.2.4 7.8.0 4.2.5 4.3.0 4.3.0-beta.1 4.3.0-rc.1 4.3.0-rc.2 4.3.0-rc.3 4.3.1 4.3.2 4.3.3 4.3.4 4.3.5 4.3.6 4.4.0 4.4.0-beta.1 4.4.0-rc.1 4.4.1 4.4.2 4.4.3 4.4.4 4.5.0 4.5.0-beta.1 4.5.0-rc.1 4.5.0-rc.3 4.5.1 4.5.2 4.5.3 4.5.4 4.5.5 4.6.0 4.6.0-beta.1 4.6.0-rc.1 4.6.1 4.6.2 4.6.3 4.6.4 4.6.5 4.7.0 4.7.0-beta.1 4.7.0-beta.2 4.7.0-rc.1 4.7.1 4.7.1-beta.1 4.7.2 4.7.3 4.7.4 4.8.0 4.8.0-beta.1 4.8.0-rc.1 4.8.0-rc.2 4.8.1 4.8.2 4.8.3 4.9.0 4.9.0-beta.1 4.9.0-rc.1 4.9.0-rc.2 4.9.1 4.9.2 4.9.3 4.9.4 4.9.5 5.0.0 5.0.0-beta.1 5.0.0-beta.2 5.0.0-rc.1 5.0.0-rc.2 5.0.0-rc.3 5.0.1 5.0.2 5.0.3 5.1.0 5.1.0-beta.1 5.1.0-rc.1 trunk 5.1.1 10.0.0 5.1.2 10.0.0-rc.1 5.1.3 10.0.0-rc.2 5.2.0 10.0.1 5.2.0-beta.1 10.0.2 5.2.0-rc.1 10.0.3 5.2.0-rc.2 10.0.4 5.2.1 10.0.5 5.2.2 10.0.6 5.2.3 10.1.0 5.2.4 10.1.0-rc.1 5.2.5 10.1.0-rc.2 5.3.0 10.1.0-rc.3 5.3.0-beta.1 10.1.0-rc.4 5.3.0-rc.1 10.1.1 5.3.0-rc.2 10.1.2 5.3.1 10.1.3 5.3.2 10.1.4 5.3.3 10.2.0 5.4.0 10.2.0-beta.1 5.4.0-beta.1 10.2.0-beta.2 5.4.0-rc.1 10.2.0-rc.1 5.4.1 10.2.1 5.4.2 10.2.2 5.4.3 10.2.3 5.4.4 10.2.4 5.4.5 10.3.0 5.5.0 10.3.0-beta.1 5.5.0-beta.1 10.3.0-beta.2 5.5.0-rc.1 10.3.0-rc.1 5.5.0-rc.2 10.3.0-rc.2 5.5.1 10.3.1 5.5.2 10.3.2 5.5.3 10.3.3 5.5.4 10.3.4 5.5.5 10.3.5 5.6.0 10.3.6 5.6.0-beta.1 10.3.7 5.6.0-rc.1 10.3.8 5.6.0-rc.2 10.4.0 5.6.1 10.4.0-beta.1 5.6.2 10.4.0-beta.2 5.6.3 10.4.0-rc.1 5.7.0 10.4.1 5.7.0-beta.1 10.4.2 5.7.0-rc.1 10.4.3 5.7.1 10.4.4 5.7.2 10.5.0 5.7.3 10.5.0-beta.1 5.8.0 10.5.0-beta.2 5.8.0-beta.1 10.5.0-rc.1 5.8.0-beta.2 10.5.0-rc.2 5.8.0-rc.1 10.5.0-rc.3 5.8.1 10.5.1 5.8.2 10.5.2 5.9.0 10.5.3 5.9.0-beta.1 10.6.0 5.9.0-rc.1 10.6.0-beta.1 5.9.0-rc.2 10.6.0-beta.2 5.9.1 10.6.0-rc.1 5.9.2 10.6.1 6.0.0 10.6.2 6.0.0-beta.1 10.7.0 6.0.0-rc.1 10.7.0-beta.1 6.0.1 10.7.0-beta.2 6.0.2 10.7.0-rc.1 6.1.0 3.0.0 6.1.0-beta.1 3.0.1 6.1.0-rc.1 3.0.2 6.1.0-rc.2 3.0.3 6.1.1 3.0.4 6.1.2 3.0.5 6.1.3 3.0.6 6.2.0 3.0.7 6.2.0-beta.1 3.0.8 6.2.0-rc.1 3.0.9 6.2.0-rc.2 3.1.0 6.2.1 3.1.1 6.2.2 3.1.2 6.2.3 3.2.0 6.3.0 3.2.1 6.3.0-beta.1 3.2.2 6.3.0-rc.1 3.2.3 6.3.0-rc.2 3.2.4 6.3.1 3.2.5 6.3.2 3.2.6 6.4.0 3.3.0 6.4.0-beta.1 3.3.1 6.4.0-rc.1 3.3.2 6.4.1 3.3.2-rc.1 6.4.2 3.3.3 6.5.0 3.3.4 6.5.0-beta.1 3.3.5 6.5.0-rc.1 3.3.6 6.5.0-rc.2 3.4.0 6.5.1 3.4.0-beta.1 6.5.2 3.4.0-rc.2 6.6.0 3.4.1 6.6.0-beta.1 3.4.2 6.6.0-rc.1 3.4.3 6.6.0-rc.2 3.4.4 6.6.1 3.4.5 6.6.2 3.4.6 6.7.0 3.4.7 6.7.0-beta.1 3.4.8 6.7.0-beta.2 3.5.0 6.7.0-rc.1 3.5.0-beta.1 6.7.1 3.5.0-rc.1 6.8.0 3.5.0-rc.2 6.8.0-beta.1 3.5.1 6.8.0-beta.2 3.5.10 6.8.0-rc.1 3.5.2 6.8.1 3.5.3 6.8.2 3.5.4 6.8.3 3.5.5 6.9.0 3.5.6 6.9.0-beta.1 3.5.7 6.9.0-beta.2 3.5.8 6.9.0-rc.1 3.5.9 6.9.1 3.6.0 6.9.2 3.6.0-beta.1 6.9.3 3.6.0-rc.1 6.9.4 3.6.0-rc.2 6.9.5 3.6.0-rc.3 7.0.0 3.6.1 7.0.0-beta.1 3.6.2 7.0.0-beta.2 3.6.3 7.0.0-beta.3 3.6.4 7.0.0-rc.1 3.6.5 7.0.0-rc.2 3.6.6 7.0.1 3.6.7 7.0.2 3.7.0 7.1.0 3.7.0-beta.1 7.1.0-beta.1 3.7.0-rc.1 7.1.0-beta.2 3.7.0-rc.2 7.1.0-rc.1 3.7.1 7.1.0-rc.2 3.7.2 7.1.1
woocommerce / includes / emails / class-wc-email.php
woocommerce / includes / emails Last commit date
class-wc-email-cancelled-order.php 5 years ago class-wc-email-customer-completed-order.php 5 years ago class-wc-email-customer-invoice.php 5 years ago class-wc-email-customer-new-account.php 4 years ago class-wc-email-customer-note.php 5 years ago class-wc-email-customer-on-hold-order.php 4 years ago class-wc-email-customer-processing-order.php 5 years ago class-wc-email-customer-refunded-order.php 5 years ago class-wc-email-customer-reset-password.php 5 years ago class-wc-email-failed-order.php 5 years ago class-wc-email-new-order.php 5 years ago class-wc-email.php 3 years ago
class-wc-email.php
1142 lines
1 <?php
2 /**
3 * Class WC_Email file.
4 *
5 * @package WooCommerce\Emails
6 */
7
8 use Pelago\Emogrifier\CssInliner;
9 use Pelago\Emogrifier\HtmlProcessor\CssToAttributeConverter;
10 use Pelago\Emogrifier\HtmlProcessor\HtmlPruner;
11
12 if ( ! defined( 'ABSPATH' ) ) {
13 exit;
14 }
15
16 if ( class_exists( 'WC_Email', false ) ) {
17 return;
18 }
19
20 /**
21 * Email Class
22 *
23 * WooCommerce Email Class which is extended by specific email template classes to add emails to WooCommerce
24 *
25 * @class WC_Email
26 * @version 2.5.0
27 * @package WooCommerce\Classes\Emails
28 * @extends WC_Settings_API
29 */
30 class WC_Email extends WC_Settings_API {
31
32 /**
33 * Email method ID.
34 *
35 * @var String
36 */
37 public $id;
38
39 /**
40 * Email method title.
41 *
42 * @var string
43 */
44 public $title;
45
46 /**
47 * 'yes' if the method is enabled.
48 *
49 * @var string yes, no
50 */
51 public $enabled;
52
53 /**
54 * Description for the email.
55 *
56 * @var string
57 */
58 public $description;
59
60 /**
61 * Default heading.
62 *
63 * Supported for backwards compatibility but we recommend overloading the
64 * get_default_x methods instead so localization can be done when needed.
65 *
66 * @var string
67 */
68 public $heading = '';
69
70 /**
71 * Default subject.
72 *
73 * Supported for backwards compatibility but we recommend overloading the
74 * get_default_x methods instead so localization can be done when needed.
75 *
76 * @var string
77 */
78 public $subject = '';
79
80 /**
81 * Plain text template path.
82 *
83 * @var string
84 */
85 public $template_plain;
86
87 /**
88 * HTML template path.
89 *
90 * @var string
91 */
92 public $template_html;
93
94 /**
95 * Template path.
96 *
97 * @var string
98 */
99 public $template_base;
100
101 /**
102 * Recipients for the email.
103 *
104 * @var string
105 */
106 public $recipient;
107
108 /**
109 * Object this email is for, for example a customer, product, or email.
110 *
111 * @var object|bool
112 */
113 public $object;
114
115 /**
116 * Mime boundary (for multipart emails).
117 *
118 * @var string
119 */
120 public $mime_boundary;
121
122 /**
123 * Mime boundary header (for multipart emails).
124 *
125 * @var string
126 */
127 public $mime_boundary_header;
128
129 /**
130 * True when email is being sent.
131 *
132 * @var bool
133 */
134 public $sending;
135
136 /**
137 * True when the email notification is sent manually only.
138 *
139 * @var bool
140 */
141 protected $manual = false;
142
143 /**
144 * True when the email notification is sent to customers.
145 *
146 * @var bool
147 */
148 protected $customer_email = false;
149
150 /**
151 * List of preg* regular expression patterns to search for,
152 * used in conjunction with $plain_replace.
153 * https://raw.github.com/ushahidi/wp-silcc/master/class.html2text.inc
154 *
155 * @var array $plain_search
156 * @see $plain_replace
157 */
158 public $plain_search = array(
159 "/\r/", // Non-legal carriage return.
160 '/&(nbsp|#0*160);/i', // Non-breaking space.
161 '/&(quot|rdquo|ldquo|#0*8220|#0*8221|#0*147|#0*148);/i', // Double quotes.
162 '/&(apos|rsquo|lsquo|#0*8216|#0*8217);/i', // Single quotes.
163 '/&gt;/i', // Greater-than.
164 '/&lt;/i', // Less-than.
165 '/&#0*38;/i', // Ampersand.
166 '/&amp;/i', // Ampersand.
167 '/&(copy|#0*169);/i', // Copyright.
168 '/&(trade|#0*8482|#0*153);/i', // Trademark.
169 '/&(reg|#0*174);/i', // Registered.
170 '/&(mdash|#0*151|#0*8212);/i', // mdash.
171 '/&(ndash|minus|#0*8211|#0*8722);/i', // ndash.
172 '/&(bull|#0*149|#0*8226);/i', // Bullet.
173 '/&(pound|#0*163);/i', // Pound sign.
174 '/&(euro|#0*8364);/i', // Euro sign.
175 '/&(dollar|#0*36);/i', // Dollar sign.
176 '/&[^&\s;]+;/i', // Unknown/unhandled entities.
177 '/[ ]{2,}/', // Runs of spaces, post-handling.
178 );
179
180 /**
181 * List of pattern replacements corresponding to patterns searched.
182 *
183 * @var array $plain_replace
184 * @see $plain_search
185 */
186 public $plain_replace = array(
187 '', // Non-legal carriage return.
188 ' ', // Non-breaking space.
189 '"', // Double quotes.
190 "'", // Single quotes.
191 '>', // Greater-than.
192 '<', // Less-than.
193 '&', // Ampersand.
194 '&', // Ampersand.
195 '(c)', // Copyright.
196 '(tm)', // Trademark.
197 '(R)', // Registered.
198 '--', // mdash.
199 '-', // ndash.
200 '*', // Bullet.
201 '£', // Pound sign.
202 'EUR', // Euro sign. € ?.
203 '$', // Dollar sign.
204 '', // Unknown/unhandled entities.
205 ' ', // Runs of spaces, post-handling.
206 );
207
208 /**
209 * Strings to find/replace in subjects/headings.
210 *
211 * @var array
212 */
213 protected $placeholders = array();
214
215 /**
216 * Strings to find in subjects/headings.
217 *
218 * @deprecated 3.2.0 in favour of placeholders
219 * @var array
220 */
221 public $find = array();
222
223 /**
224 * Strings to replace in subjects/headings.
225 *
226 * @deprecated 3.2.0 in favour of placeholders
227 * @var array
228 */
229 public $replace = array();
230
231 /**
232 * Constructor.
233 */
234 public function __construct() {
235 // Find/replace.
236 $this->placeholders = array_merge(
237 array(
238 '{site_title}' => $this->get_blogname(),
239 '{site_address}' => wp_parse_url( home_url(), PHP_URL_HOST ),
240 '{site_url}' => wp_parse_url( home_url(), PHP_URL_HOST ),
241 ),
242 $this->placeholders
243 );
244
245 // Init settings.
246 $this->init_form_fields();
247 $this->init_settings();
248
249 // Default template base if not declared in child constructor.
250 if ( is_null( $this->template_base ) ) {
251 $this->template_base = WC()->plugin_path() . '/templates/';
252 }
253
254 $this->email_type = $this->get_option( 'email_type' );
255 $this->enabled = $this->get_option( 'enabled' );
256
257 add_action( 'phpmailer_init', array( $this, 'handle_multipart' ) );
258 add_action( 'woocommerce_update_options_email_' . $this->id, array( $this, 'process_admin_options' ) );
259 }
260
261 /**
262 * Handle multipart mail.
263 *
264 * @param PHPMailer $mailer PHPMailer object.
265 * @return PHPMailer
266 */
267 public function handle_multipart( $mailer ) {
268 if ( ! $this->sending ) {
269 return $mailer;
270 }
271
272 if ( 'multipart' === $this->get_email_type() ) {
273 $mailer->AltBody = wordwrap( // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
274 preg_replace( $this->plain_search, $this->plain_replace, wp_strip_all_tags( $this->get_content_plain() ) )
275 );
276 } else {
277 $mailer->AltBody = ''; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
278 }
279
280 $this->sending = false;
281 return $mailer;
282 }
283
284 /**
285 * Format email string.
286 *
287 * @param mixed $string Text to replace placeholders in.
288 * @return string
289 */
290 public function format_string( $string ) {
291 $find = array_keys( $this->placeholders );
292 $replace = array_values( $this->placeholders );
293
294 // If using legacy find replace, add those to our find/replace arrays first. @todo deprecate in 4.0.0.
295 $find = array_merge( (array) $this->find, $find );
296 $replace = array_merge( (array) $this->replace, $replace );
297
298 // Take care of blogname which is no longer defined as a valid placeholder.
299 $find[] = '{blogname}';
300 $replace[] = $this->get_blogname();
301
302 // If using the older style filters for find and replace, ensure the array is associative and then pass through filters. @todo deprecate in 4.0.0.
303 if ( has_filter( 'woocommerce_email_format_string_replace' ) || has_filter( 'woocommerce_email_format_string_find' ) ) {
304 $legacy_find = $this->find;
305 $legacy_replace = $this->replace;
306
307 foreach ( $this->placeholders as $find => $replace ) {
308 $legacy_key = sanitize_title( str_replace( '_', '-', trim( $find, '{}' ) ) );
309 $legacy_find[ $legacy_key ] = $find;
310 $legacy_replace[ $legacy_key ] = $replace;
311 }
312
313 $string = str_replace( apply_filters( 'woocommerce_email_format_string_find', $legacy_find, $this ), apply_filters( 'woocommerce_email_format_string_replace', $legacy_replace, $this ), $string );
314 }
315
316 /**
317 * Filter for main find/replace.
318 *
319 * @since 3.2.0
320 */
321 return apply_filters( 'woocommerce_email_format_string', str_replace( $find, $replace, $string ), $this );
322 }
323
324 /**
325 * Set the locale to the store locale for customer emails to make sure emails are in the store language.
326 */
327 public function setup_locale() {
328
329 /**
330 * Filter the ability to switch email locale.
331 *
332 * @since 6.8.0
333 *
334 * @param bool $default_value The default returned value.
335 * @param WC_Email $this The WC_Email object.
336 */
337 $switch_email_locale = apply_filters( 'woocommerce_allow_switching_email_locale', true, $this );
338
339 if ( $switch_email_locale && $this->is_customer_email() && apply_filters( 'woocommerce_email_setup_locale', true ) ) {
340 wc_switch_to_site_locale();
341 }
342 }
343
344 /**
345 * Restore the locale to the default locale. Use after finished with setup_locale.
346 */
347 public function restore_locale() {
348
349 /**
350 * Filter the ability to restore email locale.
351 *
352 * @since 6.8.0
353 *
354 * @param bool $default_value The default returned value.
355 * @param WC_Email $this The WC_Email object.
356 */
357 $restore_email_locale = apply_filters( 'woocommerce_allow_restoring_email_locale', true, $this );
358
359 if ( $restore_email_locale && $this->is_customer_email() && apply_filters( 'woocommerce_email_restore_locale', true ) ) {
360 wc_restore_locale();
361 }
362 }
363
364 /**
365 * Get email subject.
366 *
367 * @since 3.1.0
368 * @return string
369 */
370 public function get_default_subject() {
371 return $this->subject;
372 }
373
374 /**
375 * Get email heading.
376 *
377 * @since 3.1.0
378 * @return string
379 */
380 public function get_default_heading() {
381 return $this->heading;
382 }
383
384 /**
385 * Default content to show below main email content.
386 *
387 * @since 3.7.0
388 * @return string
389 */
390 public function get_default_additional_content() {
391 return '';
392 }
393
394 /**
395 * Return content from the additional_content field.
396 *
397 * Displayed above the footer.
398 *
399 * @since 3.7.0
400 * @return string
401 */
402 public function get_additional_content() {
403 $content = $this->get_option( 'additional_content', '' );
404
405 return apply_filters( 'woocommerce_email_additional_content_' . $this->id, $this->format_string( $content ), $this->object, $this );
406 }
407
408 /**
409 * Get email subject.
410 *
411 * @return string
412 */
413 public function get_subject() {
414 return apply_filters( 'woocommerce_email_subject_' . $this->id, $this->format_string( $this->get_option( 'subject', $this->get_default_subject() ) ), $this->object, $this );
415 }
416
417 /**
418 * Get email heading.
419 *
420 * @return string
421 */
422 public function get_heading() {
423 return apply_filters( 'woocommerce_email_heading_' . $this->id, $this->format_string( $this->get_option( 'heading', $this->get_default_heading() ) ), $this->object, $this );
424 }
425
426 /**
427 * Get valid recipients.
428 *
429 * @return string
430 */
431 public function get_recipient() {
432 $recipient = apply_filters( 'woocommerce_email_recipient_' . $this->id, $this->recipient, $this->object, $this );
433 $recipients = array_map( 'trim', explode( ',', $recipient ) );
434 $recipients = array_filter( $recipients, 'is_email' );
435 return implode( ', ', $recipients );
436 }
437
438 /**
439 * Get email headers.
440 *
441 * @return string
442 */
443 public function get_headers() {
444 $header = 'Content-Type: ' . $this->get_content_type() . "\r\n";
445
446 if ( in_array( $this->id, array( 'new_order', 'cancelled_order', 'failed_order' ), true ) ) {
447 if ( $this->object && $this->object->get_billing_email() && ( $this->object->get_billing_first_name() || $this->object->get_billing_last_name() ) ) {
448 $header .= 'Reply-to: ' . $this->object->get_billing_first_name() . ' ' . $this->object->get_billing_last_name() . ' <' . $this->object->get_billing_email() . ">\r\n";
449 }
450 } elseif ( $this->get_from_address() && $this->get_from_name() ) {
451 $header .= 'Reply-to: ' . $this->get_from_name() . ' <' . $this->get_from_address() . ">\r\n";
452 }
453
454 return apply_filters( 'woocommerce_email_headers', $header, $this->id, $this->object, $this );
455 }
456
457 /**
458 * Get email attachments.
459 *
460 * @return array
461 */
462 public function get_attachments() {
463 return apply_filters( 'woocommerce_email_attachments', array(), $this->id, $this->object, $this );
464 }
465
466 /**
467 * Return email type.
468 *
469 * @return string
470 */
471 public function get_email_type() {
472 return $this->email_type && class_exists( 'DOMDocument' ) ? $this->email_type : 'plain';
473 }
474
475 /**
476 * Get email content type.
477 *
478 * @param string $default_content_type Default wp_mail() content type.
479 * @return string
480 */
481 public function get_content_type( $default_content_type = '' ) {
482 switch ( $this->get_email_type() ) {
483 case 'html':
484 $content_type = 'text/html';
485 break;
486 case 'multipart':
487 $content_type = 'multipart/alternative';
488 break;
489 default:
490 $content_type = 'text/plain';
491 break;
492 }
493
494 return apply_filters( 'woocommerce_email_content_type', $content_type, $this, $default_content_type );
495 }
496
497 /**
498 * Return the email's title
499 *
500 * @return string
501 */
502 public function get_title() {
503 return apply_filters( 'woocommerce_email_title', $this->title, $this );
504 }
505
506 /**
507 * Return the email's description
508 *
509 * @return string
510 */
511 public function get_description() {
512 return apply_filters( 'woocommerce_email_description', $this->description, $this );
513 }
514
515 /**
516 * Proxy to parent's get_option and attempt to localize the result using gettext.
517 *
518 * @param string $key Option key.
519 * @param mixed $empty_value Value to use when option is empty.
520 * @return string
521 */
522 public function get_option( $key, $empty_value = null ) {
523 $value = parent::get_option( $key, $empty_value );
524 return apply_filters( 'woocommerce_email_get_option', $value, $this, $value, $key, $empty_value );
525 }
526
527 /**
528 * Checks if this email is enabled and will be sent.
529 *
530 * @return bool
531 */
532 public function is_enabled() {
533 return apply_filters( 'woocommerce_email_enabled_' . $this->id, 'yes' === $this->enabled, $this->object, $this );
534 }
535
536 /**
537 * Checks if this email is manually sent
538 *
539 * @return bool
540 */
541 public function is_manual() {
542 return $this->manual;
543 }
544
545 /**
546 * Checks if this email is customer focussed.
547 *
548 * @return bool
549 */
550 public function is_customer_email() {
551 return $this->customer_email;
552 }
553
554 /**
555 * Get WordPress blog name.
556 *
557 * @return string
558 */
559 public function get_blogname() {
560 return wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES );
561 }
562
563 /**
564 * Get email content.
565 *
566 * @return string
567 */
568 public function get_content() {
569 $this->sending = true;
570
571 if ( 'plain' === $this->get_email_type() ) {
572 $email_content = wordwrap( preg_replace( $this->plain_search, $this->plain_replace, wp_strip_all_tags( $this->get_content_plain() ) ), 70 );
573 } else {
574 $email_content = $this->get_content_html();
575 }
576
577 return $email_content;
578 }
579
580 /**
581 * Apply inline styles to dynamic content.
582 *
583 * We only inline CSS for html emails, and to do so we use Emogrifier library (if supported).
584 *
585 * @version 4.0.0
586 * @param string|null $content Content that will receive inline styles.
587 * @return string
588 */
589 public function style_inline( $content ) {
590 if ( in_array( $this->get_content_type(), array( 'text/html', 'multipart/alternative' ), true ) ) {
591 ob_start();
592 wc_get_template( 'emails/email-styles.php' );
593 $css = apply_filters( 'woocommerce_email_styles', ob_get_clean(), $this );
594
595 $css_inliner_class = CssInliner::class;
596
597 if ( $this->supports_emogrifier() && class_exists( $css_inliner_class ) ) {
598 try {
599 $css_inliner = CssInliner::fromHtml( $content )->inlineCss( $css );
600
601 do_action( 'woocommerce_emogrifier', $css_inliner, $this );
602
603 $dom_document = $css_inliner->getDomDocument();
604
605 HtmlPruner::fromDomDocument( $dom_document )->removeElementsWithDisplayNone();
606 $content = CssToAttributeConverter::fromDomDocument( $dom_document )
607 ->convertCssToVisualAttributes()
608 ->render();
609 } catch ( Exception $e ) {
610 $logger = wc_get_logger();
611 $logger->error( $e->getMessage(), array( 'source' => 'emogrifier' ) );
612 }
613 } else {
614 $content = '<style type="text/css">' . $css . '</style>' . $content;
615 }
616 }
617
618 return $content;
619 }
620
621 /**
622 * Return if emogrifier library is supported.
623 *
624 * @version 4.0.0
625 * @since 3.5.0
626 * @return bool
627 */
628 protected function supports_emogrifier() {
629 return class_exists( 'DOMDocument' );
630 }
631
632 /**
633 * Get the email content in plain text format.
634 *
635 * @return string
636 */
637 public function get_content_plain() {
638 return '';
639 }
640
641 /**
642 * Get the email content in HTML format.
643 *
644 * @return string
645 */
646 public function get_content_html() {
647 return '';
648 }
649
650 /**
651 * Get the from name for outgoing emails.
652 *
653 * @param string $from_name Default wp_mail() name associated with the "from" email address.
654 * @return string
655 */
656 public function get_from_name( $from_name = '' ) {
657 $from_name = apply_filters( 'woocommerce_email_from_name', get_option( 'woocommerce_email_from_name' ), $this, $from_name );
658 return wp_specialchars_decode( esc_html( $from_name ), ENT_QUOTES );
659 }
660
661 /**
662 * Get the from address for outgoing emails.
663 *
664 * @param string $from_email Default wp_mail() email address to send from.
665 * @return string
666 */
667 public function get_from_address( $from_email = '' ) {
668 $from_email = apply_filters( 'woocommerce_email_from_address', get_option( 'woocommerce_email_from_address' ), $this, $from_email );
669 return sanitize_email( $from_email );
670 }
671
672 /**
673 * Send an email.
674 *
675 * @param string $to Email to.
676 * @param string $subject Email subject.
677 * @param string $message Email message.
678 * @param string $headers Email headers.
679 * @param array $attachments Email attachments.
680 * @return bool success
681 */
682 public function send( $to, $subject, $message, $headers, $attachments ) {
683 add_filter( 'wp_mail_from', array( $this, 'get_from_address' ) );
684 add_filter( 'wp_mail_from_name', array( $this, 'get_from_name' ) );
685 add_filter( 'wp_mail_content_type', array( $this, 'get_content_type' ) );
686
687 $message = apply_filters( 'woocommerce_mail_content', $this->style_inline( $message ) );
688 $mail_callback = apply_filters( 'woocommerce_mail_callback', 'wp_mail', $this );
689 $mail_callback_params = apply_filters( 'woocommerce_mail_callback_params', array( $to, wp_specialchars_decode( $subject ), $message, $headers, $attachments ), $this );
690 $return = $mail_callback( ...$mail_callback_params );
691
692 remove_filter( 'wp_mail_from', array( $this, 'get_from_address' ) );
693 remove_filter( 'wp_mail_from_name', array( $this, 'get_from_name' ) );
694 remove_filter( 'wp_mail_content_type', array( $this, 'get_content_type' ) );
695
696 // Clear the AltBody (if set) so that it does not leak across to different emails.
697 $this->clear_alt_body_field();
698
699 /**
700 * Action hook fired when an email is sent.
701 *
702 * @since 5.6.0
703 * @param bool $return Whether the email was sent successfully.
704 * @param int $id Email ID.
705 * @param WC_Email $this WC_Email instance.
706 */
707 do_action( 'woocommerce_email_sent', $return, $this->id, $this );
708
709 return $return;
710 }
711
712 /**
713 * Initialise Settings Form Fields - these are generic email options most will use.
714 */
715 public function init_form_fields() {
716 /* translators: %s: list of placeholders */
717 $placeholder_text = sprintf( __( 'Available placeholders: %s', 'woocommerce' ), '<code>' . esc_html( implode( '</code>, <code>', array_keys( $this->placeholders ) ) ) . '</code>' );
718 $this->form_fields = array(
719 'enabled' => array(
720 'title' => __( 'Enable/Disable', 'woocommerce' ),
721 'type' => 'checkbox',
722 'label' => __( 'Enable this email notification', 'woocommerce' ),
723 'default' => 'yes',
724 ),
725 'subject' => array(
726 'title' => __( 'Subject', 'woocommerce' ),
727 'type' => 'text',
728 'desc_tip' => true,
729 'description' => $placeholder_text,
730 'placeholder' => $this->get_default_subject(),
731 'default' => '',
732 ),
733 'heading' => array(
734 'title' => __( 'Email heading', 'woocommerce' ),
735 'type' => 'text',
736 'desc_tip' => true,
737 'description' => $placeholder_text,
738 'placeholder' => $this->get_default_heading(),
739 'default' => '',
740 ),
741 'additional_content' => array(
742 'title' => __( 'Additional content', 'woocommerce' ),
743 'description' => __( 'Text to appear below the main email content.', 'woocommerce' ) . ' ' . $placeholder_text,
744 'css' => 'width:400px; height: 75px;',
745 'placeholder' => __( 'N/A', 'woocommerce' ),
746 'type' => 'textarea',
747 'default' => $this->get_default_additional_content(),
748 'desc_tip' => true,
749 ),
750 'email_type' => array(
751 'title' => __( 'Email type', 'woocommerce' ),
752 'type' => 'select',
753 'description' => __( 'Choose which format of email to send.', 'woocommerce' ),
754 'default' => 'html',
755 'class' => 'email_type wc-enhanced-select',
756 'options' => $this->get_email_type_options(),
757 'desc_tip' => true,
758 ),
759 );
760 }
761
762 /**
763 * Email type options.
764 *
765 * @return array
766 */
767 public function get_email_type_options() {
768 $types = array( 'plain' => __( 'Plain text', 'woocommerce' ) );
769
770 if ( class_exists( 'DOMDocument' ) ) {
771 $types['html'] = __( 'HTML', 'woocommerce' );
772 $types['multipart'] = __( 'Multipart', 'woocommerce' );
773 }
774
775 return $types;
776 }
777
778 /**
779 * Admin Panel Options Processing.
780 */
781 public function process_admin_options() {
782 // Save regular options.
783 parent::process_admin_options();
784
785 $post_data = $this->get_post_data();
786
787 // Save templates.
788 if ( isset( $post_data['template_html_code'] ) ) {
789 $this->save_template( $post_data['template_html_code'], $this->template_html );
790 }
791 if ( isset( $post_data['template_plain_code'] ) ) {
792 $this->save_template( $post_data['template_plain_code'], $this->template_plain );
793 }
794 }
795
796 /**
797 * Get template.
798 *
799 * @param string $type Template type. Can be either 'template_html' or 'template_plain'.
800 * @return string
801 */
802 public function get_template( $type ) {
803 $type = basename( $type );
804
805 if ( 'template_html' === $type ) {
806 return $this->template_html;
807 } elseif ( 'template_plain' === $type ) {
808 return $this->template_plain;
809 }
810 return '';
811 }
812
813 /**
814 * Save the email templates.
815 *
816 * @since 2.4.0
817 * @param string $template_code Template code.
818 * @param string $template_path Template path.
819 */
820 protected function save_template( $template_code, $template_path ) {
821 if ( current_user_can( 'edit_themes' ) && ! empty( $template_code ) && ! empty( $template_path ) ) {
822 $saved = false;
823 $file = $this->get_theme_template_file( $template_path );
824 $code = wp_unslash( $template_code );
825
826 if ( is_writeable( $file ) ) { // phpcs:ignore WordPress.VIP.FileSystemWritesDisallow.file_ops_is_writeable
827 $f = fopen( $file, 'w+' ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_fopen
828
829 if ( false !== $f ) {
830 fwrite( $f, $code ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_fwrite
831 fclose( $f ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_fclose
832 $saved = true;
833 }
834 }
835
836 if ( ! $saved ) {
837 $redirect = add_query_arg( 'wc_error', rawurlencode( __( 'Could not write to template file.', 'woocommerce' ) ) );
838 wp_safe_redirect( $redirect );
839 exit;
840 }
841 }
842 }
843
844 /**
845 * Get the template file in the current theme.
846 *
847 * @param string $template Template name.
848 *
849 * @return string
850 */
851 public function get_theme_template_file( $template ) {
852 return get_stylesheet_directory() . '/' . apply_filters( 'woocommerce_template_directory', 'woocommerce', $template ) . '/' . $template;
853 }
854
855 /**
856 * Move template action.
857 *
858 * @param string $template_type Template type.
859 */
860 protected function move_template_action( $template_type ) {
861 $template = $this->get_template( $template_type );
862 if ( ! empty( $template ) ) {
863 $theme_file = $this->get_theme_template_file( $template );
864
865 if ( wp_mkdir_p( dirname( $theme_file ) ) && ! file_exists( $theme_file ) ) {
866
867 // Locate template file.
868 $core_file = $this->template_base . $template;
869 $template_file = apply_filters( 'woocommerce_locate_core_template', $core_file, $template, $this->template_base, $this->id );
870
871 // Copy template file.
872 copy( $template_file, $theme_file );
873
874 /**
875 * Action hook fired after copying email template file.
876 *
877 * @param string $template_type The copied template type
878 * @param string $email The email object
879 */
880 do_action( 'woocommerce_copy_email_template', $template_type, $this );
881
882 ?>
883 <div class="updated">
884 <p><?php echo esc_html__( 'Template file copied to theme.', 'woocommerce' ); ?></p>
885 </div>
886 <?php
887 }
888 }
889 }
890
891 /**
892 * Delete template action.
893 *
894 * @param string $template_type Template type.
895 */
896 protected function delete_template_action( $template_type ) {
897 $template = $this->get_template( $template_type );
898
899 if ( $template ) {
900 if ( ! empty( $template ) ) {
901 $theme_file = $this->get_theme_template_file( $template );
902
903 if ( file_exists( $theme_file ) ) {
904 unlink( $theme_file ); // phpcs:ignore WordPress.VIP.FileSystemWritesDisallow.file_ops_unlink
905
906 /**
907 * Action hook fired after deleting template file.
908 *
909 * @param string $template The deleted template type
910 * @param string $email The email object
911 */
912 do_action( 'woocommerce_delete_email_template', $template_type, $this );
913 ?>
914 <div class="updated">
915 <p><?php echo esc_html__( 'Template file deleted from theme.', 'woocommerce' ); ?></p>
916 </div>
917 <?php
918 }
919 }
920 }
921 }
922
923 /**
924 * Admin actions.
925 */
926 protected function admin_actions() {
927 // Handle any actions.
928 if (
929 ( ! empty( $this->template_html ) || ! empty( $this->template_plain ) )
930 && ( ! empty( $_GET['move_template'] ) || ! empty( $_GET['delete_template'] ) )
931 && 'GET' === $_SERVER['REQUEST_METHOD'] // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotValidated
932 ) {
933 if ( empty( $_GET['_wc_email_nonce'] ) || ! wp_verify_nonce( wc_clean( wp_unslash( $_GET['_wc_email_nonce'] ) ), 'woocommerce_email_template_nonce' ) ) {
934 wp_die( esc_html__( 'Action failed. Please refresh the page and retry.', 'woocommerce' ) );
935 }
936
937 if ( ! current_user_can( 'edit_themes' ) ) {
938 wp_die( esc_html__( 'You don&#8217;t have permission to do this.', 'woocommerce' ) );
939 }
940
941 if ( ! empty( $_GET['move_template'] ) ) {
942 $this->move_template_action( wc_clean( wp_unslash( $_GET['move_template'] ) ) );
943 }
944
945 if ( ! empty( $_GET['delete_template'] ) ) {
946 $this->delete_template_action( wc_clean( wp_unslash( $_GET['delete_template'] ) ) );
947 }
948 }
949 }
950
951 /**
952 * Admin Options.
953 *
954 * Setup the email settings screen.
955 * Override this in your email.
956 *
957 * @since 1.0.0
958 */
959 public function admin_options() {
960 // Do admin actions.
961 $this->admin_actions();
962 ?>
963 <h2><?php echo esc_html( $this->get_title() ); ?> <?php wc_back_link( __( 'Return to emails', 'woocommerce' ), admin_url( 'admin.php?page=wc-settings&tab=email' ) ); ?></h2>
964
965 <?php echo wpautop( wp_kses_post( $this->get_description() ) ); // phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped ?>
966
967 <?php
968 /**
969 * Action hook fired before displaying email settings.
970 *
971 * @param string $email The email object
972 */
973 do_action( 'woocommerce_email_settings_before', $this );
974 ?>
975
976 <table class="form-table">
977 <?php $this->generate_settings_html(); ?>
978 </table>
979
980 <?php
981 /**
982 * Action hook fired after displaying email settings.
983 *
984 * @param string $email The email object
985 */
986 do_action( 'woocommerce_email_settings_after', $this );
987 ?>
988
989 <?php
990
991 if ( current_user_can( 'edit_themes' ) && ( ! empty( $this->template_html ) || ! empty( $this->template_plain ) ) ) {
992 ?>
993 <div id="template">
994 <?php
995 $templates = array(
996 'template_html' => __( 'HTML template', 'woocommerce' ),
997 'template_plain' => __( 'Plain text template', 'woocommerce' ),
998 );
999
1000 foreach ( $templates as $template_type => $title ) :
1001 $template = $this->get_template( $template_type );
1002
1003 if ( empty( $template ) ) {
1004 continue;
1005 }
1006
1007 $local_file = $this->get_theme_template_file( $template );
1008 $core_file = $this->template_base . $template;
1009 $template_file = apply_filters( 'woocommerce_locate_core_template', $core_file, $template, $this->template_base, $this->id );
1010 $template_dir = apply_filters( 'woocommerce_template_directory', 'woocommerce', $template );
1011 ?>
1012 <div class="template <?php echo esc_attr( $template_type ); ?>">
1013 <h4><?php echo wp_kses_post( $title ); ?></h4>
1014
1015 <?php if ( file_exists( $local_file ) ) : ?>
1016 <p>
1017 <a href="#" class="button toggle_editor"></a>
1018
1019 <?php if ( is_writable( $local_file ) ) : // phpcs:ignore WordPress.VIP.FileSystemWritesDisallow.file_ops_is_writable ?>
1020 <a href="<?php echo esc_url( wp_nonce_url( remove_query_arg( array( 'move_template', 'saved' ), add_query_arg( 'delete_template', $template_type ) ), 'woocommerce_email_template_nonce', '_wc_email_nonce' ) ); ?>" class="delete_template button">
1021 <?php esc_html_e( 'Delete template file', 'woocommerce' ); ?>
1022 </a>
1023 <?php endif; ?>
1024
1025 <?php
1026 /* translators: %s: Path to template file */
1027 printf( esc_html__( 'This template has been overridden by your theme and can be found in: %s.', 'woocommerce' ), '<code>' . esc_html( trailingslashit( basename( get_stylesheet_directory() ) ) . $template_dir . '/' . $template ) . '</code>' );
1028 ?>
1029 </p>
1030
1031 <div class="editor" style="display:none">
1032 <textarea class="code" cols="25" rows="20"
1033 <?php
1034 if ( ! is_writable( $local_file ) ) : // phpcs:ignore WordPress.VIP.FileSystemWritesDisallow.file_ops_is_writable
1035 ?>
1036 readonly="readonly" disabled="disabled"
1037 <?php else : ?>
1038 data-name="<?php echo esc_attr( $template_type ) . '_code'; ?>"<?php endif; ?>><?php echo esc_html( file_get_contents( $local_file ) ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents ?></textarea>
1039 </div>
1040 <?php elseif ( file_exists( $template_file ) ) : ?>
1041 <p>
1042 <a href="#" class="button toggle_editor"></a>
1043
1044 <?php
1045 $emails_dir = get_stylesheet_directory() . '/' . $template_dir . '/emails';
1046 $templates_dir = get_stylesheet_directory() . '/' . $template_dir;
1047 $theme_dir = get_stylesheet_directory();
1048
1049 if ( is_dir( $emails_dir ) ) {
1050 $target_dir = $emails_dir;
1051 } elseif ( is_dir( $templates_dir ) ) {
1052 $target_dir = $templates_dir;
1053 } else {
1054 $target_dir = $theme_dir;
1055 }
1056
1057 if ( is_writable( $target_dir ) ) : // phpcs:ignore WordPress.VIP.FileSystemWritesDisallow.file_ops_is_writable
1058 ?>
1059 <a href="<?php echo esc_url( wp_nonce_url( remove_query_arg( array( 'delete_template', 'saved' ), add_query_arg( 'move_template', $template_type ) ), 'woocommerce_email_template_nonce', '_wc_email_nonce' ) ); ?>" class="button">
1060 <?php esc_html_e( 'Copy file to theme', 'woocommerce' ); ?>
1061 </a>
1062 <?php endif; ?>
1063
1064 <?php
1065 /* translators: 1: Path to template file 2: Path to theme folder */
1066 printf( esc_html__( 'To override and edit this email template copy %1$s to your theme folder: %2$s.', 'woocommerce' ), '<code>' . esc_html( plugin_basename( $template_file ) ) . '</code>', '<code>' . esc_html( trailingslashit( basename( get_stylesheet_directory() ) ) . $template_dir . '/' . $template ) . '</code>' );
1067 ?>
1068 </p>
1069
1070 <div class="editor" style="display:none">
1071 <textarea class="code" readonly="readonly" disabled="disabled" cols="25" rows="20"><?php echo esc_html( file_get_contents( $template_file ) ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents ?></textarea>
1072 </div>
1073 <?php else : ?>
1074 <p><?php esc_html_e( 'File was not found.', 'woocommerce' ); ?></p>
1075 <?php endif; ?>
1076 </div>
1077 <?php endforeach; ?>
1078 </div>
1079
1080 <?php
1081 wc_enqueue_js(
1082 "jQuery( 'select.email_type' ).on( 'change', function() {
1083
1084 var val = jQuery( this ).val();
1085
1086 jQuery( '.template_plain, .template_html' ).show();
1087
1088 if ( val != 'multipart' && val != 'html' ) {
1089 jQuery('.template_html').hide();
1090 }
1091
1092 if ( val != 'multipart' && val != 'plain' ) {
1093 jQuery('.template_plain').hide();
1094 }
1095
1096 }).trigger( 'change' );
1097
1098 var view = '" . esc_js( __( 'View template', 'woocommerce' ) ) . "';
1099 var hide = '" . esc_js( __( 'Hide template', 'woocommerce' ) ) . "';
1100
1101 jQuery( 'a.toggle_editor' ).text( view ).on( 'click', function() {
1102 var label = hide;
1103
1104 if ( jQuery( this ).closest(' .template' ).find( '.editor' ).is(':visible') ) {
1105 var label = view;
1106 }
1107
1108 jQuery( this ).text( label ).closest(' .template' ).find( '.editor' ).slideToggle();
1109 return false;
1110 } );
1111
1112 jQuery( 'a.delete_template' ).on( 'click', function() {
1113 if ( window.confirm('" . esc_js( __( 'Are you sure you want to delete this template file?', 'woocommerce' ) ) . "') ) {
1114 return true;
1115 }
1116
1117 return false;
1118 });
1119
1120 jQuery( '.editor textarea' ).on( 'change', function() {
1121 var name = jQuery( this ).attr( 'data-name' );
1122
1123 if ( name ) {
1124 jQuery( this ).attr( 'name', name );
1125 }
1126 });"
1127 );
1128 }
1129 }
1130
1131 /**
1132 * Clears the PhpMailer AltBody field, to prevent that content from leaking across emails.
1133 */
1134 private function clear_alt_body_field(): void {
1135 global $phpmailer;
1136
1137 if ( $phpmailer instanceof PHPMailer\PHPMailer\PHPMailer ) {
1138 $phpmailer->AltBody = ''; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
1139 }
1140 }
1141 }
1142