3

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.

Rodrigo M
  • 11,060
  • 2
  • 21
  • 43
Chris
  • 33
  • 1
  • 3

1 Answers1

5

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.one@email.com'   => 'category-one',
        'email.two@email.com'   => 'category-two',
        'email.three@email.com' => '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.one@email.com'   => 'category-one',
        'email.two@email.com'   => 'category-two',
        'email.three@email.com' => '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

LoicTheAztec
  • 184,753
  • 20
  • 224
  • 275
  • 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, – Chris Jan 05 '19 at 01:54
  • @Chris 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… – LoicTheAztec Jan 05 '19 at 02:16
  • Thanks @LoicTheAztec so all I will have to change is the following with the parent category $recipients_categories = array( 'email.one@email.com' => 'uniforms', 'email.two@email.com' => 'camps', 'email.two@email.com' => 'excursions-retreats', 'email.two@email.com' => 'school-fees', ); Is this correct? – Chris Jan 05 '19 at 02:37
  • 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. – Chris Jan 06 '19 at 01:34
  • @LoicTheAztec 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? Thanks – Rodrigo M Apr 06 '19 at 09:01
  • 2
    @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')`… – LoicTheAztec Apr 06 '19 at 09:07
  • @LoicTheAztec -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... – Chris May 13 '20 at 09:20