WC_Emails::customer_new_account()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
dl 0
loc 10
rs 9.4285
c 0
b 0
f 0
eloc 6
nc 3
nop 3
1
<?php
2
3
if ( ! defined( 'ABSPATH' ) ) {
4
	exit; // Exit if accessed directly
5
}
6
7
/**
8
 * Transactional Emails Controller
9
 *
10
 * WooCommerce Emails Class which handles the sending on transactional emails and email templates. This class loads in available emails.
11
 *
12
 * @class 		WC_Emails
13
 * @version		2.3.0
14
 * @package		WooCommerce/Classes/Emails
15
 * @category	Class
16
 * @author 		WooThemes
17
 */
18
class WC_Emails {
19
20
	/** @var array Array of email notification classes */
21
	public $emails;
22
23
	/** @var WC_Emails The single instance of the class */
24
	protected static $_instance = null;
25
26
	/**
27
	 * Main WC_Emails Instance.
28
	 *
29
	 * Ensures only one instance of WC_Emails is loaded or can be loaded.
30
	 *
31
	 * @since 2.1
32
	 * @static
33
	 * @return WC_Emails Main instance
34
	 */
35
	public static function instance() {
36
		if ( is_null( self::$_instance ) ) {
37
			self::$_instance = new self();
38
		}
39
		return self::$_instance;
40
	}
41
42
	/**
43
	 * Cloning is forbidden.
44
	 *
45
	 * @since 2.1
46
	 */
47
	public function __clone() {
48
		_doing_it_wrong( __FUNCTION__, __( 'Cheatin&#8217; huh?', 'woocommerce' ), '2.1' );
49
	}
50
51
	/**
52
	 * Unserializing instances of this class is forbidden.
53
	 *
54
	 * @since 2.1
55
	 */
56
	public function __wakeup() {
57
		_doing_it_wrong( __FUNCTION__, __( 'Cheatin&#8217; huh?', 'woocommerce' ), '2.1' );
58
	}
59
60
	/**
61
	 * Hook in all transactional emails.
62
	 */
63
	public static function init_transactional_emails() {
64
		$email_actions = apply_filters( 'woocommerce_email_actions', array(
65
			'woocommerce_low_stock',
66
			'woocommerce_no_stock',
67
			'woocommerce_product_on_backorder',
68
			'woocommerce_order_status_pending_to_processing',
69
			'woocommerce_order_status_pending_to_completed',
70
			'woocommerce_order_status_pending_to_cancelled',
71
			'woocommerce_order_status_pending_to_failed',
72
			'woocommerce_order_status_pending_to_on-hold',
73
			'woocommerce_order_status_failed_to_processing',
74
			'woocommerce_order_status_failed_to_completed',
75
			'woocommerce_order_status_failed_to_on-hold',
76
			'woocommerce_order_status_on-hold_to_processing',
77
			'woocommerce_order_status_on-hold_to_cancelled',
78
			'woocommerce_order_status_on-hold_to_failed',
79
			'woocommerce_order_status_completed',
80
			'woocommerce_order_fully_refunded',
81
			'woocommerce_order_partially_refunded',
82
			'woocommerce_new_customer_note',
83
			'woocommerce_created_customer'
84
		) );
85
86
		foreach ( $email_actions as $action ) {
87
			add_action( $action, array( __CLASS__, 'send_transactional_email' ), 10, 10 );
88
		}
89
	}
90
91
	/**
92
	 * Init the mailer instance and call the notifications for the current filter.
93
	 * @internal param array $args (default: array())
94
	 */
95
	public static function send_transactional_email() {
96
		self::instance();
97
		$args = func_get_args();
98
		do_action_ref_array( current_filter() . '_notification', $args );
99
	}
100
101
	/**
102
	 * Constructor for the email class hooks in all emails that can be sent.
103
	 *
104
	 */
105
	public function __construct() {
106
		$this->init();
107
108
		// Email Header, Footer and content hooks
109
		add_action( 'woocommerce_email_header', array( $this, 'email_header' ) );
110
		add_action( 'woocommerce_email_footer', array( $this, 'email_footer' ) );
111
		add_action( 'woocommerce_email_order_details', array( $this, 'order_details' ), 10, 4 );
112
		add_action( 'woocommerce_email_order_details', array( $this, 'order_schema_markup' ), 20, 4 );
113
		add_action( 'woocommerce_email_order_meta', array( $this, 'order_meta' ), 10, 3 );
114
		add_action( 'woocommerce_email_customer_details', array( $this, 'customer_details' ), 10, 3 );
115
		add_action( 'woocommerce_email_customer_details', array( $this, 'email_addresses' ), 20, 3 );
116
117
		// Hooks for sending emails during store events
118
		add_action( 'woocommerce_low_stock_notification', array( $this, 'low_stock' ) );
119
		add_action( 'woocommerce_no_stock_notification', array( $this, 'no_stock' ) );
120
		add_action( 'woocommerce_product_on_backorder_notification', array( $this, 'backorder' ) );
121
		add_action( 'woocommerce_created_customer_notification', array( $this, 'customer_new_account' ), 10, 3 );
122
123
		// Let 3rd parties unhook the above via this hook
124
		do_action( 'woocommerce_email', $this );
125
	}
126
127
	/**
128
	 * Init email classes.
129
	 */
130
	public function init() {
131
		// Include email classes
132
		include_once( 'emails/class-wc-email.php' );
133
134
		$this->emails['WC_Email_New_Order'] 		                 = include( 'emails/class-wc-email-new-order.php' );
135
		$this->emails['WC_Email_Cancelled_Order'] 		             = include( 'emails/class-wc-email-cancelled-order.php' );
136
		$this->emails['WC_Email_Failed_Order'] 		                 = include( 'emails/class-wc-email-failed-order.php' );
137
		$this->emails['WC_Email_Customer_On_Hold_Order'] 		     = include( 'emails/class-wc-email-customer-on-hold-order.php' );
138
		$this->emails['WC_Email_Customer_Processing_Order'] 		 = include( 'emails/class-wc-email-customer-processing-order.php' );
139
		$this->emails['WC_Email_Customer_Completed_Order'] 		     = include( 'emails/class-wc-email-customer-completed-order.php' );
140
		$this->emails['WC_Email_Customer_Refunded_Order'] 		     = include( 'emails/class-wc-email-customer-refunded-order.php' );
141
		$this->emails['WC_Email_Customer_Invoice'] 		             = include( 'emails/class-wc-email-customer-invoice.php' );
142
		$this->emails['WC_Email_Customer_Note'] 		             = include( 'emails/class-wc-email-customer-note.php' );
143
		$this->emails['WC_Email_Customer_Reset_Password'] 		     = include( 'emails/class-wc-email-customer-reset-password.php' );
144
		$this->emails['WC_Email_Customer_New_Account'] 		         = include( 'emails/class-wc-email-customer-new-account.php' );
145
146
		$this->emails = apply_filters( 'woocommerce_email_classes', $this->emails );
147
148
		// include css inliner
149
		if ( ! class_exists( 'Emogrifier' ) && class_exists( 'DOMDocument' ) ) {
150
			include_once( 'libraries/class-emogrifier.php' );
151
		}
152
	}
153
154
	/**
155
	 * Return the email classes - used in admin to load settings.
156
	 *
157
	 * @return array
158
	 */
159
	public function get_emails() {
160
		return $this->emails;
161
	}
162
163
	/**
164
	 * Get from name for email.
165
	 *
166
	 * @return string
167
	 */
168
	public function get_from_name() {
169
		return wp_specialchars_decode( get_option( 'woocommerce_email_from_name' ), ENT_QUOTES );
170
	}
171
172
	/**
173
	 * Get from email address.
174
	 *
175
	 * @return string
176
	 */
177
	public function get_from_address() {
178
		return sanitize_email( get_option( 'woocommerce_email_from_address' ) );
179
	}
180
181
	/**
182
	 * Get the email header.
183
	 *
184
	 * @param mixed $email_heading heading for the email
185
	 */
186
	public function email_header( $email_heading ) {
187
		wc_get_template( 'emails/email-header.php', array( 'email_heading' => $email_heading ) );
188
	}
189
190
	/**
191
	 * Get the email footer.
192
	 */
193
	public function email_footer() {
194
		wc_get_template( 'emails/email-footer.php' );
195
	}
196
197
	/**
198
	 * Wraps a message in the woocommerce mail template.
199
	 *
200
	 * @param mixed $email_heading
201
	 * @param string $message
202
	 * @return string
203
	 */
204
	public function wrap_message( $email_heading, $message, $plain_text = false ) {
0 ignored issues
show
Unused Code introduced by
The parameter $plain_text is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
205
		// Buffer
206
		ob_start();
207
208
		do_action( 'woocommerce_email_header', $email_heading );
209
210
		echo wpautop( wptexturize( $message ) );
211
212
		do_action( 'woocommerce_email_footer' );
213
214
		// Get contents
215
		$message = ob_get_clean();
216
217
		return $message;
218
	}
219
220
	/**
221
	 * Send the email.
222
	 *
223
	 * @param mixed $to
224
	 * @param mixed $subject
225
	 * @param mixed $message
226
	 * @param string $headers (default: "Content-Type: text/html\r\n")
227
	 * @param string $attachments (default: "")
228
	 * @return bool
229
	 */
230
	public function send( $to, $subject, $message, $headers = "Content-Type: text/html\r\n", $attachments = "" ) {
231
		// Send
232
		$email = new WC_Email();
233
		return $email->send( $to, $subject, $message, $headers, $attachments );
234
	}
235
236
	/**
237
	 * Prepare and send the customer invoice email on demand.
238
	 */
239
	public function customer_invoice( $order ) {
240
		$email = $this->emails['WC_Email_Customer_Invoice'];
241
		$email->trigger( $order );
242
	}
243
244
	/**
245
	 * Customer new account welcome email.
246
	 *
247
	 * @param int $customer_id
248
	 * @param array $new_customer_data
249
	 */
250
	public function customer_new_account( $customer_id, $new_customer_data = array(), $password_generated = false ) {
251
		if ( ! $customer_id ) {
252
			return;
253
		}
254
255
		$user_pass = ! empty( $new_customer_data['user_pass'] ) ? $new_customer_data['user_pass'] : '';
256
257
		$email = $this->emails['WC_Email_Customer_New_Account'];
258
		$email->trigger( $customer_id, $user_pass, $password_generated );
259
	}
260
261
	/**
262
	 * Show the order details table
263
	 */
264
	public function order_details( $order, $sent_to_admin = false, $plain_text = false, $email = '' ) {
265
		if ( $plain_text ) {
266
			wc_get_template( 'emails/plain/email-order-details.php', array( 'order' => $order, 'sent_to_admin' => $sent_to_admin, 'plain_text' => $plain_text, 'email' => $email ) );
267
		} else {
268
			wc_get_template( 'emails/email-order-details.php', array( 'order' => $order, 'sent_to_admin' => $sent_to_admin, 'plain_text' => $plain_text, 'email' => $email ) );
269
		}
270
	}
271
272
	/**
273
	 * Adds Schema.org markup for order in JSON-LD format.
274
	 *
275
	 * @since 2.6.0
276
	 * @param mixed $order
277
	 * @param bool $sent_to_admin (default: false)
278
	 * @param bool $plain_text (default: false)
279
	 */
280
	public function order_schema_markup( $order, $sent_to_admin = false, $plain_text = false ) {
281
		if ( $plain_text ) {
282
			return;
283
		}
284
285
		$accepted_offers = array();
286
287
		foreach ( $order->get_items() as $item ) {
288
			if ( ! apply_filters( 'woocommerce_order_item_visible', true, $item ) ) {
289
				continue;
290
			}
291
292
			$product = apply_filters( 'woocommerce_order_item_product', $order->get_product_from_item( $item ), $item );
293
			$is_visible = $product && $product->is_visible();
294
295
			$item_offered = array(
296
				'@type' => 'Product',
297
				'name' => apply_filters( 'woocommerce_order_item_name', $item['name'], $item, $is_visible )
298
			);
299
300
			if ( $sku = $product->get_sku() ) {
301
				$item_offered['sku'] = $sku;
302
			}
303
304
			if ( $is_visible ) {
305
				$item_offered['url'] = get_permalink( $product->get_id() );
306
			} else {
307
				$item_offered['url'] = get_home_url();
308
			}
309
310
			if ( $image_id = $product->get_image_id() ) {
311
				$item_offered['image'] = wp_get_attachment_image_url( $image_id, 'thumbnail' );
312
			}
313
314
			$accepted_offer = (object) array(
315
				'@type'            => 'Offer',
316
				'itemOffered'      => $item_offered,
317
				'price'            => $order->get_line_subtotal( $item ),
318
				'priceCurrency'    => $order->get_order_currency(),
319
				'eligibleQuantity' => (object) array(
320
					'@type' => 'QuantitativeValue',
321
					'value' => apply_filters( 'woocommerce_email_order_item_quantity', $item['qty'], $item )
322
				),
323
				'url'   => get_home_url(),
324
			);
325
326
			$accepted_offers[] = $accepted_offer;
327
		}
328
329
		$markup = array(
330
			'@context' => 'http://schema.org',
331
			'@type'    => 'Order',
332
			'merchant' => (object) array(
333
				'@type' => 'Organization',
334
				'name'  => get_bloginfo( 'name' ),
335
			),
336
			'orderNumber'    => strval( $order->get_order_number() ),
337
			'priceCurrency'  => $order->get_order_currency(),
338
			'price'          => $order->get_total(),
339
			'acceptedOffer'  => count( $accepted_offers ) > 1 ? $accepted_offers : $accepted_offers[0],
340
			'url'            => $order->get_view_order_url(),
341
		);
342
343
		switch ( $order->get_status() ) {
344
			case 'pending':
345
				$markup['orderStatus'] = 'http://schema.org/OrderPaymentDue';
346
				break;
347
			case 'processing':
348
				$markup['orderStatus'] = 'http://schema.org/OrderProcessing';
349
				break;
350
			case 'on-hold':
351
				$markup['orderStatus'] = 'http://schema.org/OrderProblem';
352
				break;
353
			case 'completed':
354
				$markup['orderStatus'] = 'http://schema.org/OrderDelivered';
355
				break;
356
			case 'cancelled':
357
				$markup['orderStatus'] = 'http://schema.org/OrderCancelled';
358
				break;
359
			case 'refunded':
360
				$markup['orderStatus'] = 'http://schema.org/OrderReturned';
361
				break;
362
			case 'failed':
363
				$markup['orderStatus'] = 'http://schema.org/OrderProblem';
364
				break;
365
		}
366
367
		if ( $sent_to_admin ) {
368
			$markup['potentialAction'] = (object) array(
369
				'@type'  => 'ViewAction',
370
				'target' => admin_url( 'post.php?post=' . absint( $order->id ) . '&action=edit' ),
371
			);
372
		}
373
374
		$markup = apply_filters( 'woocommerce_email_order_schema_markup', $markup, $sent_to_admin, $order );
375
376
		echo '<script type="application/ld+json">' . wp_json_encode( (object) $markup ) . '</script>';
377
	}
378
379
	/**
380
	 * Add order meta to email templates.
381
	 *
382
	 * @param mixed $order
383
	 * @param bool $sent_to_admin (default: false)
384
	 * @param bool $plain_text (default: false)
385
	 * @return string
386
	 */
387
	public function order_meta( $order, $sent_to_admin = false, $plain_text = false ) {
388
		$fields = apply_filters( 'woocommerce_email_order_meta_fields', array(), $sent_to_admin, $order );
389
390
		/**
391
		 * Deprecated woocommerce_email_order_meta_keys filter.
392
		 *
393
		 * @since 2.3.0
394
		 */
395
		$_fields = apply_filters( 'woocommerce_email_order_meta_keys', array(), $sent_to_admin );
396
397
		if ( $_fields ) {
398
			foreach ( $_fields as $key => $field ) {
399
				if ( is_numeric( $key ) ) {
400
					$key = $field;
401
				}
402
403
				$fields[ $key ] = array(
404
					'label' => wptexturize( $key ),
405
					'value' => wptexturize( get_post_meta( $order->id, $field, true ) )
406
				);
407
			}
408
		}
409
410
		if ( $fields ) {
411
412
			if ( $plain_text ) {
413
414
				foreach ( $fields as $field ) {
415
					if ( isset( $field['label'] ) && isset( $field['value'] ) && $field['value'] ) {
416
						echo $field['label'] . ': ' . $field['value'] . "\n";
417
					}
418
				}
419
420
			} else {
421
422
				foreach ( $fields as $field ) {
423
					if ( isset( $field['label'] ) && isset( $field['value'] ) && $field['value'] ) {
424
						echo '<p><strong>' . $field['label'] . ':</strong> ' . $field['value'] . '</p>';
425
					}
426
				}
427
			}
428
		}
429
	}
430
431
	/**
432
	 * Is customer detail field valid?
433
	 * @param  array  $field
434
	 * @return boolean
435
	 */
436
	public function customer_detail_field_is_valid( $field ) {
437
		return isset( $field['label'] ) && ! empty( $field['value'] );
438
	}
439
440
	/**
441
	 * Add customer details to email templates.
442
	 *
443
	 * @param mixed $order
444
	 * @param bool $sent_to_admin (default: false)
445
	 * @param bool $plain_text (default: false)
446
	 * @return string
447
	 */
448
	public function customer_details( $order, $sent_to_admin = false, $plain_text = false ) {
449
		$fields = array();
450
451 View Code Duplication
		if ( $order->customer_note ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
452
			$fields['customer_note'] = array(
453
				'label' => __( 'Note', 'woocommerce' ),
454
				'value' => wptexturize( $order->customer_note )
455
			);
456
		}
457
458
		if ( $order->billing_email ) {
459
			$fields['billing_email'] = array(
460
				'label' => __( 'Email', 'woocommerce' ),
461
				'value' => wptexturize( $order->billing_email )
462
			);
463
	    }
464
465 View Code Duplication
	    if ( $order->billing_phone ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
466
			$fields['billing_phone'] = array(
467
				'label' => __( 'Tel', 'woocommerce' ),
468
				'value' => wptexturize( $order->billing_phone )
469
			);
470
	    }
471
472
		$fields = array_filter( apply_filters( 'woocommerce_email_customer_details_fields', $fields, $sent_to_admin, $order ), array( $this, 'customer_detail_field_is_valid' ) );
473
474
		if ( $plain_text ) {
475
			wc_get_template( 'emails/plain/email-customer-details.php', array( 'fields' => $fields ) );
476
		} else {
477
			wc_get_template( 'emails/email-customer-details.php', array( 'fields' => $fields ) );
478
		}
479
	}
480
481
	/**
482
	 * Get the email addresses.
483
	 */
484
	public function email_addresses( $order, $sent_to_admin = false, $plain_text = false ) {
485
		if ( $plain_text ) {
486
			wc_get_template( 'emails/plain/email-addresses.php', array( 'order' => $order ) );
487
		} else {
488
			wc_get_template( 'emails/email-addresses.php', array( 'order' => $order ) );
489
		}
490
	}
491
492
	/**
493
	 * Get blog name formatted for emails.
494
	 * @return string
495
	 */
496
	private function get_blogname() {
497
		return wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES );
498
	}
499
500
	/**
501
	 * Low stock notification email.
502
	 *
503
	 * @param WC_Product $product
504
	 */
505
	public function low_stock( $product ) {
506
		$subject = sprintf( '[%s] %s', $this->get_blogname(), __( 'Product low in stock', 'woocommerce' ) );
507
		$message = sprintf( __( '%s is low in stock.', 'woocommerce' ), html_entity_decode( strip_tags( $product->get_formatted_name() ), ENT_QUOTES, get_bloginfo( 'charset' ) ) ) . ' ' . sprintf( __( 'There are %d left', 'woocommerce' ), html_entity_decode( strip_tags( $product->get_total_stock() ) ) );
508
509
		wp_mail(
510
			apply_filters( 'woocommerce_email_recipient_low_stock', get_option( 'woocommerce_stock_email_recipient' ), $product ),
511
			apply_filters( 'woocommerce_email_subject_low_stock', $subject, $product ),
512
			apply_filters( 'woocommerce_email_content_low_stock', $message, $product ),
513
			apply_filters( 'woocommerce_email_headers', '', 'low_stock', $product ),
514
			apply_filters( 'woocommerce_email_attachments', array(), 'low_stock', $product )
515
		);
516
	}
517
518
	/**
519
	 * No stock notification email.
520
	 *
521
	 * @param WC_Product $product
522
	 */
523
	public function no_stock( $product ) {
524
		$subject = sprintf( '[%s] %s', $this->get_blogname(), __( 'Product out of stock', 'woocommerce' ) );
525
		$message = sprintf( __( '%s is out of stock.', 'woocommerce' ), html_entity_decode( strip_tags( $product->get_formatted_name() ), ENT_QUOTES, get_bloginfo( 'charset' ) ) );
526
527
		wp_mail(
528
			apply_filters( 'woocommerce_email_recipient_no_stock', get_option( 'woocommerce_stock_email_recipient' ), $product ),
529
			apply_filters( 'woocommerce_email_subject_no_stock', $subject, $product ),
530
			apply_filters( 'woocommerce_email_content_no_stock', $message, $product ),
531
			apply_filters( 'woocommerce_email_headers', '', 'no_stock', $product ),
532
			apply_filters( 'woocommerce_email_attachments', array(), 'no_stock', $product )
533
		);
534
	}
535
536
	/**
537
	 * Backorder notification email.
538
	 *
539
	 * @param array $args
540
	 */
541
	public function backorder( $args ) {
542
		$args = wp_parse_args( $args, array(
543
			'product'  => '',
544
			'quantity' => '',
545
			'order_id' => ''
546
		) );
547
548
		extract( $args );
549
550
		if ( ! $product || ! $quantity || ! ( $order = wc_get_order( $order_id ) ) ) {
551
			return;
552
		}
553
554
		$subject = sprintf( '[%s] %s', $this->get_blogname(), __( 'Product Backorder', 'woocommerce' ) );
555
		$message = sprintf( __( '%1$s units of %2$s have been backordered in order #%3$s.', 'woocommerce' ), $quantity, html_entity_decode( strip_tags( $product->get_formatted_name() ), ENT_QUOTES, get_bloginfo( 'charset' ) ), $order->get_order_number() );
556
557
		wp_mail(
558
			apply_filters( 'woocommerce_email_recipient_backorder', get_option( 'woocommerce_stock_email_recipient' ), $args ),
559
			apply_filters( 'woocommerce_email_subject_backorder', $subject, $args ),
560
			apply_filters( 'woocommerce_email_content_backorder', $message, $args ),
561
			apply_filters( 'woocommerce_email_headers', '', 'backorder', $args ),
562
			apply_filters( 'woocommerce_email_attachments', array(), 'backorder', $args )
563
		);
564
	}
565
}
566