wordpresswoocommerce

Woocommerce, different order emails depending on product in order


I need to send two different "new_order" emails depending on the products ordered. The case is that the products are stored at different locations and I need one email to be sent containing only the products present at storage 1, and the other mail containing the products present at storage 2. If only products located at storage 1 was ordered, email 2 should not be sent at all, and vice versa.

The storage information is a custom meta field on each product.

I have added a custom email-class which is a copy of class-wc-email-new-order but only with changed name where needed.

I've been looking through the hooks and filters for this, but I was not able to go all the way. I've also been thinking about overriding the email-order-details.phpfile and check each products meta field, but I am not sure if that is the right way to go. I guess the email would still be sent even if there are no products in the table, so to speak.

My problem is that I don't know which of the emails are sent out when using the different filters, so I cannot check that condition either.

Would you just create two new emails with templates and everything and go that way, or is it something I'm missing here?

If I can clarify anything, please let me know.

Edit: After talking a bit with @helgatheviking I realized that I needed to clearify that the emails regarding storage 1 should be sent only when the order contained products located at storage 1 and emails regarding storage 2 should only be sent when the order contained products located at storage 2. If the order contained both kind of products, both emails should be sent, but only displaying their respective products.


Solution

  • After thinking it through and reflecting upon what @helgatheviking said I was able to come up with a solution.

    I copied the class-wc-new-order and created two new classes exactly the same as the original. I changed ID and class names to storage 1 and storage 2 respectively.

    I load the classes by doing the following: EDIT WRONG METHOD, SEE BELOW INSTEAD

    //Add our custom class to WC email classes
    add_filter( 'woocommerce_email_classes', [ $this, 'custom_order_email_add_email_classes' ], 10, 1 );
    
    function custom_order_email_add_email_classes( $email_classes ) {
    
         require( CUSTOM_ORDER_EMAIL_PLUGIN_DIR . 'classes/class-wc-email-new-order-storage1.php' );
         require( CUSTOM_ORDER_EMAIL_PLUGIN_DIR . 'classes/class-wc-email-new-order-storage2.php' );
    
         $email_classes['WC_Email_New_Order_Storage1']  = new WC_Email_New_Order_Storage1(); 
         $email_classes['WC_Email_New_Order_Storage2']  = new WC_Email_New_Order_Storage2();
    
         return $email_classes;
    }
    

    Notice that this is within a special plugin, you'll have to edit the code a bit if you were to use it in your functions.php.

    I then edited the trigger()-function in both email classes:

    public function trigger( $order_id, $order = false ) {
    
        $trigger = false;
    
        if ( $order_id && ! is_a( $order, 'WC_Order' ) ) {
            $order = wc_get_order( $order_id );
        }
    
        if ( is_a( $order, 'WC_Order' ) ) {
            $this->object                  = $order;
            $this->find['order-date']      = '{order_date}';
            $this->find['order-number']    = '{order_number}';
            $this->replace['order-date']   = wc_format_datetime( $this->object->get_date_created() );
            $this->replace['order-number'] = $this->object->get_order_number();
    
            $items = $order->get_items();
    
            foreach ( $items as $item_id => $item ) {
    
                $product = $item->get_product();
    
                if ( $product->get_meta( '_product_storage' ) == 'storage2' ) {//storage1 in the other email class
                    $trigger = true;
                }
            }
        }
    
        if ( ! $this->is_enabled() || ! $this->get_recipient() ) {
            return;
        }
    
        if( $trigger === true) {
            $this->send( $this->get_recipient(), $this->get_subject(), $this->get_content(), $this->get_headers(), $this->get_attachments() );
        }
        else {
            return;
        }
    }
    

    Everything seems to be behaving as it should but I'll do some more testing before accepting my own answer. Thanks again to Helgatheviking for leading me onto the right track. :)

    Edit: forgot to add my override of email-order-details.php. This is added just below <tbody>

    if ( $email->id == 'new_order_storage1' ) {
    
            $items = $order->get_items();
            foreach( $items as $item_id => $item ) {
    
                $product = $item->get_product();
    
                if ( $product->get_meta( '_product_storage' ) == 'storage1' ) {
            ?>
                    <tr class="<?php echo esc_attr( apply_filters( 'woocommerce_order_item_class', 'order_item', $item, $order ) ); ?>">
                        <td class="td" style="text-align:<?php echo $text_align; ?>; vertical-align:middle; border: 1px solid #eee; font-family: 'Helvetica Neue', Helvetica, Roboto, Arial, sans-serif; word-wrap:break-word;"><?php
    
                            // Show title/image etc
                            if ( $show_image ) {
                                echo apply_filters( 'woocommerce_order_item_thumbnail', '<div style="margin-bottom: 5px"><img src="' . ( $product->get_image_id() ? current( wp_get_attachment_image_src( $product->get_image_id(), 'thumbnail' ) ) : wc_placeholder_img_src() ) . '" alt="' . esc_attr__( 'Product image', 'woocommerce' ) . '" height="' . esc_attr( $image_size[1] ) . '" width="' . esc_attr( $image_size[0] ) . '" style="vertical-align:middle; margin-' . ( is_rtl() ? 'left' : 'right' ) . ': 10px;" /></div>', $item );
                            }
    
                            // Product name
                            echo apply_filters( 'woocommerce_order_item_name', $item->get_name(), $item, false );
    
                            // SKU
                            if ( $show_sku && is_object( $product ) && $product->get_sku() ) {
                                echo ' (#' . $product->get_sku() . ')';
                            }
    
                            // allow other plugins to add additional product information here
                            do_action( 'woocommerce_order_item_meta_start', $item_id, $item, $order, $plain_text );
    
                            wc_display_item_meta( $item );
    
                            if ( $show_download_links ) {
                                wc_display_item_downloads( $item );
                            }
    
                            // allow other plugins to add additional product information here
                            do_action( 'woocommerce_order_item_meta_end', $item_id, $item, $order, $plain_text );
    
                        ?></td>
                        <td class="td" style="text-align:<?php echo $text_align; ?>; vertical-align:middle; border: 1px solid #eee; font-family: 'Helvetica Neue', Helvetica, Roboto, Arial, sans-serif;"><?php echo apply_filters( 'woocommerce_email_order_item_quantity', $item->get_quantity(), $item ); ?></td>
                        <td class="td" style="text-align:<?php echo $text_align; ?>; vertical-align:middle; border: 1px solid #eee; font-family: 'Helvetica Neue', Helvetica, Roboto, Arial, sans-serif;"><?php echo $order->get_formatted_line_subtotal( $item ); ?></td>
                    </tr>
                <?php
                }
            }
        }
        else if ( $email->id == 'new_order_storage2' ) {
            $items = $order->get_items();
            foreach( $items as $item_id => $item ) {
    
                $product = $item->get_product();
    
                if ( $product->get_meta( '_product_storage' ) == 'storage2' ) {
            ?>
                    <tr class="<?php echo esc_attr( apply_filters( 'woocommerce_order_item_class', 'order_item', $item, $order ) ); ?>">
                        <td class="td" style="text-align:<?php echo $text_align; ?>; vertical-align:middle; border: 1px solid #eee; font-family: 'Helvetica Neue', Helvetica, Roboto, Arial, sans-serif; word-wrap:break-word;"><?php
    
                            // Show title/image etc
                            if ( $show_image ) {
                                echo apply_filters( 'woocommerce_order_item_thumbnail', '<div style="margin-bottom: 5px"><img src="' . ( $product->get_image_id() ? current( wp_get_attachment_image_src( $product->get_image_id(), 'thumbnail' ) ) : wc_placeholder_img_src() ) . '" alt="' . esc_attr__( 'Product image', 'woocommerce' ) . '" height="' . esc_attr( $image_size[1] ) . '" width="' . esc_attr( $image_size[0] ) . '" style="vertical-align:middle; margin-' . ( is_rtl() ? 'left' : 'right' ) . ': 10px;" /></div>', $item );
                            }
    
                            // Product name
                            echo apply_filters( 'woocommerce_order_item_name', $item->get_name(), $item, false );
    
                            // SKU
                            if ( $show_sku && is_object( $product ) && $product->get_sku() ) {
                                echo ' (#' . $product->get_sku() . ')';
                            }
    
                            // allow other plugins to add additional product information here
                            do_action( 'woocommerce_order_item_meta_start', $item_id, $item, $order, $plain_text );
    
                            wc_display_item_meta( $item );
    
                            if ( $show_download_links ) {
                                wc_display_item_downloads( $item );
                            }
    
                            // allow other plugins to add additional product information here
                            do_action( 'woocommerce_order_item_meta_end', $item_id, $item, $order, $plain_text );
    
                        ?></td>
                        <td class="td" style="text-align:<?php echo $text_align; ?>; vertical-align:middle; border: 1px solid #eee; font-family: 'Helvetica Neue', Helvetica, Roboto, Arial, sans-serif;"><?php echo apply_filters( 'woocommerce_email_order_item_quantity', $item->get_quantity(), $item ); ?></td>
                        <td class="td" style="text-align:<?php echo $text_align; ?>; vertical-align:middle; border: 1px solid #eee; font-family: 'Helvetica Neue', Helvetica, Roboto, Arial, sans-serif;"><?php echo $order->get_formatted_line_subtotal( $item ); ?></td>
                    </tr>
                <?php
                }
            }
        }
        else {
         echo wc_get_email_order_items( $order, array(
            'show_sku'      => $sent_to_admin,
            'show_image'    => false,
            'image_size'    => array( 32, 32 ),
            'plain_text'    => $plain_text,
            'sent_to_admin' => $sent_to_admin,
        ) ); 
        }
    

    The code displaying order items are taken directly from order-email-items. I am not sure if there is a better way to do this thought, feel free to correct me if this is the case.

    EDIT, Skyverge was using an old method to load custom email classes. Correct method for loading custom email classes is:

        //Add our custom class to WC email classes
        add_filter( 'woocommerce_email_classes', [ $this, 'custom_order_email_add_email_classes' ], 10, 1 );
    
        function custom_order_email_add_email_classes( $email_classes ) {
    
             $email_classes['WC_Email_New_Order_Storage1']  = include( CUSTOM_ORDER_EMAIL_PLUGIN_DIR . 'classes/class-wc-email-new-order-storage1.php' );
             $email_classes['WC_Email_New_Order_Storage2']  = include( CUSTOM_ORDER_EMAIL_PLUGIN_DIR . 'classes/class-wc-email-new-order-storage2.php' );
    
         return $email_classes;
    }