Add recipients based on user role to failed and cancelled WooCommerce emails - php

I want to be able to change who receives the Woocommerce email notifications based on what role the user is when ordering.
For example, If the user is logged in as a Wholesale Customer then a different email will be notified.
I've found how to change it when a new order is complete using the woocommerce_email_recipient_new_order hook but i can't find any hooks related to the failed or cancelled notifications.
add_filter( 'woocommerce_email_recipient_new_order', 'sv_conditional_email_recipient', 10, 2 );
function sv_conditional_email_recipient( $recipient, $order ) {
// Bail on WC settings pages since the order object isn't yet set yet
// Not sure why this is even a thing, but shikata ga nai
$page = $_GET['page'] = isset( $_GET['page'] ) ? $_GET['page'] : '';
if ( 'wc-settings' === $page ) {
return $recipient;
}
// just in case
if ( ! $order instanceof WC_Order ) {
return $recipient;
}
if ( in_array( 'wholesale_customer', (array) $user->roles ) ) {
$recipient .= ', shaun#example.com';
return $recipient;
}
return $recipient;
}
add_filter( 'woocommerce_email_recipient_new_order', 'sv_conditional_email_recipient', 10, 2 );
Can anyone help please?

The hook you are already using is a composite hook: woocommerce_email_recipient_{$this->id}, where {$this->id} is the WC_Email ID like new_order. So you can set any email ID instead to make it work for the desired email notification.
Below You have the 3 hooks for "New Order", "Cancelled Order" and "Failed Order" that you can use for the same hooked function.
In your function, I have removed some unnecessary code and completed the code to get the customer data (the user roles) related to the order:
add_filter( 'woocommerce_email_recipient_new_order', 'user_role_conditional_email_recipient', 10, 2 );
add_filter( 'woocommerce_email_recipient_cancelled_order', 'user_role_conditional_email_recipient', 10, 2 );
add_filter( 'woocommerce_email_recipient_failed_order', 'user_role_conditional_email_recipient', 10, 2 );
function user_role_conditional_email_recipient( $recipient, $order ) {
if ( ! is_a( $order, 'WC_Order' ) ) return $recipient;
// 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( 'wholesale_customer', $user_data->roles ) )
$recipient .= ', shaun#example.com';
return $recipient;
}
Code goes in function.php file of your active child theme (or theme) or also in any plugin file.
Tested and works.

Related

WooCommerce change BACS order status based on user roles

I get several orders where a customer selects "Direct Bank Transfer" and then they change their mind and want to pay by Credit Card. This is quite annoying because I have to manually change the order from "On Hold" to "Pending Payment" so they can pay by card via the "order-pay" endpoint which is found in "My Account" under "Orders".
I've been using the WooCommerce change order status BACS processing to automatically change the order status from "On Hold" to "Pending Payment".
// WooCommerce Change Order Status BACS Pending
add_action( 'woocommerce_thankyou', 'bacs_order_payment_pending_order_status', 10, 1 );
function bacs_order_payment_pending_order_status( $order_id ) {
if ( ! $order_id ) {
return;
}
// Get an instance of the WC_Order object
$order = new WC_Order( $order_id );
if ( ( get_post_meta($order->id, '_payment_method', true) == 'bacs' ) && ('on-hold' == $order->status ) ) {
$order->update_status('pending');
} else {
return;
}
}
But since I have several user profiles (I sell B2B as well), this is not practical for my shop. I'm trying to expand this snippet to also check for the user role. I've used the following in my other snippets. Is it possible to add the below logic to the snippet above?
$user = wp_get_current_user();
$roles = (array) $user->roles;
$roles_to_check = array('administrator', 'customer', 'shop_manager');
$compare = array_diff($roles, $roles_to_check);
if (empty($compare)){
This is my attempt.
// WooCommerce Change Order Status BACS Pending
add_action( 'woocommerce_thankyou', 'bacs_order_payment_pending_order_status', 10, 1 );
function bacs_order_payment_pending_order_status( $order_id ) {
if ( ! $order_id ) {
return;
}
// Get an instance of the WC_Order object
$order = new WC_Order( $order_id );
$user = wp_get_current_user();
$roles = (array) $user->roles;
$roles_to_check = array('administrator', 'customer', 'shop_manager');
$compare = array_diff($roles, $roles_to_check);
if (empty($compare)){
if ( ( get_post_meta($order->id, '_payment_method', true) == 'bacs' ) && ('on-hold' == $order->status ) ) {
$order->update_status('pending');
} else {
return;
}
}
You can use this as follows, comment with explanation added in the code
function bacs_order_payment_pending_order_status( $order_id ) {
// Get $order object
$order = wc_get_order( $order_id );
// Is a WC_Order
if ( is_a( $order, 'WC_Order' ) ) {
// Get user
$user = $order->get_user();
// Roles
$roles = (array) $user->roles;
// Roles to check
$roles_to_check = array( 'administrator', 'customer', 'shop_manager' );
// Compare
$compare = array_diff( $roles, $roles_to_check );
// Result is empty
if ( empty ( $compare ) ) {
if ( $order->get_payment_method() == 'bacs' && $order->has_status( 'on-hold' ) ) {
$order->update_status( 'pending' );
}
}
}
}
add_action( 'woocommerce_thankyou', 'bacs_order_payment_pending_order_status', 10, 1 );
Might Come in handy: WooCommerce: Get Order Info (total, items, etc) From $order Object
Woocommerce version 3.4.0 has introduced a much better hook that allows to change the default status for BACS payment gateway which is set to "on-hold".
Using this hook will:
Lighten your code,
Avoid "on-hold" notification to the customer when a BACS order is placed.
Here is that code:
add_filter( 'woocommerce_bacs_process_payment_order_status','filter_process_payment_order_status_callback', 10, 2 );
function filter_process_payment_order_status_callback( $status, $order ) {
// Here set the user roles to check
$roles_to_check = array( 'administrator', 'customer', 'shop_manager' );
$user = $order->get_user(); // Get the WP_User Object
$compare = array_diff( $user->roles, $roles_to_check ); // compare
if ( empty ( $compare ) ) {
return 'pending';
}
return $status;
}
Code goes in functions.php file of the active child theme (or active theme). Tested and works.
Since WooCommerce 5+: Allow re-sending New Order Notification in WooCommerce 5+
Enabling New Order email notification (sent to the admin) for BACS payments:
As pending Orders doesn't send email notifications, you can enable that with the following
add_action( 'woocommerce_checkout_order_processed', 'pending_new_order_notification', 20, 1 );
function pending_new_order_notification( $order_id ) {
// Get an instance of the WC_Order object
$order = wc_get_order( $order_id );
// Only for "pending" order status and BACS payments
if( $order->has_status( 'pending' ) && $order->get_payment_method() === 'bacs' )
{
// Send "New Email" notification (to admin)
WC()->mailer()->get_emails()['WC_Email_New_Order']->trigger( $order_id );
}
}
Code goes in functions.php file of the active child theme (or active theme). Tested and works.
Related: Send an Email notification to the admin for pending order status in WooCommerce
Useful: How to get WooCommerce order details
Related: Change default WooCommerce order status to processing for cheque and bacs payments
Freshly updated answer thread: WooCommerce change order status BACS processing

Additional email recipient based on payment method Ids in WooCommerce

I am trying to add additional email recipient based on payment method Id on WooCommerce "New order" email notification.
Here is my code:
function at_conditional_admin_email_recipient($recipient, $order){
// if( ! is_a($order, 'WC_Order') ) return $recipient;
if ( get_post_meta($order->id, '_payment_method', true) == 'my_custom_gateway_id' ) {
$recipient .= ', xx1#xx.com';
} else {
$recipient .= ', xx2#xx.com';
}
return $recipient;
};
add_filter( 'woocommerce_email_recipient_new_order', 'at_conditional_admin_email_recipient', 10, 2 );
But the hook doesn't seem firing my function. What could be the reason?
Your code is outdated since Woocommerce 3, try the following instead:
add_filter( 'woocommerce_email_recipient_new_order', 'payment_id_based_new_order_email_recipient', 10, 2 );
function payment_id_based_new_order_email_recipient( $recipient, $order ){
// Avoiding backend displayed error in Woocommerce email settings (mandatory)
if( ! is_a($order, 'WC_Order') )
return $recipient;
// Here below set in the array the desired payment Ids
$targeted_payment_ids = array('bacs');
if ( in_array( $order->get_payment_method(), $targeted_payment_ids ) ) {
$recipient .= ', manager1#gmail.com';
} else {
$recipient .= ', manager2#gmail.com';
}
return $recipient;
}
Code goes in functions.php file of your active child theme (or active theme). It should works.
Also sometimes the problem can be related to a wrong payment method Id string in your code (so try first for example with WooCommerce "cod" or "bacs" payment methods ids, to see if the code works).

Stop send specific email notification for specific users in Woocommerce

I want to stop send Woocommerce email for specific user/email. this is my example code to stop send email when order is completed.
<?php
add_filter( 'woocommerce_email_headers', 'ieo_ignore_function', 10, 2);
function ieo_ignore_function($headers, $email_id, $order) {
$list = 'admin#example.com,cs#example.com';
$user_email = (method_exists( $order, 'get_billing_email' ))? $order->get_billing_email(): $order->billing_email;
$email_class = wc()->mailer();
if($email_id == 'customer_completed_order'){
if(stripos($list, $user_email)!==false){
remove_action( 'woocommerce_order_status_completed_notification', array( $email_class->emails['WC_Email_Customer_Completed_Order'], 'trigger' ) );
}
}
}
But WP keep send the email. I try to search in Woocommerce docs and source (github) and Stackoverflow also but still cant solve this.
In this example "Customer completed order" notification is disable for specific customer email addresses:
// Disable "Customer completed order" for specifics emails
add_filter( 'woocommerce_email_recipient_customer_completed_order', 'completed_email_recipient_customization', 10, 2 );
function completed_email_recipient_customization( $recipient, $order ) {
// Disable "Customer completed order
if( is_a('WC_Order', $order) && in_array($order->get_billing_email(), array('jack#mail.com','emma#mail.com') ) ){
$recipient = '';
}
return $recipient;
}
Code goes in function.php file of your active child theme (active theme). Tested and works.
Note: A filter hook needs always to return the filtered main function argument
It can also be done from User IDs like:
// Disable "Customer completed order" for specifics User IDs
add_filter( 'woocommerce_email_recipient_customer_completed_order', 'completed_email_recipient_customization', 10, 2 );
function completed_email_recipient_customization( $recipient, $order ) {
// Disable "Customer completed order
if( is_a('WC_Order', $order) && in_array($order->get_customer_id(), array(25,87) ) ){
$recipient = '';
}
return $recipient;
}
Code goes in function.php file of your active child theme (active theme). Tested and works.
Similar: Stop specific customer email notification based on payment methods in Woocommerce
While answer above is working, this seems to be more straighforward solution:
add_filter( 'woocommerce_email_recipient_customer_completed_order', 'completed_email_recipient_customization', 10, 2 );
function completed_email_recipient_customization( $recipient, $order ) {
if( in_array($recipient, ['some#email2block.com', 'another#email2block.com'] ) ) {
$recipient = '';
}
return $recipient;
}

Stop specific customer email notification based on payment methods in Woocommerce

In Woocommerce, I need to stop email notifications sent to the customer when order place except when payment_method is BACS (Direct bank transfer).
I tried following in my active theme's function.php file:
add_filter( 'woocommerce_email_recipient_customer_on_hold_order_order', 'customer_order_email_if_bacs', 10, 2 );
function customer_order_email_if_bacs( $recipient, $order ) {
if( $order->payment_method() !== 'bacs' ) $recipient = '';
return $recipient;
}
But it don't work. Any help is appreciated.
Update 2
The woocommerce_email_recipient_{$email_id} filter is a composite hook and the right email ID to set in it is customer_on_hold_order and not customer_on_hold_order_order which will not work…
With the WC_Order object, since Woocommerce 3, you need to use get_payment_method() method.
To avoid Customer ON Hold email notification except for "Bacs" payment method use:
add_filter( 'woocommerce_email_recipient_customer_on_hold_order', 'customer_on_hold_order_for_bacs', 10, 2 );
function customer_on_hold_order_for_bacs( $recipient, $order ) {
if( is_a('WC_Order', $order) && $order->get_payment_method() !== 'bacs' ){
$recipient = '';
}
return $recipient;
}
Code goes in function.php file of your active child theme (active theme). Tested and works.

Sending email to customer on cancelled order in Woocommerce

I am trying to send an email to the client when an order gets cancelled. By default, woocommerce only sends this email only to the admin of the site.
This code has solved the issue for related posts on the web:
function wc_cancelled_order_add_customer_email( $recipient, $order ){
return $recipient . ',' . $order->billing_email;
}
add_filter( 'woocommerce_email_recipient_cancelled_order', 'wc_cancelled_order_add_customer_email', 10, 2 );
add_filter( 'woocommerce_email_recipient_failed_order', 'wc_cancelled_order_add_customer_email', 10, 2 );
However, it seems like woocommerce removed those filter hooks completely.
Is there any way of doing this?
Thanks in advance!
In this custom function hooked in woocommerce_order_status_changed action hook, I am targeting "cancelled" and "failed" orders sending an the corresponding email notification to the customer (as admin will receive it on his side by WooCommerce automated notifications):
add_action('woocommerce_order_status_changed', 'send_custom_email_notifications', 10, 4 );
function send_custom_email_notifications( $order_id, $old_status, $new_status, $order ){
if ( $new_status == 'cancelled' || $new_status == 'failed' ){
$wc_emails = WC()->mailer()->get_emails(); // Get all WC_emails objects instances
$customer_email = $order->get_billing_email(); // The customer email
}
if ( $new_status == 'cancelled' ) {
// change the recipient of this instance
$wc_emails['WC_Email_Cancelled_Order']->recipient = $customer_email;
// Sending the email from this instance
$wc_emails['WC_Email_Cancelled_Order']->trigger( $order_id );
}
elseif ( $new_status == 'failed' ) {
// change the recipient of this instance
$wc_emails['WC_Email_Failed_Order']->recipient = $customer_email;
// Sending the email from this instance
$wc_emails['WC_Email_Failed_Order']->trigger( $order_id );
}
}
Code goes in function.php file of your active child theme (or theme) or also in any plugin file.
This should works in WooCommerce 3+
If you need, instead of changing the email, you can add it, to existing recipients:
// Add a recipient in this instance
$wc_emails['WC_Email_Failed_Order']->recipient .= ',' . $customer_email;
Related answer: Send an email notification when order status change from pending to cancelled

Categories