2012-09-17 00:53:17 +00:00
< ? php
/**
* Transactional Emails Controller
*
* WooCommerce Emails Class which handles the sending on transactional emails and email templates . This class loads in available emails .
*
2018-03-22 17:54:16 +00:00
* @ package WooCommerce / Classes / Emails
* @ version 2.3 . 0
*/
defined ( 'ABSPATH' ) || exit ;
/**
* Emails class .
2012-09-17 00:53:17 +00:00
*/
class WC_Emails {
2012-11-27 16:22:47 +00:00
2018-03-22 17:54:16 +00:00
/**
* Array of email notification classes
*
* @ var array
*/
public $emails = array ();
2012-11-27 16:22:47 +00:00
2018-03-22 17:54:16 +00:00
/**
* The single instance of the class
*
* @ var WC_Emails
*/
2013-09-12 13:41:02 +00:00
protected static $_instance = null ;
2017-04-06 12:46:07 +00:00
/**
* Background emailer class .
2018-03-22 17:54:16 +00:00
*
* @ var WC_Background_Emailer
2017-04-06 12:46:07 +00:00
*/
2018-03-22 17:54:16 +00:00
protected static $background_emailer = null ;
2017-04-06 12:46:07 +00:00
2013-09-12 13:41:02 +00:00
/**
2015-11-03 13:31:20 +00:00
* Main WC_Emails Instance .
2013-09-12 13:41:02 +00:00
*
2014-06-19 19:43:05 +00:00
* Ensures only one instance of WC_Emails is loaded or can be loaded .
2013-09-12 13:41:02 +00:00
*
* @ since 2.1
* @ static
2014-06-19 19:43:05 +00:00
* @ return WC_Emails Main instance
2013-09-12 13:41:02 +00:00
*/
public static function instance () {
2014-10-20 15:59:02 +00:00
if ( is_null ( self :: $_instance ) ) {
2013-09-12 13:41:02 +00:00
self :: $_instance = new self ();
2014-10-20 15:59:02 +00:00
}
2013-09-12 13:41:02 +00:00
return self :: $_instance ;
}
/**
* Cloning is forbidden .
*
* @ since 2.1
*/
public function __clone () {
2018-02-07 22:01:12 +00:00
wc_doing_it_wrong ( __FUNCTION__ , __ ( 'Cloning is forbidden.' , 'woocommerce' ), '2.1' );
2013-09-12 13:41:02 +00:00
}
/**
* Unserializing instances of this class is forbidden .
*
* @ since 2.1
*/
public function __wakeup () {
2018-02-07 22:01:12 +00:00
wc_doing_it_wrong ( __FUNCTION__ , __ ( 'Unserializing instances of this class is forbidden.' , 'woocommerce' ), '2.1' );
2013-09-12 13:41:02 +00:00
}
2014-11-26 00:02:41 +00:00
/**
2015-11-03 13:31:20 +00:00
* Hook in all transactional emails .
2014-11-26 00:02:41 +00:00
*/
public static function init_transactional_emails () {
2018-03-22 17:54:16 +00:00
$email_actions = apply_filters (
'woocommerce_email_actions' , array (
'woocommerce_low_stock' ,
'woocommerce_no_stock' ,
'woocommerce_product_on_backorder' ,
'woocommerce_order_status_pending_to_processing' ,
'woocommerce_order_status_pending_to_completed' ,
'woocommerce_order_status_processing_to_cancelled' ,
'woocommerce_order_status_pending_to_failed' ,
'woocommerce_order_status_pending_to_on-hold' ,
'woocommerce_order_status_failed_to_processing' ,
'woocommerce_order_status_failed_to_completed' ,
'woocommerce_order_status_failed_to_on-hold' ,
'woocommerce_order_status_on-hold_to_processing' ,
'woocommerce_order_status_on-hold_to_cancelled' ,
'woocommerce_order_status_on-hold_to_failed' ,
'woocommerce_order_status_completed' ,
'woocommerce_order_fully_refunded' ,
'woocommerce_order_partially_refunded' ,
'woocommerce_new_customer_note' ,
'woocommerce_created_customer' ,
)
);
2014-11-26 00:02:41 +00:00
2017-04-13 13:22:33 +00:00
if ( apply_filters ( 'woocommerce_defer_transactional_emails' , false ) ) {
2017-04-06 12:46:07 +00:00
self :: $background_emailer = new WC_Background_Emailer ();
foreach ( $email_actions as $action ) {
add_action ( $action , array ( __CLASS__ , 'queue_transactional_email' ), 10 , 10 );
}
} else {
foreach ( $email_actions as $action ) {
add_action ( $action , array ( __CLASS__ , 'send_transactional_email' ), 10 , 10 );
}
2014-11-26 00:02:41 +00:00
}
}
2017-02-01 19:08:18 +00:00
/**
2017-04-18 10:35:37 +00:00
* Queues transactional email so it ' s not sent in current request if enabled ,
* otherwise falls back to send now .
2017-02-01 19:08:18 +00:00
*/
public static function queue_transactional_email () {
2017-04-18 10:35:37 +00:00
if ( is_a ( self :: $background_emailer , 'WC_Background_Emailer' ) ) {
2018-03-22 17:54:16 +00:00
self :: $background_emailer -> push_to_queue (
array (
'filter' => current_filter (),
'args' => func_get_args (),
)
);
2017-04-18 10:35:37 +00:00
} else {
call_user_func_array ( array ( __CLASS__ , 'send_transactional_email' ), func_get_args () );
}
2017-02-01 19:08:18 +00:00
}
2014-11-26 00:02:41 +00:00
/**
* Init the mailer instance and call the notifications for the current filter .
2017-02-01 19:08:18 +00:00
*
2017-02-24 20:00:22 +00:00
* @ internal
*
* @ param string $filter Filter name .
2017-02-28 21:16:58 +00:00
* @ param array $args Email args ( default : []) .
2017-02-01 19:08:18 +00:00
*/
2017-02-28 21:16:03 +00:00
public static function send_queued_transactional_email ( $filter = '' , $args = array () ) {
if ( apply_filters ( 'woocommerce_allow_send_queued_transactional_email' , true , $filter , $args ) ) {
2017-02-24 13:16:41 +00:00
self :: instance (); // Init self so emails exist.
2017-04-05 18:50:40 +00:00
// Ensure gateways are loaded in case they need to insert data into the emails.
WC () -> payment_gateways ();
WC () -> shipping ();
2017-02-28 21:16:03 +00:00
do_action_ref_array ( $filter . '_notification' , $args );
2017-02-24 13:16:41 +00:00
}
2017-02-01 19:08:18 +00:00
}
/**
* Init the mailer instance and call the notifications for the current filter .
*
2017-02-24 20:00:22 +00:00
* @ internal
*
* @ param array $args Email args ( default : []) .
2014-11-26 00:02:41 +00:00
*/
2017-02-01 19:08:18 +00:00
public static function send_transactional_email ( $args = array () ) {
2017-04-13 13:22:07 +00:00
try {
$args = func_get_args ();
self :: instance (); // Init self so emails exist.
do_action_ref_array ( current_filter () . '_notification' , $args );
} catch ( Exception $e ) {
if ( defined ( 'WP_DEBUG' ) && WP_DEBUG ) {
2018-03-22 17:54:16 +00:00
trigger_error ( 'Transactional email triggered fatal error for callback ' . current_filter (), E_USER_WARNING ); // phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped, WordPress.PHP.DevelopmentFunctions.error_log_trigger_error
2017-04-13 13:22:07 +00:00
}
}
2014-11-26 00:02:41 +00:00
}
2012-09-17 00:53:17 +00:00
/**
* Constructor for the email class hooks in all emails that can be sent .
*/
2014-10-20 15:59:02 +00:00
public function __construct () {
2013-07-26 14:36:28 +00:00
$this -> init ();
2018-03-22 17:54:16 +00:00
// Email Header, Footer and content hooks.
2013-07-26 14:36:28 +00:00
add_action ( 'woocommerce_email_header' , array ( $this , 'email_header' ) );
add_action ( 'woocommerce_email_footer' , array ( $this , 'email_footer' ) );
2017-07-11 13:52:30 +00:00
add_action ( 'woocommerce_email_order_details' , array ( $this , 'order_downloads' ), 10 , 4 );
2015-11-30 15:16:23 +00:00
add_action ( 'woocommerce_email_order_details' , array ( $this , 'order_details' ), 10 , 4 );
2013-07-26 14:36:28 +00:00
add_action ( 'woocommerce_email_order_meta' , array ( $this , 'order_meta' ), 10 , 3 );
2014-10-08 21:47:50 +00:00
add_action ( 'woocommerce_email_customer_details' , array ( $this , 'customer_details' ), 10 , 3 );
2015-05-06 12:10:06 +00:00
add_action ( 'woocommerce_email_customer_details' , array ( $this , 'email_addresses' ), 20 , 3 );
2013-07-26 14:36:28 +00:00
2018-03-22 17:54:16 +00:00
// Hooks for sending emails during store events.
2013-07-26 14:36:28 +00:00
add_action ( 'woocommerce_low_stock_notification' , array ( $this , 'low_stock' ) );
add_action ( 'woocommerce_no_stock_notification' , array ( $this , 'no_stock' ) );
add_action ( 'woocommerce_product_on_backorder_notification' , array ( $this , 'backorder' ) );
add_action ( 'woocommerce_created_customer_notification' , array ( $this , 'customer_new_account' ), 10 , 3 );
2017-11-01 13:10:25 +00:00
// Hook for replacing {site_title} in email-footer.
2018-03-22 17:54:16 +00:00
add_filter ( 'woocommerce_email_footer_text' , array ( $this , 'email_footer_replace_site_title' ) );
2017-10-28 02:18:53 +00:00
2018-03-22 17:54:16 +00:00
// Let 3rd parties unhook the above via this hook.
2013-07-26 14:36:28 +00:00
do_action ( 'woocommerce_email' , $this );
}
/**
2015-11-03 13:31:20 +00:00
* Init email classes .
2013-07-26 14:36:28 +00:00
*/
2014-10-20 15:59:02 +00:00
public function init () {
2018-03-22 17:54:16 +00:00
// Include email classes.
include_once dirname ( __FILE__ ) . '/emails/class-wc-email.php' ;
$this -> emails [ 'WC_Email_New_Order' ] = include 'emails/class-wc-email-new-order.php' ;
$this -> emails [ 'WC_Email_Cancelled_Order' ] = include 'emails/class-wc-email-cancelled-order.php' ;
$this -> emails [ 'WC_Email_Failed_Order' ] = include 'emails/class-wc-email-failed-order.php' ;
$this -> emails [ 'WC_Email_Customer_On_Hold_Order' ] = include 'emails/class-wc-email-customer-on-hold-order.php' ;
$this -> emails [ 'WC_Email_Customer_Processing_Order' ] = include 'emails/class-wc-email-customer-processing-order.php' ;
$this -> emails [ 'WC_Email_Customer_Completed_Order' ] = include 'emails/class-wc-email-customer-completed-order.php' ;
$this -> emails [ 'WC_Email_Customer_Refunded_Order' ] = include 'emails/class-wc-email-customer-refunded-order.php' ;
$this -> emails [ 'WC_Email_Customer_Invoice' ] = include 'emails/class-wc-email-customer-invoice.php' ;
$this -> emails [ 'WC_Email_Customer_Note' ] = include 'emails/class-wc-email-customer-note.php' ;
$this -> emails [ 'WC_Email_Customer_Reset_Password' ] = include 'emails/class-wc-email-customer-reset-password.php' ;
$this -> emails [ 'WC_Email_Customer_New_Account' ] = include 'emails/class-wc-email-customer-new-account.php' ;
2012-11-27 16:22:47 +00:00
2012-09-17 00:53:17 +00:00
$this -> emails = apply_filters ( 'woocommerce_email_classes' , $this -> emails );
2014-10-08 21:34:31 +00:00
2018-03-22 17:54:16 +00:00
// include css inliner.
2015-02-13 14:16:58 +00:00
if ( ! class_exists ( 'Emogrifier' ) && class_exists ( 'DOMDocument' ) ) {
2018-03-22 17:54:16 +00:00
include_once dirname ( __FILE__ ) . '/libraries/class-emogrifier.php' ;
2014-10-08 21:34:31 +00:00
}
2012-09-17 00:53:17 +00:00
}
2012-11-27 16:22:47 +00:00
2012-09-17 00:53:17 +00:00
/**
* Return the email classes - used in admin to load settings .
2012-11-27 16:22:47 +00:00
*
2012-09-17 00:53:17 +00:00
* @ return array
*/
2014-10-20 15:59:02 +00:00
public function get_emails () {
2012-09-17 00:53:17 +00:00
return $this -> emails ;
}
/**
* Get from name for email .
*
* @ return string
*/
2014-10-20 15:59:02 +00:00
public function get_from_name () {
2015-11-02 09:11:25 +00:00
return wp_specialchars_decode ( get_option ( 'woocommerce_email_from_name' ), ENT_QUOTES );
2012-09-17 00:53:17 +00:00
}
/**
* Get from email address .
*
* @ return string
*/
2014-10-20 15:59:02 +00:00
public function get_from_address () {
2015-11-02 09:11:25 +00:00
return sanitize_email ( get_option ( 'woocommerce_email_from_address' ) );
2012-09-17 00:53:17 +00:00
}
/**
* Get the email header .
*
2018-03-22 17:54:16 +00:00
* @ param mixed $email_heading Heading for the email .
2012-09-17 00:53:17 +00:00
*/
2014-10-20 15:59:02 +00:00
public function email_header ( $email_heading ) {
2013-11-25 12:45:04 +00:00
wc_get_template ( 'emails/email-header.php' , array ( 'email_heading' => $email_heading ) );
2012-09-17 00:53:17 +00:00
}
/**
* Get the email footer .
*/
2014-10-20 15:59:02 +00:00
public function email_footer () {
2013-11-25 12:45:04 +00:00
wc_get_template ( 'emails/email-footer.php' );
2012-09-17 00:53:17 +00:00
}
2017-10-28 02:18:53 +00:00
/**
2017-11-01 13:10:25 +00:00
* Filter callback to replace { site_title } in email footer
*
* @ since 3.3 . 0
* @ param string $string Email footer text .
2017-10-28 02:18:53 +00:00
* @ return string Email footer text with any replacements done .
*/
public function email_footer_replace_site_title ( $string ) {
return str_replace ( '{site_title}' , $this -> get_blogname (), $string );
}
2012-09-17 00:53:17 +00:00
/**
* Wraps a message in the woocommerce mail template .
*
2017-09-26 16:27:50 +00:00
* @ param string $email_heading Heading text .
* @ param string $message Email message .
* @ param bool $plain_text Set true to send as plain text . Default to false .
2017-05-15 11:50:52 +00:00
*
2012-09-17 00:53:17 +00:00
* @ return string
*/
2014-10-20 15:59:02 +00:00
public function wrap_message ( $email_heading , $message , $plain_text = false ) {
2017-09-26 16:27:50 +00:00
// Buffer.
2012-09-17 00:53:17 +00:00
ob_start ();
2017-09-26 16:27:50 +00:00
do_action ( 'woocommerce_email_header' , $email_heading , null );
2012-09-17 00:53:17 +00:00
2018-03-22 17:54:16 +00:00
echo wpautop ( wptexturize ( $message ) ); // WPCS: XSS ok.
2012-09-17 00:53:17 +00:00
2017-09-26 16:27:50 +00:00
do_action ( 'woocommerce_email_footer' , null );
2012-09-17 00:53:17 +00:00
2017-09-26 16:27:50 +00:00
// Get contents.
2012-09-17 00:53:17 +00:00
$message = ob_get_clean ();
return $message ;
}
/**
* Send the email .
*
2018-03-22 17:54:16 +00:00
* @ param mixed $to Receiver .
* @ param mixed $subject Email subject .
* @ param mixed $message Message .
* @ param string $headers Email headers ( default : " Content-Type: text/html \r \n " ) .
* @ param string $attachments Attachments ( default : " " ) .
2015-07-16 15:56:34 +00:00
* @ return bool
2012-09-17 00:53:17 +00:00
*/
2018-03-22 17:54:16 +00:00
public function send ( $to , $subject , $message , $headers = " Content-Type: text/html \r \n " , $attachments = '' ) {
// Send.
2014-09-23 17:02:00 +00:00
$email = new WC_Email ();
2015-07-16 15:56:34 +00:00
return $email -> send ( $to , $subject , $message , $headers , $attachments );
2012-09-17 00:53:17 +00:00
}
2012-11-27 16:22:47 +00:00
2012-09-17 00:53:17 +00:00
/**
* Prepare and send the customer invoice email on demand .
2017-05-15 11:50:52 +00:00
*
2018-03-22 17:54:16 +00:00
* @ param int | WC_Order $order Order instance or ID .
2012-09-17 00:53:17 +00:00
*/
2014-10-20 15:59:02 +00:00
public function customer_invoice ( $order ) {
2012-09-17 00:53:17 +00:00
$email = $this -> emails [ 'WC_Email_Customer_Invoice' ];
2017-02-09 22:49:39 +00:00
if ( ! is_object ( $order ) ) {
$order = wc_get_order ( absint ( $order ) );
}
$email -> trigger ( $order -> get_id (), $order );
2012-09-17 00:53:17 +00:00
}
2012-11-27 16:22:47 +00:00
2012-09-17 00:53:17 +00:00
/**
* Customer new account welcome email .
*
2018-03-22 17:54:16 +00:00
* @ param int $customer_id Customer ID .
* @ param array $new_customer_data New customer data .
* @ param bool $password_generated If password is generated .
2012-09-17 00:53:17 +00:00
*/
2014-10-20 15:59:02 +00:00
public function customer_new_account ( $customer_id , $new_customer_data = array (), $password_generated = false ) {
if ( ! $customer_id ) {
2012-09-17 00:53:17 +00:00
return ;
2014-10-20 15:59:02 +00:00
}
2012-11-27 16:22:47 +00:00
2013-06-04 15:33:05 +00:00
$user_pass = ! empty ( $new_customer_data [ 'user_pass' ] ) ? $new_customer_data [ 'user_pass' ] : '' ;
2012-09-17 00:53:17 +00:00
$email = $this -> emails [ 'WC_Email_Customer_New_Account' ];
2013-06-04 15:33:05 +00:00
$email -> trigger ( $customer_id , $user_pass , $password_generated );
2012-11-27 16:22:47 +00:00
}
2015-11-30 15:16:23 +00:00
/**
* Show the order details table
2017-05-15 11:50:52 +00:00
*
2018-03-22 17:54:16 +00:00
* @ param WC_Order $order Order instance .
* @ param bool $sent_to_admin If should sent to admin .
* @ param bool $plain_text If is plain text email .
* @ param string $email Email address .
2015-11-30 15:16:23 +00:00
*/
public function order_details ( $order , $sent_to_admin = false , $plain_text = false , $email = '' ) {
if ( $plain_text ) {
2018-03-22 17:54:16 +00:00
wc_get_template (
'emails/plain/email-order-details.php' , array (
'order' => $order ,
'sent_to_admin' => $sent_to_admin ,
'plain_text' => $plain_text ,
'email' => $email ,
)
);
2015-11-30 15:16:23 +00:00
} else {
2018-03-22 17:54:16 +00:00
wc_get_template (
'emails/email-order-details.php' , array (
'order' => $order ,
'sent_to_admin' => $sent_to_admin ,
'plain_text' => $plain_text ,
'email' => $email ,
)
);
2015-11-30 15:16:23 +00:00
}
}
2017-07-11 13:52:30 +00:00
/**
* Show order downloads in a table .
*
* @ since 3.2 . 0
2018-03-22 17:54:16 +00:00
* @ param WC_Order $order Order instance .
* @ param bool $sent_to_admin If should sent to admin .
* @ param bool $plain_text If is plain text email .
* @ param string $email Email address .
2017-07-11 13:52:30 +00:00
*/
public function order_downloads ( $order , $sent_to_admin = false , $plain_text = false , $email = '' ) {
2017-11-06 16:59:45 +00:00
$show_downloads = $order -> has_downloadable_item () && $order -> is_download_permitted () && ! $sent_to_admin ;
2017-07-11 13:52:30 +00:00
if ( ! $show_downloads ) {
return ;
}
$downloads = $order -> get_downloadable_items ();
2018-03-22 17:54:16 +00:00
$columns = apply_filters (
'woocommerce_email_downloads_columns' , array (
'download-product' => __ ( 'Product' , 'woocommerce' ),
'download-expires' => __ ( 'Expires' , 'woocommerce' ),
'download-file' => __ ( 'Download' , 'woocommerce' ),
)
);
2017-07-11 13:52:30 +00:00
if ( $plain_text ) {
2018-03-22 17:54:16 +00:00
wc_get_template (
'emails/plain/email-downloads.php' , array (
'order' => $order ,
'sent_to_admin' => $sent_to_admin ,
'plain_text' => $plain_text ,
'email' => $email ,
'downloads' => $downloads ,
'columns' => $columns ,
)
);
2017-07-11 13:52:30 +00:00
} else {
2018-03-22 17:54:16 +00:00
wc_get_template (
'emails/email-downloads.php' , array (
'order' => $order ,
'sent_to_admin' => $sent_to_admin ,
'plain_text' => $plain_text ,
'email' => $email ,
'downloads' => $downloads ,
'columns' => $columns ,
)
);
2017-07-11 13:52:30 +00:00
}
}
2012-09-17 00:53:17 +00:00
/**
* Add order meta to email templates .
2012-11-27 16:22:47 +00:00
*
2018-03-22 17:54:16 +00:00
* @ param WC_Order $order Order instance .
* @ param bool $sent_to_admin If should sent to admin .
* @ param bool $plain_text If is plain text email .
2012-09-17 00:53:17 +00:00
*/
2014-10-20 15:59:02 +00:00
public function order_meta ( $order , $sent_to_admin = false , $plain_text = false ) {
2016-01-08 12:16:55 +00:00
$fields = apply_filters ( 'woocommerce_email_order_meta_fields' , array (), $sent_to_admin , $order );
2014-11-13 00:53:36 +00:00
/**
2015-11-03 13:31:20 +00:00
* Deprecated woocommerce_email_order_meta_keys filter .
2014-11-13 00:53:36 +00:00
*
* @ since 2.3 . 0
*/
$_fields = apply_filters ( 'woocommerce_email_order_meta_keys' , array (), $sent_to_admin );
if ( $_fields ) {
foreach ( $_fields as $key => $field ) {
if ( is_numeric ( $key ) ) {
2013-08-22 11:25:17 +00:00
$key = $field ;
2014-11-13 00:53:36 +00:00
}
2013-08-22 11:25:17 +00:00
2014-11-13 00:53:36 +00:00
$fields [ $key ] = array (
'label' => wptexturize ( $key ),
2016-08-27 01:46:45 +00:00
'value' => wptexturize ( get_post_meta ( $order -> get_id (), $field , true ) ),
2014-11-13 00:53:36 +00:00
);
2012-09-17 00:53:17 +00:00
}
2014-10-20 15:59:02 +00:00
}
2012-09-17 00:53:17 +00:00
2014-11-13 00:53:36 +00:00
if ( $fields ) {
2012-11-27 16:22:47 +00:00
2012-09-17 00:53:17 +00:00
if ( $plain_text ) {
2012-11-27 16:22:47 +00:00
2014-11-13 00:53:36 +00:00
foreach ( $fields as $field ) {
if ( isset ( $field [ 'label' ] ) && isset ( $field [ 'value' ] ) && $field [ 'value' ] ) {
2018-03-22 17:54:16 +00:00
echo $field [ 'label' ] . ': ' . $field [ 'value' ] . " \n " ; // WPCS: XSS ok.
2014-04-15 15:01:20 +00:00
}
}
2012-09-17 00:53:17 +00:00
} else {
2014-11-13 00:53:36 +00:00
foreach ( $fields as $field ) {
if ( isset ( $field [ 'label' ] ) && isset ( $field [ 'value' ] ) && $field [ 'value' ] ) {
2018-03-22 17:54:16 +00:00
echo '<p><strong>' . $field [ 'label' ] . ':</strong> ' . $field [ 'value' ] . '</p>' ; // WPCS: XSS ok.
2014-04-15 15:01:20 +00:00
}
}
2012-09-17 00:53:17 +00:00
}
}
}
2015-11-02 10:41:05 +00:00
/**
* Is customer detail field valid ?
2018-03-22 17:54:16 +00:00
*
* @ param array $field Field data to check if is valid .
2015-11-02 10:41:05 +00:00
* @ return boolean
*/
public function customer_detail_field_is_valid ( $field ) {
return isset ( $field [ 'label' ] ) && ! empty ( $field [ 'value' ] );
}
2014-10-08 21:47:50 +00:00
/**
2017-07-11 13:52:30 +00:00
* Allows developers to add additional customer details to templates .
*
* In versions prior to 3.2 this was used for notes , phone and email but this data has moved .
2014-10-08 21:47:50 +00:00
*
2018-03-22 17:54:16 +00:00
* @ param WC_Order $order Order instance .
* @ param bool $sent_to_admin If should sent to admin .
* @ param bool $plain_text If is plain text email .
2014-10-08 21:47:50 +00:00
*/
2014-11-26 00:02:41 +00:00
public function customer_details ( $order , $sent_to_admin = false , $plain_text = false ) {
2017-02-28 20:35:52 +00:00
if ( ! is_a ( $order , 'WC_Order' ) ) {
2017-02-27 17:08:13 +00:00
return ;
}
2014-10-08 21:47:50 +00:00
2017-07-11 13:52:30 +00:00
$fields = array_filter ( apply_filters ( 'woocommerce_email_customer_details_fields' , array (), $sent_to_admin , $order ), array ( $this , 'customer_detail_field_is_valid' ) );
2014-11-12 19:44:11 +00:00
2017-07-11 13:52:30 +00:00
if ( ! empty ( $fields ) ) {
if ( $plain_text ) {
wc_get_template ( 'emails/plain/email-customer-details.php' , array ( 'fields' => $fields ) );
} else {
wc_get_template ( 'emails/email-customer-details.php' , array ( 'fields' => $fields ) );
}
2014-10-08 21:47:50 +00:00
}
}
/**
* Get the email addresses .
2017-05-15 11:50:52 +00:00
*
2018-03-22 17:54:16 +00:00
* @ param WC_Order $order Order instance .
* @ param bool $sent_to_admin If should sent to admin .
* @ param bool $plain_text If is plain text email .
2014-10-08 21:47:50 +00:00
*/
2014-11-26 00:02:41 +00:00
public function email_addresses ( $order , $sent_to_admin = false , $plain_text = false ) {
2017-02-28 20:35:52 +00:00
if ( ! is_a ( $order , 'WC_Order' ) ) {
2017-02-27 17:08:13 +00:00
return ;
}
2015-02-19 13:57:20 +00:00
if ( $plain_text ) {
2018-03-22 17:54:16 +00:00
wc_get_template (
'emails/plain/email-addresses.php' , array (
'order' => $order ,
'sent_to_admin' => $sent_to_admin ,
)
);
2015-02-19 13:57:20 +00:00
} else {
2018-03-22 17:54:16 +00:00
wc_get_template (
'emails/email-addresses.php' , array (
'order' => $order ,
'sent_to_admin' => $sent_to_admin ,
)
);
2015-02-19 13:57:20 +00:00
}
2014-11-13 00:33:47 +00:00
}
2014-11-12 23:32:15 +00:00
2014-10-20 15:59:02 +00:00
/**
2015-11-03 13:31:20 +00:00
* Get blog name formatted for emails .
2018-03-22 17:54:16 +00:00
*
2014-10-20 15:59:02 +00:00
* @ return string
*/
private function get_blogname () {
return wp_specialchars_decode ( get_option ( 'blogname' ), ENT_QUOTES );
}
2012-09-17 00:53:17 +00:00
/**
* Low stock notification email .
*
2018-03-22 17:54:16 +00:00
* @ param WC_Product $product Product instance .
2012-09-17 00:53:17 +00:00
*/
2014-10-20 15:59:02 +00:00
public function low_stock ( $product ) {
2017-04-12 17:01:59 +00:00
if ( 'no' === get_option ( 'woocommerce_notify_low_stock' , 'yes' ) ) {
return ;
}
2014-10-20 15:59:02 +00:00
$subject = sprintf ( '[%s] %s' , $this -> get_blogname (), __ ( 'Product low in stock' , 'woocommerce' ) );
2016-10-29 12:57:09 +00:00
$message = sprintf (
2018-03-22 17:54:16 +00:00
/* translators: 1: product name 2: items in stock */
2016-10-29 13:13:46 +00:00
__ ( '%1$s is low in stock. There are %2$d left.' , 'woocommerce' ),
2016-10-29 12:57:09 +00:00
html_entity_decode ( strip_tags ( $product -> get_formatted_name () ), ENT_QUOTES , get_bloginfo ( 'charset' ) ),
WIP - Product CRUD (#12065)
* Created function to get the catalog visibility options
* First methods for WP_Product crud
* Product set methods
* Fixed several erros while setting data
* First methods for WP_Product crud
* Product set methods
* Fixed several erros while setting data
* Hardcode the get_type per product class
* Initial look through getters and setters and abstract data
* Missing var
* Add related product functions and deprecate those in class.
* No need to exclude ID
* Fixed coding standards and improved the docblocks
* Get cached terms from wc_get_related_terms()
* Fixed wrong variable in wc_get_related_terms
* Use count() instead of sizeof()
* Sanitize ids later
* Remove unneeded comments
* wc_get_product_term_ids instead of related wording and use in other places.
get_the_terms is used here and also handles caching, something
wp_get_post_terms does not.
* Clean up the abstract product class a bit, deprecate two functions we have renamed, make update & create work properly, and add some tests for it.
* Bump template version
* Handle PR feedback: Remove duplicate regular_price update, allow changing of post status for products, remove deprecation for get_title since we might still offer it as a function
* Made abstract function useful
* External Product CRUD
* _virtual meta should be 'no', not taxable, in product unit test helper
* Grouped product class
* Tests
* Move children to meta and update test
* Use get_upsell_ids
* Spacing in query
* Moving and refactoring methods
* Availability html
* Tidy/add todos
* Rename method
* Put back review functions (still todo)
* missing $this
* get_price_including_tax/excluding_tax functions
* wc_get_price_to_display
* Price handling
* [Product CRUD] Variable (#12146)
* [Product CRUD] Variable Products
* Handle PR feedback.
* [Product CRUD] Grouped Handling (#12151)
* Handle grouped product saving
* Update routine
* [Product CRUD] Product crud terms (#12149)
* Category and tag id handling
* Replace template functions
* Remove todo
* Handle default name in save function
* Product crud admin save routine (#12174)
* Initial props
* Work on admin saving
* Set/get attributes
* Atom was moaning about this before but no longer.
* Update get_shipping_class
* WC_Product_Attribute
* Use getter in admin panel
* Fix attribute saving
* Spacing
* Fix comment
* wc_implode_text_attributes helper function
* [Product CRUD] Product crud admin use getters (#12196)
* Initial props
* Work on admin saving
* Set/get attributes
* Atom was moaning about this before but no longer.
* Update get_shipping_class
* WC_Product_Attribute
* Use getter in admin panel
* Fix attribute saving
* Move settings into new files
* Refactor panels and use getters
* Use getters for variation panel
* Revert save variation changes for now
* Add todos
* Fix downloads
* REST API CRUD Updates
* Additional API updates/fixes. Added some todos
* Fix final failing tests and implementing setters/getters and attributes functionality.
* Fix comparison for is_on_sale and remove download_type from WC_Product.
* Add a wc_get_products wrapper.
* Remove the download type input from the product data metabox for downloadable products. (#12221)
* [Product CRUD] Variations - setters, getters and admin. (#12228)
* Started on variation changes
* Stock functions
* Variation class
* Bulk change ->id to get_id() to fix variation form display
* Missing status
* Fix add to cart
* Start on stored data save
* save variation
* Save_variations
* Variation edit panel
* Save variations code works.
* Remove stored data code and fix save
* Improve legacy class
* wc_bool_to_string
* prepare_set_attributes
* Use wc_get_products
* More feedback fixes
* Feedback fixes
* Implement CRUD in the legacy REST API
* Handle PR feedback
* [Product CRUD] Getter setter proxy methods (#12236)
* Started on variation changes
* Stock functions
* Variation class
* Bulk change ->id to get_id() to fix variation form display
* Missing status
* Fix add to cart
* Start on stored data save
* save variation
* Save_variations
* Variation edit panel
* Save variations code works.
* Remove stored data code and fix save
* Improve legacy class
* wc_bool_to_string
* prepare_set_attributes
* Use wc_get_products
* More feedback fixes
* get_prop implementation in abstract and data classes
* Implement set_prop
* Change handling
* Array key exists
* set_object_read
* Use get_the_terms() instead of wp_get_post_terms()
wp_get_post_terms() is a wrapper around wp_get_object_terms() which does not
use the object cache, and generates a database query every time it is used.
get_the_terms() however can use data from the object cache if present.
* Allow WP_Query to preload post data, and meta in wc_get_products()
Allow WP_Query to bulk query for post data and meta if more than
just IDs are requested from wc_get_products(). Reduces query count
significantly.
* [Product CRUD] Variable, variation, notices, and stock handling (#12277)
* No longer needed
* Remove old todos
* Use getters in admin list
* Related and upsells update for CRUD
* Fix notice in gallery
* Variable fixes and todos
* Context
* Price sync
* Revert variation attributes change
* Return parent data in view context
* Defer term counting
* wc_find_matching_product_variation
* Stock manage tweaks
* Stock fixes
* Correct id
* correct id
* Better sync
* Data logic setter fix
* feedback
* First methods for WP_Product crud
* Product set methods
* Fixed several erros while setting data
* Hardcode the get_type per product class
* Initial look through getters and setters and abstract data
* Missing var
* Fixed coding standards and improved the docblocks
* Get cached terms from wc_get_related_terms()
* Fixed wrong variable in wc_get_related_terms
* Use count() instead of sizeof()
* Add related product functions and deprecate those in class.
* No need to exclude ID
* Sanitize ids later
* Clean up the abstract product class a bit, deprecate two functions we have renamed, make update & create work properly, and add some tests for it.
* Remove unneeded comments
* wc_get_product_term_ids instead of related wording and use in other places.
get_the_terms is used here and also handles caching, something
wp_get_post_terms does not.
* Handle PR feedback: Remove duplicate regular_price update, allow changing of post status for products, remove deprecation for get_title since we might still offer it as a function
* External Product CRUD
* _virtual meta should be 'no', not taxable, in product unit test helper
* Bump template version
* Made abstract function useful
* Grouped product class
* Tests
* Move children to meta and update test
* Use get_upsell_ids
* Spacing in query
* Moving and refactoring methods
* Availability html
* Tidy/add todos
* Rename method
* Put back review functions (still todo)
* missing $this
* get_price_including_tax/excluding_tax functions
* wc_get_price_to_display
* Price handling
* [Product CRUD] Variable (#12146)
* [Product CRUD] Variable Products
* Handle PR feedback.
* [Product CRUD] Grouped Handling (#12151)
* Handle grouped product saving
* Update routine
* [Product CRUD] Product crud terms (#12149)
* Category and tag id handling
* Replace template functions
* Remove todo
* Handle default name in save function
* Product crud admin save routine (#12174)
* Initial props
* Work on admin saving
* Set/get attributes
* Atom was moaning about this before but no longer.
* Update get_shipping_class
* WC_Product_Attribute
* Use getter in admin panel
* Fix attribute saving
* Spacing
* Fix comment
* wc_implode_text_attributes helper function
* [Product CRUD] Product crud admin use getters (#12196)
* Initial props
* Work on admin saving
* Set/get attributes
* Atom was moaning about this before but no longer.
* Update get_shipping_class
* WC_Product_Attribute
* Use getter in admin panel
* Fix attribute saving
* Move settings into new files
* Refactor panels and use getters
* Use getters for variation panel
* Revert save variation changes for now
* Add todos
* Fix downloads
* REST API CRUD Updates
* Additional API updates/fixes. Added some todos
* Fix final failing tests and implementing setters/getters and attributes functionality.
* Fix comparison for is_on_sale and remove download_type from WC_Product.
* Add a wc_get_products wrapper.
* Remove the download type input from the product data metabox for downloadable products. (#12221)
* [Product CRUD] Variations - setters, getters and admin. (#12228)
* Started on variation changes
* Stock functions
* Variation class
* Bulk change ->id to get_id() to fix variation form display
* Missing status
* Fix add to cart
* Start on stored data save
* save variation
* Save_variations
* Variation edit panel
* Save variations code works.
* Remove stored data code and fix save
* Improve legacy class
* wc_bool_to_string
* prepare_set_attributes
* Use wc_get_products
* More feedback fixes
* Feedback fixes
* Implement CRUD in the legacy REST API
* Handle PR feedback
* [Product CRUD] Getter setter proxy methods (#12236)
* Started on variation changes
* Stock functions
* Variation class
* Bulk change ->id to get_id() to fix variation form display
* Missing status
* Fix add to cart
* Start on stored data save
* save variation
* Save_variations
* Variation edit panel
* Save variations code works.
* Remove stored data code and fix save
* Improve legacy class
* wc_bool_to_string
* prepare_set_attributes
* Use wc_get_products
* More feedback fixes
* get_prop implementation in abstract and data classes
* Implement set_prop
* Change handling
* Array key exists
* set_object_read
* Use get_the_terms() instead of wp_get_post_terms()
wp_get_post_terms() is a wrapper around wp_get_object_terms() which does not
use the object cache, and generates a database query every time it is used.
get_the_terms() however can use data from the object cache if present.
* [Product CRUD] Variable, variation, notices, and stock handling (#12277)
* No longer needed
* Remove old todos
* Use getters in admin list
* Related and upsells update for CRUD
* Fix notice in gallery
* Variable fixes and todos
* Context
* Price sync
* Revert variation attributes change
* Return parent data in view context
* Defer term counting
* wc_find_matching_product_variation
* Stock manage tweaks
* Stock fixes
* Correct id
* correct id
* Better sync
* Data logic setter fix
* feedback
* Prevent notices
* Handle image_id from parent
* Fix error
* Remove _wc_save_product_price
* Remove todo
* Fixed wrong variation URLs
* Fixed undefined $image_id in WC_Product_Variation::get_image_id()
* Allow wc_rest_prepare_date_response() handle timestamps
* Updated get methods on REST API for variations
* Use variations CRUD to save variations metadata
* [Product CRUD] Abstract todos (#12305)
* Get dimensions and weights, with soft deprecation
* Product attributes
* Ratings
* Fix read method
* Downloads
* Feedback
* Revert "[Product CRUD] Abstract todos (#12305)"
This reverts commit 9a6136fcf88fec16f97457b7c8a4388f7587bfa2.
* Remove deprecated get_variation_id()
* New default attributes method
* [Product CRUD] Product Datastore (#12317)
* Fix up tests in the product/* folder.
* Handle data store updates for grouped, variable, external, simple, and general data store updates for products.
* Variations & variable changes.
* Update -functions.php calls to use data store.
* Add an interface for the public product data store methods.
* Finished product factory tests
* Correctly delete in the api, fix up some comments, and implement an interface for the public variable methods.
* Fix up delete in all versions of the api
* Handle feedback
* Match protected decloration to parent
* Product crud abstract todos (#12316)
* Get dimensions and weights, with soft deprecation
* Product attributes
* Ratings
* Fix read method
* Downloads
* Feedback
* Fix up store
* Fixed method returning in write context
* Fix error in variation admin
* Check for parent value - fixes tax class
* Remove old/complete todos
* Allow set tax class as "parent"
* Removed duplicated sync
* Fixed wrong variation URLs
* Fixed undefined $image_id in WC_Product_Variation::get_image_id()
* Allow wc_rest_prepare_date_response() handle timestamps
* Updated get methods on REST API for variations
* Use variations CRUD to save variations metadata
* Remove deprecated get_variation_id()
* New default attributes method
* Fixed method returning in write context
* Allow set tax class as "parent"
* Removed duplicated sync
* Fixed coding standards
* TODO is not accurate.
* Should pass WC_Product instancies to WC_Comments methods (#12327)
* Use new method in abstract order class to prevent headers sent issue in tests
* Fixed variable description in REST API
* Updated how create initial product variation
* Fixed a few fatal errors and warnings in Products CRUD (#12329)
* Fixed a few fatal errors and warnings in Products CRUD
* Fixed sync functions
* Add variations CRUD to legacy API (#12331)
* Apply crud to variable products in legacy API v1
* New REST API do not need fallback for default attributes
* Apply variations CRUD to legacy API v2
* Legacy v2 - save default attributes
* Variations in legacy API v2 do not have descriptions
* Fixed legacy API v2 variations params
* Applied variations CRUD to legacy API v3
* Sync before save in legacy apis
* Punc
* Removed API todos
* Removed test
* Products endpoint tweaks (#12354)
* Var type already normalized on CRUD
* Let Product CRUD handle with validation, sanitization and conditional checks
* Set downloads using WC_Product_Download
* Stop try catch exceptions more than one time
* Handle WC_Data_Exception in legacy API
* Complete remove products when fails on creating
* On creating I mean!
* Already have a method to complete delete products
* Fixed standards using WP CodeSniffer
* get_the_terms() returns false when empty
* get_manage_stock returns boolean
@claudiosanches
* Merge conflict
* Variations API endpoint fixes
* Product CRUD improvements (#12359)
* args is not used any more - remove todo
* Added test for attributes
* wc_get_price_excluding_tax usage
* parent usage
* Fix rating counts
* Test fixes
* Cleanup after tests
* Make sure status transition code runs even during API calls, not just in admin.
* Default visibility
* Fix attribute setting in API
* Use get name instead of get title
* variation id usage
* Improved cross sell templates
* variation_data
* Grouped product sync
* Notices
* Sync is not needed in API
* Delete
* Rename interfaces
* Update counts in data store
2016-11-16 12:38:24 +00:00
html_entity_decode ( strip_tags ( $product -> get_stock_quantity () ) )
2016-10-29 12:57:09 +00:00
);
2014-10-20 15:59:02 +00:00
wp_mail (
apply_filters ( 'woocommerce_email_recipient_low_stock' , get_option ( 'woocommerce_stock_email_recipient' ), $product ),
apply_filters ( 'woocommerce_email_subject_low_stock' , $subject , $product ),
apply_filters ( 'woocommerce_email_content_low_stock' , $message , $product ),
apply_filters ( 'woocommerce_email_headers' , '' , 'low_stock' , $product ),
apply_filters ( 'woocommerce_email_attachments' , array (), 'low_stock' , $product )
);
2012-09-17 00:53:17 +00:00
}
/**
* No stock notification email .
*
2018-03-22 17:54:16 +00:00
* @ param WC_Product $product Product instance .
2012-09-17 00:53:17 +00:00
*/
2014-10-20 15:59:02 +00:00
public function no_stock ( $product ) {
2017-04-12 17:01:59 +00:00
if ( 'no' === get_option ( 'woocommerce_notify_no_stock' , 'yes' ) ) {
return ;
}
2014-10-20 15:59:02 +00:00
$subject = sprintf ( '[%s] %s' , $this -> get_blogname (), __ ( 'Product out of stock' , 'woocommerce' ) );
2016-10-29 12:57:09 +00:00
/* translators: %s: product name */
2015-08-31 11:29:34 +00:00
$message = sprintf ( __ ( '%s is out of stock.' , 'woocommerce' ), html_entity_decode ( strip_tags ( $product -> get_formatted_name () ), ENT_QUOTES , get_bloginfo ( 'charset' ) ) );
2014-10-20 15:59:02 +00:00
wp_mail (
apply_filters ( 'woocommerce_email_recipient_no_stock' , get_option ( 'woocommerce_stock_email_recipient' ), $product ),
apply_filters ( 'woocommerce_email_subject_no_stock' , $subject , $product ),
apply_filters ( 'woocommerce_email_content_no_stock' , $message , $product ),
apply_filters ( 'woocommerce_email_headers' , '' , 'no_stock' , $product ),
apply_filters ( 'woocommerce_email_attachments' , array (), 'no_stock' , $product )
);
2012-09-17 00:53:17 +00:00
}
/**
* Backorder notification email .
*
2018-03-22 17:54:16 +00:00
* @ param array $args Arguments .
2012-09-17 00:53:17 +00:00
*/
2014-10-20 15:59:02 +00:00
public function backorder ( $args ) {
2018-03-22 17:54:16 +00:00
$args = wp_parse_args (
$args , array (
'product' => '' ,
'quantity' => '' ,
'order_id' => '' ,
)
);
2012-09-17 00:53:17 +00:00
2017-11-17 11:38:26 +00:00
$order = wc_get_order ( $args [ 'order_id' ] );
if (
! $args [ 'product' ] ||
! is_object ( $args [ 'product' ] ) ||
! $args [ 'quantity' ] ||
! $order
) {
2014-10-20 15:59:02 +00:00
return ;
}
2012-09-17 00:53:17 +00:00
2016-10-12 10:16:30 +00:00
$subject = sprintf ( '[%s] %s' , $this -> get_blogname (), __ ( 'Product backorder' , 'woocommerce' ) );
2018-03-22 17:54:16 +00:00
/* translators: 1: product quantity 2: product name 3: order number */
2017-11-17 11:38:26 +00:00
$message = sprintf ( __ ( '%1$s units of %2$s have been backordered in order #%3$s.' , 'woocommerce' ), $args [ 'quantity' ], html_entity_decode ( strip_tags ( $args [ 'product' ] -> get_formatted_name () ), ENT_QUOTES , get_bloginfo ( 'charset' ) ), $order -> get_order_number () );
2018-03-22 17:54:16 +00:00
2014-10-20 15:59:02 +00:00
wp_mail (
apply_filters ( 'woocommerce_email_recipient_backorder' , get_option ( 'woocommerce_stock_email_recipient' ), $args ),
apply_filters ( 'woocommerce_email_subject_backorder' , $subject , $args ),
apply_filters ( 'woocommerce_email_content_backorder' , $message , $args ),
apply_filters ( 'woocommerce_email_headers' , '' , 'backorder' , $args ),
apply_filters ( 'woocommerce_email_attachments' , array (), 'backorder' , $args )
);
2012-09-17 00:53:17 +00:00
}
2016-08-10 22:23:26 +00:00
/**
* Adds Schema . org markup for order in JSON - LD format .
*
2017-03-15 16:36:53 +00:00
* @ deprecated 3.0 . 0
2016-08-14 22:39:01 +00:00
* @ see WC_Structured_Data :: generate_order_data ()
2016-08-11 09:17:14 +00:00
*
2016-08-10 22:23:26 +00:00
* @ since 2.6 . 0
2018-03-22 17:54:16 +00:00
* @ param WC_Order $order Order instance .
* @ param bool $sent_to_admin If should sent to admin .
* @ param bool $plain_text If is plain text email .
2016-08-10 22:23:26 +00:00
*/
public function order_schema_markup ( $order , $sent_to_admin = false , $plain_text = false ) {
2017-03-15 16:36:53 +00:00
wc_deprecated_function ( 'WC_Emails::order_schema_markup' , '3.0' , 'WC_Structured_Data::generate_order_data' );
2016-08-10 22:23:26 +00:00
2016-10-13 21:19:13 +00:00
WC () -> structured_data -> generate_order_data ( $order , $sent_to_admin , $plain_text );
2016-10-13 22:39:27 +00:00
WC () -> structured_data -> output_structured_data ();
2016-08-11 09:17:14 +00:00
}
2013-05-27 14:20:01 +00:00
}