Different recipients based on product category in WooCommerce email notification
Asked Answered
C

2

6

I am setting up a site for a school that sells both virtual products (fees and excursion payments) and Physical (uniforms) however they would like to have order notifications for each category to be sent to separate recipients as they are dealt with by different departments.

For example all uniform category orders are to go to recipient one, while all the others go to recipient two... I have come across multiple ways to send custom emails messages based on the product, however none of these meet my requirements.

I would also like to be able to do this without the use of a plugin like Woocommerce Advanced Notifications.

Any assistance with this would be greatly appreciated.

Cervine answered 4/1, 2019 at 7:38 Comment(0)
E
8

The following will add additional recipients to "New Order" email notification based on your product categories, that you will define in an indexed array with an email recipient / product category pairs:

add_filter( 'woocommerce_email_recipient_new_order', 'custom_email_recipient_new_order', 10, 2 );
function custom_email_recipient_new_order( $recipient, $order ) {
    // Not in backend when using $order (avoiding an error)
    if( ! is_a($order, 'WC_Order') ) return $recipient;

    // Define the email recipients / categories pairs in the array
    $recipients_categories = array(
        '[email protected]'   => 'category-one',
        '[email protected]'   => 'category-two',
        '[email protected]' => 'category-three',
    );

    // Loop through order items
    foreach ( $order->get_items() as $item ) {
        // Loop through defined product categories
        foreach ( $recipients_categories as $email => $category ) {
            if( has_term( $category, 'product_cat', $item->get_product_id() ) && strpos($recipient, $email) === false ) {
                $recipient .= ',' . $email;
            }
        }
    }
    return $recipient;
}

Code goes in functions.php file of your active child theme (or active theme). Tested and works.

Notes:

  • The defined Product categories can be term Ids, term slugs or term names.
  • Each product category need to be defined in the related products as has_term() WordPress conditional function doesn't handle parent terms.

###Addition to handle parent product categories:

// Custom conditional function that handle parent product categories too
function has_product_categories( $categories, $product_id = 0 ) {
    $parent_term_ids = $categories_ids = array(); // Initializing
    $taxonomy        = 'product_cat';
    $product_id      = $product_id == 0 ? get_the_id() : $product_id;

    if( is_string( $categories ) ) {
        $categories = (array) $categories; // Convert string to array
    }

    // Convert categories term names and slugs to categories term ids
    foreach ( $categories as $category ){
        $result = (array) term_exists( $category, $taxonomy );
        if ( ! empty( $result ) ) {
            $categories_ids[] = reset($result);
        }
    }

    // Loop through the current product category terms to get only parent main category term
    foreach( get_the_terms( $product_id, $taxonomy ) as $term ){
        if( $term->parent > 0 ){
            $parent_term_ids[] = $term->parent; // Set the parent product category
            $parent_term_ids[] = $term->term_id; // (and the child)
        } else {
            $parent_term_ids[] = $term->term_id; // It is the Main category term and we set it.
        }
    }
    return array_intersect( $categories_ids, array_unique($parent_term_ids) ) ? true : false;
}

// Adding custom recipients based on product categories
add_filter( 'woocommerce_email_recipient_new_order', 'custom_email_recipient_new_order', 10, 2 );
function custom_email_recipient_new_order( $recipient, $order ) {
    // Not in backend when using $order (avoiding an error)
    if( ! is_a($order, 'WC_Order') ) return $recipient;

    // Define the email recipients / categories pairs in the array
    $recipients_categories = array(
        '[email protected]'   => 'category-one',
        '[email protected]'   => 'category-two',
        '[email protected]' => 'category-three',
    );

    // Loop through order items
    foreach ( $order->get_items() as $item ) {
        // Loop through defined product categories
        foreach ( $recipients_categories as $email => $category ) {
            if( has_product_categories( $item->get_product_id(), array( $category ) ) && strpos($recipient, $email) === false ) {
                $recipient .= ',' . $email;
            }
        }
    }
    return $recipient;
}

Code goes in functions.php file of your active child theme (or active theme). Tested and works.

Note: The Product categories can be term Ids, term slugs or term names.


Similar: Different recipients based on products sold in WooCommerce email notification

Excretory answered 4/1, 2019 at 11:49 Comment(7)
thanks for the quick reply, sorry for my delayed one :( I'm a bit lost, can i just use the normal category/slug name ie, Uniforms, as i am not sure how to obtain the term id, term slug ect... Further more, with this "Each product category need to be defined in the related products as has_term() WordPress conditional function doesn't handle parent terms." Are you saying that I can not use the parent category Uniforms, but rather the sub-categories like boys, girls...etc... Regards,Cervine
@Cervine Yes has_term() function doesn't handle parent product categories… To make it work with parent term I have added something else at the end of this answer, that you can use instead…Excretory
Thanks @Excretory so all I will have to change is the following with the parent category $recipients_categories = array( '[email protected]' => 'uniforms', '[email protected]' => 'camps', '[email protected]' => 'excursions-retreats', '[email protected]' => 'school-fees', ); Is this correct?Cervine
Yes this is working now. I had to use the Parent Category name as displayed as the slug would not work. Thanks for all your assistance.Cervine
@Excretory what is the reason for // Not on backend (avoiding an error) if( is_admin() ) return $recipient; ? Doesn't this mean that admin orders are not notified in the same way a front end order is? ThanksInflate
@RodrigoM, Updated my code… On Admin in settings > emails the $order variable is not defined, so that's make an error without ! is_a($order, 'WC_Order')Excretory
@Excretory -I have recently been getting the following displayed in WC Email settings page: Uncaught Error: Call to a member function get_items() on null in .../functions.php:151 // Loop through order items foreach ( $order->get_items() as $item ) { // Loop through defined product categories foreach ( $recipients_categories as $email => $category ) { if( has_product_categories( $item->get_product_id(), array( $category ) ) && strpos($recipient, $email) === false ) { $recipient .= ',' . $email; } ...emails not sending...Cervine
S
0

Here's my solution, a bit simpler. It is set for new order order :

function send_new_order_email_to_additional_recipient( $recipient, $order ) {
    if ( ! is_a( $order, 'WC_Order' ) ) return $recipient;

    // Define the additional email address you want to send the new order notification to.
    $additional_email = '[email protected]';
    $additional_email2 = '[email protected]';
    // Loop through order items to check if there's a product from category "125"
    foreach ( $order->get_items() as $item_id => $item ) {
        $product_id = $item->get_product_id();
        if ( has_term( '125', 'product_cat', $product_id ) ) { // Change 125 for your term id
            // If a product from the specified category is found, add the additional email
            $recipient .= ',' . $additional_email . ',' . $additional_email2;
            break; // No need to continue checking once a product from the category is found
        }
    }

    return $recipient;
}
add_filter( 'woocommerce_email_recipient_new_order', 'send_new_order_email_to_additional_recipient', 10, 2 );
Shetler answered 19/2 at 13:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.