Woocommerce email notifications additional recipients based on user role - wordpress

In Woocommerce, I am trying to send the "new order" email to extra email addresses. The other email addresses depend on what the role of the user is.
Based on "Adding a custom email recipient depending on selected custom checkout field value" answer code, making changes to it, here is my code:
add_filter( 'woocommerce_email_recipient_new_order', 'new_order_conditional_email_recipient', 10, 2 );
function new_order_conditional_email_recipient( $recipient, $order ) {
if ( ! is_a( $order, 'WC_Order' ) ) return $recipient; // (Optional)
// Get the order ID (retro compatible)
$order_id = method_exists( $order, 'get_id' ) ? $order->get_id() : $order->id;
// Get the customer ID
$user_id = $order->get_user_id();
// Get the user data
$user_data = get_userdata( $user_id );
// Adding an additional recipient for a custom user role
if ( in_array( 'user_role1', $user_data->roles ) )
$recipient .= ', email1#gmail.com';
elseif ( in_array( 'user_role2', $user_data->roles ) )
$recipient .= ', email2#gmail.com';
return $recipient;
}
I just can't seem to find out how to get user information from the order.
This is what I tried right now, but when I try to place an other I get an "internal server error".
So I am basically trying to find out how to get fields from the user who placed the order.

For user roles based, try the following:
add_filter( 'woocommerce_email_recipient_new_order', 'new_order_conditional_email_recipient', 10, 2 );
function new_order_conditional_email_recipient( $recipient, $order ) {
if ( ! is_a( $order, 'WC_Order' ) )
return $recipient;
// Get an instance of the WP_User Object related to the order
$user = $order->get_user();
// Add additional recipient based on custom user roles
if ( in_array( 'user_role1', $user->roles ) )
$recipient .= ', email1#gmail.com';
elseif ( in_array( 'user_role2', $user->roles ) )
$recipient .= ', email2#gmail.com';
return $recipient;
}
Code goes in function.php file of your active child theme (or active theme). It should works.

Related

Hide item meta data in certain WooCommerce email notifications

I've got this code snippet in my functions.php file:
add_action( 'woocommerce_checkout_create_order_line_item', 'add_custom_field_to_order_item_meta', 10, 4 );
function add_custom_field_to_order_item_meta( $item, $cart_item_key, $values, $order ) {
$custom_field_value = get_post_meta( $item->get_product_id(), 'supplier_sku', true );
if ( ! empty($custom_field_value) ){
$item->update_meta_data( __('Supplier SKU', 'woocommerce'), $custom_field_value );
}
}
It pulls in the custom field on products, called Supplier SKU and then adds it to the WooCommerce email notifications. Which is fine, but I want to exclude it from the customer email notification and only have it display in the admin email notification.
How can I achieve this?
You could use the woocommerce_display_item_meta hook and return an empty string
function filter_woocommerce_display_item_meta ( $html, $item, $args ) {
$html = '';
return $html;
}
add_filter( 'woocommerce_display_item_meta', 'filter_woocommerce_display_item_meta', 10, 3 );
While the above would work, there would be some issues, namely:
The hook doesn't run just for email notifications, so it wouldn't show up anywhere
Even if this hook would only be executed for email notifications, we would still need to specify that this should only be the case for certain email notifications. However, this hook does not offer a solution for it by default to make this distinction
So a workaround will be needed, this can be done by creating a global variable through another hook that applies only to email notifications
Step 1) creating and adding a global variable
// 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_display_item_meta, add and check for specific conditions
Only for email notifications
Only for specific meta data
Only for admin 'new order' email
function filter_woocommerce_display_item_meta ( $html, $item, $args ) {
// For email notifications and specific meta
if ( ! is_wc_endpoint_url() && $item->is_type( 'line_item' ) && $item->get_meta( 'Supplier SKU' ) ) {
// 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' ) ) ) {
$html = '';
}
}
return $html;
}
add_filter( 'woocommerce_display_item_meta', 'filter_woocommerce_display_item_meta', 10, 3 );

Adding addiotional email from products custom field

I am trying to add a new email to order confirmation. Now I am able to use the order's custom fields to ad a new extra email address. But i would like to use a custom field from the product instead.
Below is what I have done so far.
add_filter( 'woocommerce_email_recipient_new_order', 'additional_customer_email_recipient', 10, 2 ); // New Order
function additional_customer_email_recipient( $recipient, $order ) {
if ( ! is_a( $order, 'WC_Order' ) ) return $recipient;
$prod_id = get_the_ID();
$extra_mail = get_post_meta($prod_id,'extra_email',true);
$recipient = $extra_mail;
return $recipient;
}

Add custom field (ACF) to WooCommerce completed order email notification

There are many threads which deal with the topic "custom fields in WooCommerce emails" but I couldn't find the exact case I am struggling with.
I could achieve 50% of this project to display the field as a meta in the order table.
add_action( 'woocommerce_order_item_meta_end', 'custom_product_info', 20, 4 );
function custom_product_info ( $item_id, $item, $order, $plain_text ) {
$id = $item->get_product_id();
$erlebnisidgc = get_field('erlebnis_id',$id);
if($erlebnisidgc){
echo "<p>Here's your Link</p><a href=https://b-ceed.de/?eventid='.$erlebnisidgc'>Testlink</a>";
}
}
So this code works perfectly with the custom field. Problem is that this output isn't shown only in the customer_completed_order email but also in all other emails.
Therefore, I tried this code snippet:
add_action( 'woocommerce_order_item_meta_end', 'custom_product_info', 20, 4 );
function custom_product_info ( $item_id, $item, $order, $plain_text ) {
if ( $email->id == 'customer_completed_order' ) {
$id = $item->get_product_id();
$erlebnisidgc = get_field('erlebnis_id',$id);
if($erlebnisidgc){
echo "<p>Here's your Link</p><a href=https://b-ceed.de/?eventid='.$erlebnisidgc'>Testlink</a>";
}
}
}
But now the output won't be displayed in any email anymore and it triggers a internal server error. Any advice?
$email ($email->id) is not passed as argument to the woocommerce_order_item_meta_end hook, therefore it is undefined
So to target specific email notifications a workaround will be needed, this can be done by creating a global variable via the woocommerce_email_before_order_table hook
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 );
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 ) ) {
// Target specific emails, several can be added in the array, separated by a comma
$target_emails = array( 'customer_completed_order' );
// Target specific WooCommerce email notifications
if ( in_array( $email_data['email_id'], $target_emails ) ) {
// Get product ID
$product_id = $item->get_product_id();
// Get field
$erlebnisidgc = get_field( 'erlebnis_id', $product_id );
// Has some value
if ( $erlebnisidgc ) {
echo '<p>Here is your Link</p>';
echo 'Testlink';
}
}
}
}
}
add_action( 'woocommerce_order_item_meta_end', 'action_woocommerce_order_item_meta_end', 10, 4 );
Used in this answer:
Determine only for WooCommerce admin email notification
How to target other WooCommerce order emails

Add extra customer note on order creation for specific user role in WooCommerce

For a specific user role I want to add a specific customer note to the order.
This is my code:
add_action( 'woocommerce_new_order', 'add_customer_note_user_role' );
function add_customer_note_user_role( $order_id ) {
$user_info = get_userdata(get_current_user_id());
if ( $user_info->roles[0]=="administrator" ) {
$order = wc_get_order( $order_id );
// The text for the note
$note = 'This is the message';
// Add the note
$order->add_order_note( $note );
// Save the data
$order->save();
}
}
But this puts the message in the wrong place. When you check an order in the backend it's been displayed in the purple message boxes.
I want the message to be displayed as a customer note which is displayed under the shipping address. Because my API is picking up the notes from that place and puts them in our ERP.
I tried to change
$order->add_order_note( $note );
to
$order->add_order_note( $note, 'is_customer_note', true );
But without the desired result, any advice?
To display the message as a customer note displayed below the shipping address, you can use set_customer_note() instead.
So you get:
function action_woocommerce_new_order( $order_id ) {
// Get the WC_Order Object
$order = wc_get_order( $order_id );
// Get the WP_User Object
$user = $order->get_user();
// Check for "administrator" user roles only
if ( is_a( $user, 'WP_User' ) && in_array( 'administrator', (array) $user->roles ) ) {
// The text for the note
$note = 'This is the message';
// Set note
$order->set_customer_note( $note );
// Save
$order->save();
}
}
add_action( 'woocommerce_new_order', 'action_woocommerce_new_order', 10, 1 );
To keep the original message (when NOT empty) use this instead:
function action_woocommerce_new_order( $order_id ) {
// Get the WC_Order Object
$order = wc_get_order( $order_id );
// Get the WP_User Object
$user = $order->get_user();
// Check for "administrator" user roles only
if ( is_a( $user, 'WP_User' ) && in_array( 'administrator', (array) $user->roles ) ) {
// The text for the note
$note = 'This is the message';
// Get customer note
$customer_note = $order->get_customer_note();
// NOT empty
if ( ! empty ( $customer_note ) ) {
$note = $customer_note . ' | ' . $note;
}
// Set note
$order->set_customer_note( $note );
// Save
$order->save();
}
}
add_action( 'woocommerce_new_order', 'action_woocommerce_new_order', 10, 1 );

Adding email notification to site admin for custom order status change in Woocommerce

WooCommerce default mode is to send an email to the client when order status change happens. But how can the admin / store manager know when these changes are made? Keeping the orders page open 24/7 and refresh the view is not a solution.
I have tried the following code, however this does not work for custom order status.
add_filter('woocommerce_email_recipient_customer_processing_order', 'email_recipient_custom_notification', 10, 2);
function email_recipient_custom_notification( $recipient, $order ) {
if ( ! is_a( $order, 'WC_Order' ) ) return $recipient;
error_log("Hello: woocommerce_email_recipient_customer_processing_order : recipient = " . $recipient . "\n" );
// Set HERE your replacement recipient email(s)… (If multiple, separate them by a coma)
$recipient .= ', admin#xyz.com';
return $recipient;
}
add_filter('woocommerce_email_recipient_customer_out-to-delivery_order', 'email_out_to_delivery_notification', 10, 2);
function email_out_to_delivery_notification( $recipient, $order ) {
if ( ! is_a( $order, 'WC_Order' ) ) return $recipient;
error_log("Hello: woocommerce_email_recipient_customer_out-to-delivery_order : recipient
= " . $recipient . "\n" );
// Set HERE your replacement recipient email(s)… (If multiple, separate them by a coma)
$recipient .= ', admin#xyz.com';
return $recipient;
}
Note that 'out-to-delivery' is the custom order status that I have successfully added. I am able to change the order status from "On-hold --> Processing --> Out-To-Delivery --> Completed".
With the above changes site admin get the notification for 'New-Order' and 'Processing' order status. But he doesn't get notification for 'Out-To-Delivery' or 'Completed' status change. Seems that the filter 'woocommerce_email_recipient_customer_out-to-delivery_order' that I have used doesn't work.
Thanks
The following code works for me for sending email notification on custom order-status change:
add_filter('woocommerce_email_recipient_customer_processing_order', 'email_recipient_custom_notification', 10, 2);
function email_recipient_custom_notification( $recipient, $order ) {
if ( ! is_a( $order, 'WC_Order' ) ) return $recipient;
// Set HERE your replacement recipient email(s)… (If multiple, separate them by a coma)
$recipient .= ', admin#xyz.com';
return $recipient;
}
add_action('woocommerce_order_status_changed', 'send_custom_email_notifications', 10, 4 );
function send_custom_email_notifications( $order_id, $old_status, $new_status, $order ){
$wc_emails = WC()->mailer()->get_emails(); // Get all WC_emails objects instances
if ($new_status === 'out-to-delivery') {
$wc_emails['WC_Email_Customer_Processing_Order']->trigger( $order_id );
}
}

Resources