Targeting Specific Email with the Email Id in Woocommerce

Targeting specific email with the email id in Woocommerce

The wc_order_email class or function doesn't exist in WooCommerce, so I have updated your question.

What you are looking at is $email variable argument (the WC_Email current type object). It's mostly defined everywhere in templates and hooks.

To get the usable current Email ID as a variable you will simply use $email_id = $email->id

To get the current Email ID of your custom emails, you should use this code (just for testing):

add_action( 'woocommerce_email_order_details', 'get_the_wc_email_id', 9, 4 );
function get_the_wc_email_id( $order, $sent_to_admin, $plain_text, $email ) {
// Will output the email id for the current notification
echo '<pre>'; print_r($email->id); echo '</pre>';
}

Code goes in function.php file of your active child theme (or theme) or also in any plugin file.

You will get the following:

  • new_order
  • customer_on_hold_order
  • customer_processing_order
  • customer_completed_order
  • customer_refunded_order
  • customer_partially_refunded_order
  • cancelled_order
  • failed_order
  • customer_reset_password
  • customer_invoice
  • customer_new_account
  • customer_note

Once you get the correct email ID slug for your custom email notification you can use it on any following hook (instead of overriding email templates):

woocommerce_email_header (2 arguments: $email_heading, $email)
woocommerce_email_order_details (4 arguments: $order, $sent_to_admin, $plain_text, $email)
woocommerce_email_order_meta (4 arguments: $order, $sent_to_admin, $plain_text, $email)
woocommerce_email_customer_details (4 arguments: $order, $sent_to_admin, $plain_text, $email)
woocommerce_email_footer (1 argument: $email)

HERE an example of code where I target "New order" email notifications only:

add_action( 'woocommerce_email_order_details', 'add_custom_text_to_new_order_email', 10, 4 );
function add_custom_text_to_new_order_email( $order, $sent_to_admin, $plain_text, $email ) {
// Only for "New Order" email notifications (to be replaced by yours)
if( ! ( 'new_order' == $email->id ) ) return;

// Display a custom text (for example)
echo '<p>'.__('My custom text').'</p>';
}

Code goes in function.php file of your active child theme (or theme) or also in any plugin file.

Tested and works.

Target specific WooCommerce email notifications when using the woocommerce_order_item_meta_start hook

As you can see in your code attempt, $email is not part of the woocommerce_order_item_meta_start hook. So to target certain WooCommerce email notifications, you will need a workaround.

Step 1) creating and adding a global variable, via another hook that only applies to WooCommerce email notifications.

// Setting global variable
function action_woocommerce_email_before_order_table( $order, $sent_to_admin, $plain_text, $email ) {
$GLOBALS['email_id'] = $email->id;
}
add_action( 'woocommerce_email_before_order_table', 'action_woocommerce_email_before_order_table', 1, 4 );

Step 2) In the hook woocommerce_order_item_meta_start, use the global variable so we can target certain WooCommerce email notifications

function action_woocommerce_order_item_meta_start( $item_id, $item, $order, $plain_text ) {
// On email notifications for line items
if ( ! is_wc_endpoint_url() && $item->is_type('line_item') ) {
// Getting the email ID global variable
$ref_name_globals_var = isset( $GLOBALS ) ? $GLOBALS : '';
$email_id = isset( $ref_name_globals_var['email_id'] ) ? $ref_name_globals_var['email_id'] : '';

// NOT empty and targeting specific email. Multiple statuses can be added, separated by a comma
if ( ! empty ( $email_id ) && in_array( $email_id, array( 'new_order', 'customer_completed_order' ) ) ) {
// Get meta
$ot_address = get_post_meta( $item->get_product_id(), 'ot_address', true );

// OR use to get meta
// $ot_address = $item->get_meta( 'ot_address' );

if ( ! empty( $ot_address ) ) {
printf( '<div>' . __( 'Terms: %s', 'woocommerce' ) . '</div>', $ot_address );
}
}
}
}
add_action( 'woocommerce_order_item_meta_start', 'action_woocommerce_order_item_meta_start', 10, 4 );

How to get the Woocommerce Current email id (like admin_new_order, customer_processing_order) inside the email template file

Techno Deviser's comment is correct.

Inside email-order-details.php you have a few params available:

$order, $sent_to_admin, $plain_text, $email

$email is an object that consists of order info and much more.
I see that id is always available.

So you can do:

$email_id = $email->id;

if($email_id == 'customer_note') {
// another id i've seen during testing (just now) is: customer_on_hold_order

//do somthing
}

NOTE: inside email-order-items.php the $email param is not available. For now i'm not really sure how to get some kind of email id in this template, i'll have to investigate more.

Regards, Bjorn

How to pass $email to WooCommerce emails template files if not available by default

In /includes/class-wc-emails.php we see that only $email_heading is passed via wc_get_template()

/**
* Get the email header.
*
* @param mixed $email_heading Heading for the email.
*/
public function email_header( $email_heading ) {
wc_get_template( 'emails/email-header.php', array( 'email_heading' => $email_heading ) );
}

So to pass the $email->id we have to use a workaround, first we will make the variable global available.


1) This can be done via different hooks but the woocommerce_email_header hook seems to be the most suitable in this specific case:

// Header - set global variable
function action_woocommerce_email_header( $email_heading, $email ) {
$GLOBALS['email_id'] = $email->id;
}
add_action( 'woocommerce_email_header', 'action_woocommerce_email_header', 10, 2 );

Code goes in functions.php file of the active child theme (or active theme).

2) Then in the desired template file you can use:

2.1) put this just after if ( ! defined( 'ABSPATH' ) ) {..}

// Getting the email ID global variable
$ref_name_globals_var = isset( $GLOBALS ) ? $GLOBALS : '';
$email_id = isset( $ref_name_globals_var['email_id'] ) ? $ref_name_globals_var['email_id'] : '';

2.2) and at the desired location, towards the output

// Targeting specific email. Multiple statuses can be added, separated by a comma
if ( in_array( $email_id, array( 'new_order', 'customer_processing_order' ) ) ) {
// Desired output
echo '<p style="color: red; font-size: 20px;">Your output</p>';
}

Add custom text 'per item' based on product category in WooCommerce email notifications

Some notes on your code attempt:

  • $product_cat and $cat do not exist as arguments for the woocommerce_order_item_meta_end hook
  • $cat->get_product_cat() does not exist and is incorrect
  • Use has_term() WordPress function to check if the current post has any of given terms

So you get:

// Setting global variable
function action_woocommerce_email_before_order_table( $order, $sent_to_admin, $plain_text, $email ) {
$GLOBALS['email_data'] = array(
'email_id' => $email->id, // The email ID (to target specific email notification)
'is_email' => true // When it concerns a WooCommerce email notification
);
}
add_action( 'woocommerce_email_before_order_table', 'action_woocommerce_email_before_order_table', 1, 4 );

// Displaying description
function action_woocommerce_order_item_meta_end( $item_id, $item, $order, $plain_text ) {
// Getting the custom 'email_data' global variable
$ref_name_globals_var = $GLOBALS;

// Isset & NOT empty
if ( isset ( $ref_name_globals_var ) && ! empty( $ref_name_globals_var ) ) {
// Isset
$email_data = isset( $ref_name_globals_var['email_data'] ) ? $ref_name_globals_var['email_data'] : '';

// NOT empty
if ( ! empty( $email_data ) ) {
// Specific categories: the term name/term_id/slug. Several could be added, separated by a comma
$categories = array( 108, 1, 'categorie-1' );

// The text information
$text_information = __( 'There is an offer in this particular item', 'woocommerce' );

// Specific email notifications: multiple statuses can be added, separated by a comma
$email_ids = array( 'new_order', 'customer_processing_order', 'customer_completed_order', 'customer_on_hold_order' );

// Targeting specific email notifications AND check if the current post has any of given terms
if ( in_array( $email_data['email_id'], $email_ids ) && has_term( $categories, 'product_cat', $item->get_product_id() ) ) {
// Display the text
echo '<p>' . $text_information . '</p>';
}
}
}
}
add_action( 'woocommerce_order_item_meta_end', 'action_woocommerce_order_item_meta_end', 10, 4 );

Display message in WooCommerce email notifications when order has backorder items in it

Your code contains a CRITICAL uncaught error, namely: Call to a member function is_on_backorder() on null

Following code will add the message for the customer_processing_order email notification. Also see: How to target other WooCommerce order emails

So you get:

function action_woocommerce_email_after_order_table( $order, $sent_to_admin, $plain_text, $email ) {
// Initialize
$flag = false;

// Target certain email notification
if ( $email->id == 'customer_processing_order' ) {
// Iterating through each item in the order
foreach ( $order->get_items() as $item ) {
// Get a an instance of product object related to the order item
$product = $item->get_product();

// Check if the product is on backorder
if ( $product->is_on_backorder() ) {
$flag = true;

// Stop the loop
break;
}
}

// True
if ( $flag ) {
echo '<p style="color: red; font-size: 30px;">' . __( 'My message', 'woocommerce' ) . '</p>';
}
}
}
add_action( 'woocommerce_email_after_order_table', 'action_woocommerce_email_after_order_table', 10, 4 );

Targetting WooCommerce customer processing and completed order email notifications

This can be done easily targeting those email notifications through the missing hook argument $email, this way:

add_action( 'woocommerce_email_after_order_table', 'local_pickup_extra_content_email', 10, 4  );
function local_pickup_extra_content_email( $order, $sent_to_admin, $plain_text, $email ) {
// Only for "Processing Order" and "Order Completed" customer emails
if( ! ( 'customer_processing_order' == $email->id || 'customer_completed_order' == $email->id ) ) return;

$lang = get_post_meta( $order->id, 'wpml_language', true );
if ( $lang == 'he' && && strpos( $order->get_shipping_method(), 'Local Pickup' ) !== false) {
echo '<p><strong>Note:</strong> Please wait for telephone confirmation of local pickup.</p>';
}
}

This code goes in function.php file of your active child theme (or theme) or also in any plugin file.

Tested and works


Similar answer: Add a custom text to specific email notification for local pickup Woocommerce orders

Change sender name to value from order meta data in WooCommerce email notifications

It is not necessary to add this filter in the woocommerce_order_status_processing hook, when the order status changes to processing. Because we can apply the reverse. Via $email->id it is possible to target specific email notifications when this hook is triggered.

To obtain meta data belonging to the order, you can use $order->get_meta( 'meta_key' )

So you get:

function filter_woocommerce_email_from_name( $from_name, $email ) {
// Targeting specific email notification via the email id
if ( $email->id == 'customer_processing_order' && is_a( $email->object, 'WC_Order' ) ) {
// Get order
$order = $email->object;

// Get meta
$business_name = $order->get_meta( 'businessname' );

// NOT empty
if ( ! empty ( $business_name ) ) {
$from_name = $business_name;
}
}

return $from_name;
}
add_filter( 'woocommerce_email_from_name', 'filter_woocommerce_email_from_name', 10, 2 );


Related Topics



Leave a reply



Submit