Add a button to WooCommerce admin orders that send a custom email notification

137 Views Asked by At

I'm currently working on a project that involves implementing a notification button to alert our drivers via email when an order is ready for pickup. However, I've encountered a puzzling issue that has left me scratching my head.

Here's the situation: Whenever the notification button is clicked, the order status inexplicably changes to 'pending payment.' This is not the desired behavior, and I'm struggling to pinpoint the root cause of this problem.


add_action( 'woocommerce_admin_order_data_after_order_details', 'send_driver_email_on_order_ready' );
function send_driver_email_on_order_ready( $order_id ) {
    $order = wc_get_order( $order_id );
    $id=$order->get_ID();
    $status = $order->get_status();
    $meta_data = $order->get_meta_data();
    
    if($status=='processing' || 'driver-assigned' || 'out-for-delivery'){
        foreach ( $meta_data as $meta ) {
            if ( $meta->key === 'lddfw_driverid' ) {
                $driver_id = $meta->value;
            }
            if ( $meta->key === 'Order_Ready' ) {
                $order_ready_value = $meta->value;

                if ( $order_ready_value === 'Yes' ) {
                    // Check if email has already been sent
                    $email_sent = $order->get_meta( 'email_sent', true );

                    if ( $email_sent != 'Yes' ) {
                        // Get driver information
                        $driver = get_userdata( $driver_id );
                        $driver_name = $driver->display_name;
                        $driver_email = $driver->user_email;

                        // Send email to driver
                        $subject = 'Order no.' . $id . ' ready for pickup';
                        $message = 'Hello ' . $driver_name . ',<br><br> Order no.' . $id . ' is now ready for pickup.';
                        $headers = array( 'Content-Type: text/html; charset=UTF-8' );

                        if ( wp_mail( $driver_email, $subject, $message, $headers ) ) {
                            // Update email_sent meta value
                            $order->update_meta_data( 'email_sent', 'Yes' );
                            $order->save();
                        }
                    }
                }
            }
        }
    }
}
add_filter('wp_mail_from', 'original_mail_address_email');
function original_mail_address_email(){
    $email ='[email protected]';
    return $email;
}
add_filter('wp_mail_from_name', 'email_name_order_ready');
function email_name_order_ready(){
    return 'Oven Fresh';
}


In addition to this challenge, I'd like to refine the functionality of the button. Ideally, I want the button to be displayed only when the order status is 'driver assigned' or 'out for delivery.' This would streamline the process and make it more efficient for our team.

Any assistance, insights, or suggestions you can provide would be greatly appreciated. Your help would be nothing short of a blessing.

1

There are 1 best solutions below

0
LoicTheAztec On BEST ANSWER

There are some mistakes, unnecessary complications and missing things.

The following will display a button to send an email notification to the driver for specific order statuses on:

  • a new column in Admin order list,
    enter image description here

  • single orders after billing address.

    enter image description here

When the email is sent, a success message replaces the button and an admin note is set. When an email has been sent, "Email sent" string is displayed instead of the button.

// Utility function: Display the button "Send Email"
function send_email_button_html( $order, $order_id ) {
    $order_ready = $order->get_meta('Order_Ready');
    $email_sent  = $order->get_meta('email_sent');

    $allowed_statuses = ['driver-assigned', 'out-for-delivery'];

    if( in_array( $order->get_status(), $allowed_statuses ) && $order_ready === 'Yes' && $email_sent !== 'Yes' ) {
        printf('<div><button type="button" class="email-btn button button-primary" data-id="%d">%s</button>
        <div class="message-%d"></div></div>', $order_id, __("Send email"), $order_id );
    } elseif ( $email_sent === 'Yes' ) {
        printf('<div>%s</div>', __("Email sent"));
    }
}

// Utility function: Send the email to the driver
function send_email_to_driver( $order ){
    $from_name  = __('Oven Fresh'); // Reply-to from name
    $from_email = '[email protected]'; // Reply-to from email

    $driver_id  = $order->get_meta('lddfw_driverid');
    $driver     = wp_get_current_user( $driver_id );
    $mailer     = WC()->mailer(); // Load WC Mailer

    $headers    = 'Content-Type: text/html; charset=UTF-8'."\r\n";
    $headers   .= 'Reply-to: ' . $from_name . ' <' . $from_email . ">\r\n";

    $subject    = sprintf(__('Order no.%s ready for pickup'), $order->get_order_number());

    $message    = sprintf(__('Hello %s,<br><br> Order no.%s is now ready for pickup.'), $driver->display_name, $order->get_order_number());
    $message    = '<html><head></head><body><p>'.$message.'</p></body><html>';
    $message    = $mailer->wrap_message( __('Order ready for pickup'), $message );
 
    $email_sent = $mailer->send( $driver->user_email, $subject, $message, $headers ); // Send email to diver

    if ( $email_sent ) {
        $order->update_meta_data( 'email_sent', 'Yes' ); // Tag order
        $order->add_order_note( __('Email sent to the driver.') ); // Add an admin note to the order
        $order->save(); // Save to database
    } 
}

// Add a new column in admin order list
add_filter( 'manage_edit-shop_order_columns', 'order_column_send_email_driver' );
function order_column_send_email_driver( $columns ) {
    $new_columns = array();

    foreach ( $columns as $column_key => $column_label ) {
        if ( 'order_total' === $column_key ) {
            $new_columns['email_driver'] = __('Email driver', 'woocommerce');
        }
        $new_columns[$column_key] = $column_label;
    }
    return $new_columns;
}

// Display send email button as content for column in admin order list
add_action( 'manage_shop_order_posts_custom_column', 'order_column_send_email_button', 10, 2 );
function order_column_send_email_button( $column, $order_id ) {
    if ( $column === 'email_driver' ) {
        global $the_order;
        send_email_button_html( $the_order, $order_id );
    }     
}

// Display send email button in Single orders
add_action( 'woocommerce_admin_order_data_after_shipping_address', 'display_send_email_button_single_order' );
function display_send_email_button_single_order( $order ) {
    send_email_button_html( $order, $order->get_id() );
}

// WP Admin Ajax receiver: Trigger email and update order
add_action('wp_ajax_send_email_driver', 'send_email_driver_ajax');
function send_email_driver_ajax() {
    if (isset($_POST['order_id'])) {
        $order = wc_get_order(intval($_POST['order_id']));
        echo send_email_to_driver($order) ? '1' : '0';
    }
    wp_die(); // Exit silently (mandatory)
}

// jQuery Ajax
add_action('admin_footer', 'send_email_driver_js');
function send_email_driver_js() {
    global $pagenow, $typenow;

    if( in_array( $pagenow, ['edit.php', 'post.php'] ) && 'shop_order' === $typenow ) :
    ?>
    <script id="send-email-driver" type="text/javascript">
        jQuery(function($) {
            $('body').on('click', 'button.email-btn', function(e) {
                e.preventDefault();
                const btnSend = $(this),
                      orderID = btnSend.data('id');
                      
                $.ajax({
                    url:  '<?php echo admin_url( 'admin-ajax.php' ); ?>',
                    type: 'POST',
                    data: {
                        'action'  : 'send_email_driver',
                        'order_id': orderID,
                    },
                    success: function(response) {
                        if ( response ) {
                            btnSend.replaceWith('<small style="color:green;">Email just sent!</small>');
                        } else {
                            $('.message-'+orderID).html('<small style="color:green;font-weight:bold;">Email NOT sent!</small>').fadeIn().delay(2000).fadeOut();
                        }
                    },
                });
            });
        });
    </script>
    <?php
    endif;
}

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

Screenshot of the email sent:

enter image description here