WooCommerce New Bulk Action Part 2

Ok so in Part 1 I said I wasn’t going to use the email function so removed it from the code I used from http://www.niepes.com/web/how-to-create-a-custom-order-status-in-woocommerce/

Clearly I need to think ahead a bit more. Over the last few weeks I’ve had a ton of sales, and I’m preparing everything to be ready to send them out as soon as I receive them from the supplier. Unfortunately our supplier contact me and advised there’s a few days delay on one product and about 10 days delay on another.

So I now need to mass mail people telling them.

I did look at using elasticemail to mass mail, but there’s a whole thing in their templates gearing towards marketing mails and opt out information. This isn’t a marketing mail it’s part of the transaction, I could live with giving it some opt out links. but what I really need is to be able to mail merge the order information into the mail.

So I quickly gave up on using elastcmail’s campaign function. I still use them as my mail relay and they’ve been very good, and support has been top notch for the few questions I’ve had.

Anyway, I thought back to the code for adding bulk actions and remembered there was an email function. So I checked out the code again, and yep it should be able to do what I need.

I decided to do things a little differently though.

First I create 2 new order status using JetPack (you can code this but it’s easier to just type and submit in jetpack) :

I’m going to be bulk assigning every order I want emailed to stock-email, anything that fails (wp-mail does fail) will go to stock-email-fail. This is the bit that wasn’t in the orginal code.

I also want to pass the orderid and name into the mail function. I could just have the mail function go get them, but it already queries the email address in the change_order_status function so I may as well keep it there.

Here’s my new Code.

//added for woocommerce bulk actions.
add_action('admin_footer-edit.php', 'custom_bulk_admin_footer');
function custom_bulk_admin_footer() {
 global $post_type;
 if($post_type == 'shop_order') {
 <script type="text/javascript">
 jQuery(document).ready(function() {
 //printing status
 jQuery('<option>').val('printing').text('<?php _e('Mark as Printing')?>').appendTo("select[name='action']");
 jQuery('<option>').val('printing').text('<?php _e('Mark as Printing')?>').appendTo("select[name='action2']");

 //stock status
 jQuery('<option>').val('stock').text('<?php _e('Mark as Awaiting Stock')?>').appendTo("select[name='action']");
 jQuery('<option>').val('stock').text('<?php _e('Mark as Awaiting Stock')?>').appendTo("select[name='action2']");

 //stock status
 jQuery('<option>').val('stock-emailed').text('<?php _e('Mark as Awaiting Stock Emailed')?>').appendTo("select[name='action']");
 jQuery('<option>').val('stock-emailed').text('<?php _e('Mark as Awaiting Stock Emailed')?>').appendTo("select[name='action2']");
add_action('load-edit.php', 'custom_bulk_action');
function custom_bulk_action() {
 global $typenow;
 $post_type = $typenow;

 if($post_type == 'shop_order') {
 $wp_list_table = _get_list_table('WP_Posts_List_Table');
 $action = $wp_list_table->current_action();
 $allowed_actions = array("stock","printing","stock-emailed");
 if(!in_array($action, $allowed_actions)) return;

 if(isset($_REQUEST['post'])) {
 $orderids = array_map('intval', $_REQUEST['post']);

 switch($action) {
 case "printing":
 foreach( $orderids as $orderis ) {
 change_order_status($orderid, $action);
 case "stock":
 foreach( $orderids as $orderid ) {
 change_order_status($orderid, $action);
 case "stock-emailed":
 foreach( $orderids as $orderid ) {
 change_order_status($orderid, $action);
 default: return;

 $sendback = admin_url( "edit.php?post_type=$post_type&success=1" );
function change_order_status($orderid, $action) {
 $order = new WC_Order($orderid);
 if(($action=='printing') && ($order->status!='printing')) {
 $order->update_status('printing', '');
 if(($action=='stock') && ($order->status!='stock')) {
 $order->update_status('stock', '');
 if(($action=='stock-emailed') && ($order->status!='stock-emailed')) {
 $email = get_post_meta( $orderid, '_billing_email' )[0];
 $name = get_post_meta( $orderid, '_billing_first_name')[0];
 $name = ucwords($name);
 if (send_this($email,$orderid,$name)) {
 $order->update_status('stock-emailed', '');
 } else {
 $order->update_status('stock-email-fail', '');
add_action('admin_notices', 'custom_bulk_admin_notices');
function custom_bulk_admin_notices() {
 global $post_type, $pagenow;
 if( $post_type == 'shop_order' && isset($_GET['success']) ) {
 echo '<div class="updated"><p>The orders have been successfully update!</p></div>';
function send_this($email,$orderid,$name) {

 $headers = 'From: Shop <[email protected]>' . "\r\n";
 $headers .= "MIME-Version: 1.0\r\n";
 $headers .= "Content-Type: text/html; charset=ISO-8859-1\r\n";

 $subject = 'Order Update';

 $message = '

 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
 Order Update: #' . $orderid . '
 <body leftmargin="0" marginwidth="0" topmargin="0" marginheight="0" offset="0">
 <div style=" background-color: #f5f5f5; width:100%; -webkit-text-size-adjust:none !important; margin:0; padding: 70px 0 70px 0;">
 <table border="0" cellpadding="0" cellspacing="0" height="100%" width="100%">
 <td align="center" valign="top">
 <div id="template_header_image">
 <table border="0" cellpadding="0" cellspacing="0" max-width="600" id="template_container" style=" box-shadow:0 0 0 3px rgba(0,0,0,0.025) !impo$
 <td align="center" valign="top">
 <!-- Header -->
 <table border="0" cellpadding="0" cellspacing="0" width="100%" id="template_header" style=" background-color: #557da1; color: #ffffff;$
 <h1 style=" color: #ffffff; margin:0; padding: 28px 24px; text-shadow: 0 1px 0 #7797b4; display:block; font-family:Arial; font$
 Order: #' . $orderid . ' Update
 <!-- End Header -->
 <td align="center" valign="top">
 <!-- Body -->
 <table border="0" cellpadding="0" cellspacing="0" width="600" id="template_body">
 <td valign="top" style=" background-color: #fdfdfd; border-radius:6px !important;">
 <!-- Content -->
 <table border="0" cellpadding="20" cellspacing="0" width="100%">
 <td valign="top">
 <div style=" color: #737373; font-family:Arial; font-size:14px; line-height:150%; text-align:left;">
 Hi ' . $name . ',
 Thank you 


 return wp_mail( $email, $subject, $message, $headers );

I haven’t include the full email above, just a snip so you can see where I put the orderid and name. The actual template I’ve used is one off woocommerce itself to keep the look of the emails the same as an order progress.

To get the mails flowing just select a bunch of orders and bulk change them to ‘Mark as Awaiting Stock Emailed’. This happily looped through 250 at a time on my system. After doing over 3,000 I only had 14 moved automatically to the failed status, and rerunning them didn’t cause any problems.

The one issue I did run into was the name of the failed status, originally I had it set as stock-emailed-fail. But there’s a limit on the number of characters you can use and it came into the system as stock-emailed-fai. I managed to loose 3 orders in the first test batch, as they were now assigned a status that didn’t exist. So I had to find them in the database and set them to the proper status. If you keep your slugs short, you shouldn’t see this issue. but make sure you also type the exactly the same in the code as they appear in jetpack.

I take no responsibility for any lost orders as a result of using this code.

One thought on “WooCommerce New Bulk Action Part 2”

Leave a Reply

Your email address will not be published. Required fields are marked *