class-wc-emails.php 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659
  1. <?php
  2. /**
  3. * Transactional Emails Controller
  4. *
  5. * WooCommerce Emails Class which handles the sending on transactional emails and email templates. This class loads in available emails.
  6. *
  7. * @package WooCommerce/Classes/Emails
  8. * @version 2.3.0
  9. */
  10. defined( 'ABSPATH' ) || exit;
  11. /**
  12. * Emails class.
  13. */
  14. class WC_Emails {
  15. /**
  16. * Array of email notification classes
  17. *
  18. * @var array
  19. */
  20. public $emails = array();
  21. /**
  22. * The single instance of the class
  23. *
  24. * @var WC_Emails
  25. */
  26. protected static $_instance = null;
  27. /**
  28. * Background emailer class.
  29. *
  30. * @var WC_Background_Emailer
  31. */
  32. protected static $background_emailer = null;
  33. /**
  34. * Main WC_Emails Instance.
  35. *
  36. * Ensures only one instance of WC_Emails is loaded or can be loaded.
  37. *
  38. * @since 2.1
  39. * @static
  40. * @return WC_Emails Main instance
  41. */
  42. public static function instance() {
  43. if ( is_null( self::$_instance ) ) {
  44. self::$_instance = new self();
  45. }
  46. return self::$_instance;
  47. }
  48. /**
  49. * Cloning is forbidden.
  50. *
  51. * @since 2.1
  52. */
  53. public function __clone() {
  54. wc_doing_it_wrong( __FUNCTION__, __( 'Cloning is forbidden.', 'woocommerce' ), '2.1' );
  55. }
  56. /**
  57. * Unserializing instances of this class is forbidden.
  58. *
  59. * @since 2.1
  60. */
  61. public function __wakeup() {
  62. wc_doing_it_wrong( __FUNCTION__, __( 'Unserializing instances of this class is forbidden.', 'woocommerce' ), '2.1' );
  63. }
  64. /**
  65. * Hook in all transactional emails.
  66. */
  67. public static function init_transactional_emails() {
  68. $email_actions = apply_filters(
  69. 'woocommerce_email_actions', array(
  70. 'woocommerce_low_stock',
  71. 'woocommerce_no_stock',
  72. 'woocommerce_product_on_backorder',
  73. 'woocommerce_order_status_pending_to_processing',
  74. 'woocommerce_order_status_pending_to_completed',
  75. 'woocommerce_order_status_processing_to_cancelled',
  76. 'woocommerce_order_status_pending_to_failed',
  77. 'woocommerce_order_status_pending_to_on-hold',
  78. 'woocommerce_order_status_failed_to_processing',
  79. 'woocommerce_order_status_failed_to_completed',
  80. 'woocommerce_order_status_failed_to_on-hold',
  81. 'woocommerce_order_status_on-hold_to_processing',
  82. 'woocommerce_order_status_on-hold_to_cancelled',
  83. 'woocommerce_order_status_on-hold_to_failed',
  84. 'woocommerce_order_status_completed',
  85. 'woocommerce_order_fully_refunded',
  86. 'woocommerce_order_partially_refunded',
  87. 'woocommerce_new_customer_note',
  88. 'woocommerce_created_customer',
  89. )
  90. );
  91. if ( apply_filters( 'woocommerce_defer_transactional_emails', false ) ) {
  92. self::$background_emailer = new WC_Background_Emailer();
  93. foreach ( $email_actions as $action ) {
  94. add_action( $action, array( __CLASS__, 'queue_transactional_email' ), 10, 10 );
  95. }
  96. } else {
  97. foreach ( $email_actions as $action ) {
  98. add_action( $action, array( __CLASS__, 'send_transactional_email' ), 10, 10 );
  99. }
  100. }
  101. }
  102. /**
  103. * Queues transactional email so it's not sent in current request if enabled,
  104. * otherwise falls back to send now.
  105. */
  106. public static function queue_transactional_email() {
  107. if ( is_a( self::$background_emailer, 'WC_Background_Emailer' ) ) {
  108. self::$background_emailer->push_to_queue(
  109. array(
  110. 'filter' => current_filter(),
  111. 'args' => func_get_args(),
  112. )
  113. );
  114. } else {
  115. call_user_func_array( array( __CLASS__, 'send_transactional_email' ), func_get_args() );
  116. }
  117. }
  118. /**
  119. * Init the mailer instance and call the notifications for the current filter.
  120. *
  121. * @internal
  122. *
  123. * @param string $filter Filter name.
  124. * @param array $args Email args (default: []).
  125. */
  126. public static function send_queued_transactional_email( $filter = '', $args = array() ) {
  127. if ( apply_filters( 'woocommerce_allow_send_queued_transactional_email', true, $filter, $args ) ) {
  128. self::instance(); // Init self so emails exist.
  129. // Ensure gateways are loaded in case they need to insert data into the emails.
  130. WC()->payment_gateways();
  131. WC()->shipping();
  132. do_action_ref_array( $filter . '_notification', $args );
  133. }
  134. }
  135. /**
  136. * Init the mailer instance and call the notifications for the current filter.
  137. *
  138. * @internal
  139. *
  140. * @param array $args Email args (default: []).
  141. */
  142. public static function send_transactional_email( $args = array() ) {
  143. try {
  144. $args = func_get_args();
  145. self::instance(); // Init self so emails exist.
  146. do_action_ref_array( current_filter() . '_notification', $args );
  147. } catch ( Exception $e ) {
  148. if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
  149. 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
  150. }
  151. }
  152. }
  153. /**
  154. * Constructor for the email class hooks in all emails that can be sent.
  155. */
  156. public function __construct() {
  157. $this->init();
  158. // Email Header, Footer and content hooks.
  159. add_action( 'woocommerce_email_header', array( $this, 'email_header' ) );
  160. add_action( 'woocommerce_email_footer', array( $this, 'email_footer' ) );
  161. add_action( 'woocommerce_email_order_details', array( $this, 'order_downloads' ), 10, 4 );
  162. add_action( 'woocommerce_email_order_details', array( $this, 'order_details' ), 10, 4 );
  163. add_action( 'woocommerce_email_order_meta', array( $this, 'order_meta' ), 10, 3 );
  164. add_action( 'woocommerce_email_customer_details', array( $this, 'customer_details' ), 10, 3 );
  165. add_action( 'woocommerce_email_customer_details', array( $this, 'email_addresses' ), 20, 3 );
  166. // Hooks for sending emails during store events.
  167. add_action( 'woocommerce_low_stock_notification', array( $this, 'low_stock' ) );
  168. add_action( 'woocommerce_no_stock_notification', array( $this, 'no_stock' ) );
  169. add_action( 'woocommerce_product_on_backorder_notification', array( $this, 'backorder' ) );
  170. add_action( 'woocommerce_created_customer_notification', array( $this, 'customer_new_account' ), 10, 3 );
  171. // Hook for replacing {site_title} in email-footer.
  172. add_filter( 'woocommerce_email_footer_text', array( $this, 'email_footer_replace_site_title' ) );
  173. // Let 3rd parties unhook the above via this hook.
  174. do_action( 'woocommerce_email', $this );
  175. }
  176. /**
  177. * Init email classes.
  178. */
  179. public function init() {
  180. // Include email classes.
  181. include_once dirname( __FILE__ ) . '/emails/class-wc-email.php';
  182. $this->emails['WC_Email_New_Order'] = include 'emails/class-wc-email-new-order.php';
  183. $this->emails['WC_Email_Cancelled_Order'] = include 'emails/class-wc-email-cancelled-order.php';
  184. $this->emails['WC_Email_Failed_Order'] = include 'emails/class-wc-email-failed-order.php';
  185. $this->emails['WC_Email_Customer_On_Hold_Order'] = include 'emails/class-wc-email-customer-on-hold-order.php';
  186. $this->emails['WC_Email_Customer_Processing_Order'] = include 'emails/class-wc-email-customer-processing-order.php';
  187. $this->emails['WC_Email_Customer_Completed_Order'] = include 'emails/class-wc-email-customer-completed-order.php';
  188. $this->emails['WC_Email_Customer_Refunded_Order'] = include 'emails/class-wc-email-customer-refunded-order.php';
  189. $this->emails['WC_Email_Customer_Invoice'] = include 'emails/class-wc-email-customer-invoice.php';
  190. $this->emails['WC_Email_Customer_Note'] = include 'emails/class-wc-email-customer-note.php';
  191. $this->emails['WC_Email_Customer_Reset_Password'] = include 'emails/class-wc-email-customer-reset-password.php';
  192. $this->emails['WC_Email_Customer_New_Account'] = include 'emails/class-wc-email-customer-new-account.php';
  193. $this->emails = apply_filters( 'woocommerce_email_classes', $this->emails );
  194. // include css inliner.
  195. if ( ! class_exists( 'Emogrifier' ) && class_exists( 'DOMDocument' ) ) {
  196. include_once dirname( __FILE__ ) . '/libraries/class-emogrifier.php';
  197. }
  198. }
  199. /**
  200. * Return the email classes - used in admin to load settings.
  201. *
  202. * @return array
  203. */
  204. public function get_emails() {
  205. return $this->emails;
  206. }
  207. /**
  208. * Get from name for email.
  209. *
  210. * @return string
  211. */
  212. public function get_from_name() {
  213. return wp_specialchars_decode( get_option( 'woocommerce_email_from_name' ), ENT_QUOTES );
  214. }
  215. /**
  216. * Get from email address.
  217. *
  218. * @return string
  219. */
  220. public function get_from_address() {
  221. return sanitize_email( get_option( 'woocommerce_email_from_address' ) );
  222. }
  223. /**
  224. * Get the email header.
  225. *
  226. * @param mixed $email_heading Heading for the email.
  227. */
  228. public function email_header( $email_heading ) {
  229. wc_get_template( 'emails/email-header.php', array( 'email_heading' => $email_heading ) );
  230. }
  231. /**
  232. * Get the email footer.
  233. */
  234. public function email_footer() {
  235. wc_get_template( 'emails/email-footer.php' );
  236. }
  237. /**
  238. * Filter callback to replace {site_title} in email footer
  239. *
  240. * @since 3.3.0
  241. * @param string $string Email footer text.
  242. * @return string Email footer text with any replacements done.
  243. */
  244. public function email_footer_replace_site_title( $string ) {
  245. return str_replace( '{site_title}', $this->get_blogname(), $string );
  246. }
  247. /**
  248. * Wraps a message in the woocommerce mail template.
  249. *
  250. * @param string $email_heading Heading text.
  251. * @param string $message Email message.
  252. * @param bool $plain_text Set true to send as plain text. Default to false.
  253. *
  254. * @return string
  255. */
  256. public function wrap_message( $email_heading, $message, $plain_text = false ) {
  257. // Buffer.
  258. ob_start();
  259. do_action( 'woocommerce_email_header', $email_heading, null );
  260. echo wpautop( wptexturize( $message ) ); // WPCS: XSS ok.
  261. do_action( 'woocommerce_email_footer', null );
  262. // Get contents.
  263. $message = ob_get_clean();
  264. return $message;
  265. }
  266. /**
  267. * Send the email.
  268. *
  269. * @param mixed $to Receiver.
  270. * @param mixed $subject Email subject.
  271. * @param mixed $message Message.
  272. * @param string $headers Email headers (default: "Content-Type: text/html\r\n").
  273. * @param string $attachments Attachments (default: "").
  274. * @return bool
  275. */
  276. public function send( $to, $subject, $message, $headers = "Content-Type: text/html\r\n", $attachments = '' ) {
  277. // Send.
  278. $email = new WC_Email();
  279. return $email->send( $to, $subject, $message, $headers, $attachments );
  280. }
  281. /**
  282. * Prepare and send the customer invoice email on demand.
  283. *
  284. * @param int|WC_Order $order Order instance or ID.
  285. */
  286. public function customer_invoice( $order ) {
  287. $email = $this->emails['WC_Email_Customer_Invoice'];
  288. if ( ! is_object( $order ) ) {
  289. $order = wc_get_order( absint( $order ) );
  290. }
  291. $email->trigger( $order->get_id(), $order );
  292. }
  293. /**
  294. * Customer new account welcome email.
  295. *
  296. * @param int $customer_id Customer ID.
  297. * @param array $new_customer_data New customer data.
  298. * @param bool $password_generated If password is generated.
  299. */
  300. public function customer_new_account( $customer_id, $new_customer_data = array(), $password_generated = false ) {
  301. if ( ! $customer_id ) {
  302. return;
  303. }
  304. $user_pass = ! empty( $new_customer_data['user_pass'] ) ? $new_customer_data['user_pass'] : '';
  305. $email = $this->emails['WC_Email_Customer_New_Account'];
  306. $email->trigger( $customer_id, $user_pass, $password_generated );
  307. }
  308. /**
  309. * Show the order details table
  310. *
  311. * @param WC_Order $order Order instance.
  312. * @param bool $sent_to_admin If should sent to admin.
  313. * @param bool $plain_text If is plain text email.
  314. * @param string $email Email address.
  315. */
  316. public function order_details( $order, $sent_to_admin = false, $plain_text = false, $email = '' ) {
  317. if ( $plain_text ) {
  318. wc_get_template(
  319. 'emails/plain/email-order-details.php', array(
  320. 'order' => $order,
  321. 'sent_to_admin' => $sent_to_admin,
  322. 'plain_text' => $plain_text,
  323. 'email' => $email,
  324. )
  325. );
  326. } else {
  327. wc_get_template(
  328. 'emails/email-order-details.php', array(
  329. 'order' => $order,
  330. 'sent_to_admin' => $sent_to_admin,
  331. 'plain_text' => $plain_text,
  332. 'email' => $email,
  333. )
  334. );
  335. }
  336. }
  337. /**
  338. * Show order downloads in a table.
  339. *
  340. * @since 3.2.0
  341. * @param WC_Order $order Order instance.
  342. * @param bool $sent_to_admin If should sent to admin.
  343. * @param bool $plain_text If is plain text email.
  344. * @param string $email Email address.
  345. */
  346. public function order_downloads( $order, $sent_to_admin = false, $plain_text = false, $email = '' ) {
  347. $show_downloads = $order->has_downloadable_item() && $order->is_download_permitted() && ! $sent_to_admin;
  348. if ( ! $show_downloads ) {
  349. return;
  350. }
  351. $downloads = $order->get_downloadable_items();
  352. $columns = apply_filters(
  353. 'woocommerce_email_downloads_columns', array(
  354. 'download-product' => __( 'Product', 'woocommerce' ),
  355. 'download-expires' => __( 'Expires', 'woocommerce' ),
  356. 'download-file' => __( 'Download', 'woocommerce' ),
  357. )
  358. );
  359. if ( $plain_text ) {
  360. wc_get_template(
  361. 'emails/plain/email-downloads.php', array(
  362. 'order' => $order,
  363. 'sent_to_admin' => $sent_to_admin,
  364. 'plain_text' => $plain_text,
  365. 'email' => $email,
  366. 'downloads' => $downloads,
  367. 'columns' => $columns,
  368. )
  369. );
  370. } else {
  371. wc_get_template(
  372. 'emails/email-downloads.php', array(
  373. 'order' => $order,
  374. 'sent_to_admin' => $sent_to_admin,
  375. 'plain_text' => $plain_text,
  376. 'email' => $email,
  377. 'downloads' => $downloads,
  378. 'columns' => $columns,
  379. )
  380. );
  381. }
  382. }
  383. /**
  384. * Add order meta to email templates.
  385. *
  386. * @param WC_Order $order Order instance.
  387. * @param bool $sent_to_admin If should sent to admin.
  388. * @param bool $plain_text If is plain text email.
  389. */
  390. public function order_meta( $order, $sent_to_admin = false, $plain_text = false ) {
  391. $fields = apply_filters( 'woocommerce_email_order_meta_fields', array(), $sent_to_admin, $order );
  392. /**
  393. * Deprecated woocommerce_email_order_meta_keys filter.
  394. *
  395. * @since 2.3.0
  396. */
  397. $_fields = apply_filters( 'woocommerce_email_order_meta_keys', array(), $sent_to_admin );
  398. if ( $_fields ) {
  399. foreach ( $_fields as $key => $field ) {
  400. if ( is_numeric( $key ) ) {
  401. $key = $field;
  402. }
  403. $fields[ $key ] = array(
  404. 'label' => wptexturize( $key ),
  405. 'value' => wptexturize( get_post_meta( $order->get_id(), $field, true ) ),
  406. );
  407. }
  408. }
  409. if ( $fields ) {
  410. if ( $plain_text ) {
  411. foreach ( $fields as $field ) {
  412. if ( isset( $field['label'] ) && isset( $field['value'] ) && $field['value'] ) {
  413. echo $field['label'] . ': ' . $field['value'] . "\n"; // WPCS: XSS ok.
  414. }
  415. }
  416. } else {
  417. foreach ( $fields as $field ) {
  418. if ( isset( $field['label'] ) && isset( $field['value'] ) && $field['value'] ) {
  419. echo '<p><strong>' . $field['label'] . ':</strong> ' . $field['value'] . '</p>'; // WPCS: XSS ok.
  420. }
  421. }
  422. }
  423. }
  424. }
  425. /**
  426. * Is customer detail field valid?
  427. *
  428. * @param array $field Field data to check if is valid.
  429. * @return boolean
  430. */
  431. public function customer_detail_field_is_valid( $field ) {
  432. return isset( $field['label'] ) && ! empty( $field['value'] );
  433. }
  434. /**
  435. * Allows developers to add additional customer details to templates.
  436. *
  437. * In versions prior to 3.2 this was used for notes, phone and email but this data has moved.
  438. *
  439. * @param WC_Order $order Order instance.
  440. * @param bool $sent_to_admin If should sent to admin.
  441. * @param bool $plain_text If is plain text email.
  442. */
  443. public function customer_details( $order, $sent_to_admin = false, $plain_text = false ) {
  444. if ( ! is_a( $order, 'WC_Order' ) ) {
  445. return;
  446. }
  447. $fields = array_filter( apply_filters( 'woocommerce_email_customer_details_fields', array(), $sent_to_admin, $order ), array( $this, 'customer_detail_field_is_valid' ) );
  448. if ( ! empty( $fields ) ) {
  449. if ( $plain_text ) {
  450. wc_get_template( 'emails/plain/email-customer-details.php', array( 'fields' => $fields ) );
  451. } else {
  452. wc_get_template( 'emails/email-customer-details.php', array( 'fields' => $fields ) );
  453. }
  454. }
  455. }
  456. /**
  457. * Get the email addresses.
  458. *
  459. * @param WC_Order $order Order instance.
  460. * @param bool $sent_to_admin If should sent to admin.
  461. * @param bool $plain_text If is plain text email.
  462. */
  463. public function email_addresses( $order, $sent_to_admin = false, $plain_text = false ) {
  464. if ( ! is_a( $order, 'WC_Order' ) ) {
  465. return;
  466. }
  467. if ( $plain_text ) {
  468. wc_get_template(
  469. 'emails/plain/email-addresses.php', array(
  470. 'order' => $order,
  471. 'sent_to_admin' => $sent_to_admin,
  472. )
  473. );
  474. } else {
  475. wc_get_template(
  476. 'emails/email-addresses.php', array(
  477. 'order' => $order,
  478. 'sent_to_admin' => $sent_to_admin,
  479. )
  480. );
  481. }
  482. }
  483. /**
  484. * Get blog name formatted for emails.
  485. *
  486. * @return string
  487. */
  488. private function get_blogname() {
  489. return wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES );
  490. }
  491. /**
  492. * Low stock notification email.
  493. *
  494. * @param WC_Product $product Product instance.
  495. */
  496. public function low_stock( $product ) {
  497. if ( 'no' === get_option( 'woocommerce_notify_low_stock', 'yes' ) ) {
  498. return;
  499. }
  500. $subject = sprintf( '[%s] %s', $this->get_blogname(), __( 'Product low in stock', 'woocommerce' ) );
  501. $message = sprintf(
  502. /* translators: 1: product name 2: items in stock */
  503. __( '%1$s is low in stock. There are %2$d left.', 'woocommerce' ),
  504. html_entity_decode( strip_tags( $product->get_formatted_name() ), ENT_QUOTES, get_bloginfo( 'charset' ) ),
  505. html_entity_decode( strip_tags( $product->get_stock_quantity() ) )
  506. );
  507. wp_mail(
  508. apply_filters( 'woocommerce_email_recipient_low_stock', get_option( 'woocommerce_stock_email_recipient' ), $product ),
  509. apply_filters( 'woocommerce_email_subject_low_stock', $subject, $product ),
  510. apply_filters( 'woocommerce_email_content_low_stock', $message, $product ),
  511. apply_filters( 'woocommerce_email_headers', '', 'low_stock', $product ),
  512. apply_filters( 'woocommerce_email_attachments', array(), 'low_stock', $product )
  513. );
  514. }
  515. /**
  516. * No stock notification email.
  517. *
  518. * @param WC_Product $product Product instance.
  519. */
  520. public function no_stock( $product ) {
  521. if ( 'no' === get_option( 'woocommerce_notify_no_stock', 'yes' ) ) {
  522. return;
  523. }
  524. $subject = sprintf( '[%s] %s', $this->get_blogname(), __( 'Product out of stock', 'woocommerce' ) );
  525. /* translators: %s: product name */
  526. $message = sprintf( __( '%s is out of stock.', 'woocommerce' ), html_entity_decode( strip_tags( $product->get_formatted_name() ), ENT_QUOTES, get_bloginfo( 'charset' ) ) );
  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. * Backorder notification email.
  537. *
  538. * @param array $args Arguments.
  539. */
  540. public function backorder( $args ) {
  541. $args = wp_parse_args(
  542. $args, array(
  543. 'product' => '',
  544. 'quantity' => '',
  545. 'order_id' => '',
  546. )
  547. );
  548. $order = wc_get_order( $args['order_id'] );
  549. if (
  550. ! $args['product'] ||
  551. ! is_object( $args['product'] ) ||
  552. ! $args['quantity'] ||
  553. ! $order
  554. ) {
  555. return;
  556. }
  557. $subject = sprintf( '[%s] %s', $this->get_blogname(), __( 'Product backorder', 'woocommerce' ) );
  558. /* translators: 1: product quantity 2: product name 3: order number */
  559. $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() );
  560. wp_mail(
  561. apply_filters( 'woocommerce_email_recipient_backorder', get_option( 'woocommerce_stock_email_recipient' ), $args ),
  562. apply_filters( 'woocommerce_email_subject_backorder', $subject, $args ),
  563. apply_filters( 'woocommerce_email_content_backorder', $message, $args ),
  564. apply_filters( 'woocommerce_email_headers', '', 'backorder', $args ),
  565. apply_filters( 'woocommerce_email_attachments', array(), 'backorder', $args )
  566. );
  567. }
  568. /**
  569. * Adds Schema.org markup for order in JSON-LD format.
  570. *
  571. * @deprecated 3.0.0
  572. * @see WC_Structured_Data::generate_order_data()
  573. *
  574. * @since 2.6.0
  575. * @param WC_Order $order Order instance.
  576. * @param bool $sent_to_admin If should sent to admin.
  577. * @param bool $plain_text If is plain text email.
  578. */
  579. public function order_schema_markup( $order, $sent_to_admin = false, $plain_text = false ) {
  580. wc_deprecated_function( 'WC_Emails::order_schema_markup', '3.0', 'WC_Structured_Data::generate_order_data' );
  581. WC()->structured_data->generate_order_data( $order, $sent_to_admin, $plain_text );
  582. WC()->structured_data->output_structured_data();
  583. }
  584. }