• Resolved bhamrick

    (@bhamrick)


    I have a custom email sent when products in certain shipping classes are ordered. This email is sent to one of our fulfillment centers with the items ordered that they need to fulfill. My problem right now is I have some code to generate an order programmatically, and those orders end up triggering the email twice. This is an issue because I don’t want my fulfillment center to end up shipping more than one package for the same order.

    Here’s my custom email class:

    <?php
    
    if ( ! defined( 'ABSPATH' ) ) {
        exit;
    }
    
    if ( ! class_exists( 'WC_Fulfillment_Order_Email' ) ) :
    
    /**
     * A custom Expedited Order WooCommerce Email class
     */
    class WC_Fulfillment_Order_Email extends WC_Email {
    
        /**
         * Constructor.
         */
        public function __construct() {
            $this->id               = 'wc_fulfillment_order';
            $this->title            = 'Fulfillment Order';
            $this->description      = 'Fulfillment Order Notification emails are sent when an Fulfillment product is purchased.';
            $this->heading          = 'Fulfillment Shipping Order';
            $this->subject                  = 'Fulfillment Shipping Order';
            $this->template_html    = 'emails/new-fulfillment-order.php';
            $this->template_plain   = 'emails/plain/new-fulfillment-order.php';
    
            // Triggers for this email
            add_action( 'woocommerce_order_status_pending_to_processing_notification', array( $this, 'trigger' ) );
            add_action( 'woocommerce_order_status_pending_to_completed_notification', array( $this, 'trigger' ) );
            add_action( 'woocommerce_order_status_pending_to_on-hold_notification', array( $this, 'trigger' ) );
            add_action( 'woocommerce_order_status_failed_to_processing_notification', array( $this, 'trigger' ) );
            add_action( 'woocommerce_order_status_failed_to_completed_notification', array( $this, 'trigger' ) );
            add_action( 'woocommerce_order_status_failed_to_on-hold_notification', array( $this, 'trigger' ) );
    
            // Call parent constructor
            parent::__construct();
    
            // Other settings
            $this->recipient = $this->get_option( 'recipient', get_option( 'admin_email' ) );
        }
    
        /**
         * Trigger.
         *
         * @param int $order_id
         */
        public function trigger( $order_id ) {
            if ( $order_id ) {
                $this->object                  = wc_get_order( $order_id );
                $this->find['order-date']      = '{order_date}';
                $this->find['order-number']    = '{order_number}';
                $this->replace['order-date']   = date_i18n( wc_date_format(), strtotime( $this->object->order_date ) );
                $this->replace['order-number'] = $this->object->get_order_number();
            }
    
            if ( ! $this->is_enabled() || ! $this->get_recipient() ) {
                return;
            }
    
            $fulfillment = false;
            foreach ($this->object->get_items() as $item) {
                $product = new WC_Product($item['product_id']);
            if ($product->get_shipping_class() == 'fulfillment') {
                    $fulfillment = true;
                }
            }
            if (!$fulfillment)
                return;
    
            $this->send( $this->get_recipient(), $this->get_subject(), $this->get_content(), $this->get_headers(), $this->get_attachments() );
        }
    
        /**
         * Get content html.
         *
         * @access public
         * @return string
         */
        public function get_content_html() {
            return wc_get_template_html( $this->template_html, array(
                'order'         => $this->object,
                'email_heading' => $this->get_heading(),
                'sent_to_admin' => true,
                'plain_text'    => false,
                'email'         => $this
            ) );
        }
    
        /**
         * Get content plain.
         *
         * @access public
         * @return string
         */
        public function get_content_plain() {
            return wc_get_template_html( $this->template_plain, array(
                'order'         => $this->object,
                'email_heading' => $this->get_heading(),
                'sent_to_admin' => true,
                'plain_text'    => true,
                'email'         => $this
            ) );
        }
    
        /**
         * Initialise settings form fields.
         */
        public function init_form_fields() {
            $this->form_fields = array(
                'enabled' => array(
                    'title'         => __( 'Enable/Disable', 'woocommerce' ),
                    'type'          => 'checkbox',
                    'label'         => __( 'Enable this email notification', 'woocommerce' ),
                    'default'       => 'yes'
                ),
                'recipient' => array(
                    'title'         => __( 'Recipient(s)', 'woocommerce' ),
                    'type'          => 'text',
                    'description'   => sprintf( __( 'Enter recipients (comma separated) for this email. Defaults to <code>%s</code>.', 'woocommerce' ), esc_attr( get_option('admin_email') ) ),
                    'placeholder'   => '',
                    'default'       => '',
                    'desc_tip'      => true
                ),
                'subject' => array(
                    'title'         => __( 'Subject', 'woocommerce' ),
                    'type'          => 'text',
                    'description'   => sprintf( __( 'This controls the email subject line. Leave blank to use the default subject: <code>%s</code>.', 'woocommerce' ), $this->subject ),
                    'placeholder'   => '',
                    'default'       => '',
                    'desc_tip'      => true
                ),
                'heading' => array(
                    'title'         => __( 'Email Heading', 'woocommerce' ),
                    'type'          => 'text',
                    'description'   => sprintf( __( 'This controls the main heading contained within the email notification. Leave blank to use the default heading: <code>%s</code>.', 'woocommerce' ), $this->heading ),
                    'placeholder'   => '',
                    'default'       => '',
                    'desc_tip'      => true
                ),
                'email_type' => array(
                    'title'         => __( 'Email type', 'woocommerce' ),
                    'type'          => 'select',
                    'description'   => __( 'Choose which format of email to send.', 'woocommerce' ),
                    'default'       => 'html',
                    'class'         => 'email_type wc-enhanced-select',
                    'options'       => $this->get_email_type_options(),
                    'desc_tip'      => true
                )
            );
        }
    }
    
    endif;
    
    return new WC_Fulfillment_Order_Email();

    And here’s the code that triggers the new order:

    $address = array(
        'first_name' => $payload['customer']['firstName'],
        'last_name'  => $payload['customer']['lastName'],
        'email'      => $payload['customer']['email'],
        'phone'      => $payload['customer']['phone'],
        'address_1'  => $payload['customer']['line1'],
        'address_2'  => $payload['customer']['line2'],
        'city'       => $payload['customer']['city'],
        'state'      => $payload['customer']['state'],
        'postcode'   => $payload['customer']['zip'],
        'country'    => 'US'
      );
      $order = wc_create_order();
      foreach ($payload['items'] as $item) {
        $order->add_product( get_product_by_sku( $item['sku'] ), $item['qty'] );
      }
      $order->set_address( $address, 'billing' );
      $order->set_address( $address, 'shipping' );
      $order->update_status('processing');
      $order->calculate_totals();

    I’ve tried removing $order->update_status('processing'); and just instantiating the order with that status by using wc_create_order(array('status' => 'processing')); but that just ended up not sending any emails. Also tried limiting the triggers to one, just using woocommerce_order_status_pending_to_processing_notification but that still sends it twice.

    Thanks!

Viewing 6 replies - 1 through 6 (of 6 total)
  • Thread Starter bhamrick

    (@bhamrick)

    Figured this out for anyone else who might run into this. I copied my original code from a blog post but it looks like that code is out of date. I noticed it wasn’t working early on and copied my WC_Fulfillment_Order_Email class from the native WC_Email_New_Order class, but I just figured out I also needed to update how I was including that class. This is the method SkyVerge used, which I copied:

    function add_expedited_order_woocommerce_email( $email_classes ) {
    	// include our custom email class
    	require_once( 'includes/class-wc-expedited-order-email.php' );
    	// add the email class to the list of email classes that WooCommerce loads
    	$email_classes['WC_Expedited_Order_Email'] = new WC_Expedited_Order_Email();
    	return $email_classes;
    }
    add_filter( 'woocommerce_email_classes', 'add_expedited_order_woocommerce_email' );

    That seems to be the culprit, I updated it to the style WooCommerce now uses to include its native email classes:

    function add_fulfillment_order_woocommerce_email( $email_classes ) {
    
        // add the email class to the list of email classes that WooCommerce loads
        $email_classes['WC_Fulfillment_Order_Email'] = include( 'includes/class-wc-fulfillment-order-email.php' );
    
        return $email_classes;
    
    }
    add_filter( 'woocommerce_email_classes', 'add_fulfillment_order_woocommerce_email' );

    So far everything is working as expected!

    Thank you!
    I ran into the same thing, also using the SkyVerge code.
    Luckily you figured this out a week ago.
    So thank you for the timing and the sharing ??

    Thanks a lot!
    I noticed the change in the end of the class files:
    return new WC_Email_Customer_Completed_Order();
    and I didn’t understand it (it seemed to be redundant).

    I found your post since emails were sent twice, and the new syntax fixed it!
    ??

    • This reply was modified 7 years, 11 months ago by yanoom. Reason: Notify me of follow-up replies via email

    Hello. Is there a place to download the zip file of the corrected code (including hierarchy folder just to put that in the plugin directory ?) Thanks for no programmer guy….
    Chris

    Thread Starter bhamrick

    (@bhamrick)

    Sorry, if you’re not fluent in PHP I wouldn’t recommend attempting this. Plenty of freelancers out there looking for work, I’d recommend hiring one.

    Just wanted to say thank you for finding this as I’ve been struggling with the same problem, double emails.
    Even made a Stackoverflow question regarding this but thanks to you I solved it. ??

    Regards,

Viewing 6 replies - 1 through 6 (of 6 total)
  • The topic ‘WooCommerce Email Triggering Twice (2x sends)’ is closed to new replies.