Bad news first – we’ve seen how to add content to any WooCommerce order email, however I did not specify that if you use the [products] shortcode that’s not going to work unfortunately. The reason behind this, in plain English, is that… it just doesn’t work, and it outputs a weird list of “Sale!” list items (see screenshot below)!
So, I want to fix this, and find a WooCommerce email-compatible way to show a grid of products based on a list of product IDs (for example, the list of related products based on the ordered items), and make sure I can actually see product images, titles, prices and a link. Enjoy!
PHP Snippet: Display Related Products Grid @ WooCommerce Customer Processing Order Email
Note 1: you can target any WooCommerce email. Here, I’m adding content to the Customer Processing Order email, but you could do it on the Completed one only, or all of them. Check this guide to find out the email ID you should use in the snippet below.
Note 2: in the snippet I’m calculating the Related Products from the order items. You can use a custom list of product IDs instead if you wish – simply remove the $related calculations, and edit the foreach iterable_expression from “array_slice( $related, 0, $limit )” to “array( 123, 456, 789 )” where 123, 456 and 789 are the product IDs you want to show.
Note 3: I’m displaying 3 columns and 2 rows of products. Change $cols = 3 and $limit = 6 based on your requirements ($cols = 4 and $limit = 4 would give you 4 items in 1 row).
/**
* @snippet Product Grid @ WooCommerce Emails
* @how-to businessbloomer.com/woocommerce-customization
* @author Rodolfo Melogli, Business Bloomer
* @compatible WooCommerce 7
* @community https://businessbloomer.com/club/
*/
add_action( 'woocommerce_email_after_order_table', 'bbloomer_add_product_grid_specific_email', 20, 4 );
function bbloomer_add_product_grid_specific_email( $order, $sent_to_admin, $plain_text, $email ) {
if ( $email->id == 'customer_processing_order' ) {
$related = array();
foreach ( $order->get_items() as $item_id => $item ) {
$related = array_merge( wc_get_related_products( $item->get_product_id() ), $related );
}
if ( ! $related ) return;
shuffle( $related );
$related = array_unique( $related );
echo '<h2>Related Products</h2>';
$html = '';
$col = 1;
$cols = 3;
$limit = 6;
$html .= '<div><table style="table-layout:fixed;width:100%;"><tbody>';
foreach ( array_slice( $related, 0, $limit ) as $product_id ) {
$product = wc_get_product( $product_id );
$html .= ( $col + $cols - 1 ) % $cols === 0 ? '<tr>' : '';
$html .= '<td style="text-align:center;vertical-align:bottom">';
$html .= $product->get_image();
$html .= '<h3 style="text-align:center">' . $product->get_title() . '</h3>';
$html .= '<p>' . $product->get_price_html() . '</p>';
$html .= '<p><a href="' . get_permalink( $product_id ) . '">' . __( 'Read more', 'woocommerce' ) . '</a></p></td>';
$html .= $col % $cols === 0 ? '</tr>' : '';
$col++;
}
$html .= '</tbody></table></div>';
echo $html;
}
}
Looks pretty useful, thanks for sharing a straight-forward method for adding related products to WC emails. I am going to test it pretty soon although I am afraid that most of the people don’t really read those kind of emails carefully. Do you have any data if this works from marketing prospective?
You won’t know until you test and track it!
Hi, Thanks for this awesome idea.I have a question which is not so related to this topic. Would it be possible to create two (or three) different email formats for an order status email such as order completion?
The scenario is, we ship some products for same day delivery and some on next day. So we would like to use an email that says ‘your order arrives today’ to the same-day-delievry customers and ‘you order arrives tomorrow’ to the next-day-delivery customers. It would be perfect if we simply could choose the email with a check box. Just dreaming though 🙂
Hello Joice, thanks so much for your comment! Yes, this is definitely possible, but I’m afraid it’s custom work. If you’d like to get a quote, feel free to contact me here. Thanks a lot for your understanding!