php - Display custom product image on WooCommerce email notifications ← (PHP)

I am trying to modify the product images in the auto generated WooCommerce order e-mails. Note, I am trying to do this with hooks, rather than creating a modified e-mail template.

To start, I have a hidden input on the single product page. I have some JS that sets the ID of the image, which is based on the product's colour (a custom attribute I made with ACF).

<input class="js-col-img-id" type="hidden" name="product-col-img-id" value="">

For reference, here's what I've done to get this to work on the cart page:

// Add custom attributes to cart item data
add_action('woocommerce_add_cart_item_data', 'jwd_add_custom_attr_to_cart', 10, 3);

function jwd_add_custom_attr_to_cart($cart_item_data, $product_id, $variation_id) {
    $attrs = array(...,'product-col-img-id');

    foreach ($attrs as $attr) {
        $san_attr = filter_input( INPUT_POST, $attr );

        if ( !empty( $san_attr ) ) {
            $cart_item_data[$attr] = $san_attr;
        }
    }

    return $cart_item_data;
}

// This function sets the image ID in the cart, and it displays the image properly
add_action( 'woocommerce_before_calculate_totals', 'bwa_new_price' );
function bwa_new_price($cart) {

    // ...

    $cart_items = $cart->get_cart();

    foreach($cart_items as $item) {
        $data = $item['data'];

        // product-col-img-id is sent through the hidden input when the add to cart form is submitted
        $colour_img_ID = $item['product-col-img-id'] ?? false;

        if ($colour_img_ID) {
            $data->set_image_id($colour_img_ID);
        }
    }
}

// Add custom attributes to order
add_action( 'woocommerce_checkout_create_order_line_item', 'jwd_add_attr_to_order_items', 10, 4 );
function jwd_add_attr_to_order_items( $item, $cart_item_key, $values, $order ) {
    if ( !empty( $values['product-colour'] ) ) {
        $item->add_meta_data( 'Colour', $values['product-colour'] );
    }

    // I tried replicating this for the img ID. It does display it in the var dump mentioned below, and it does display it as an actual label in the e-mail (which I'd want to get rid of). The difficulty then becomes reading the ID through code and setting the product to display that image
    if ( !empty( $values['product-col-img-id'] ) ) {
        $item->add_meta_data( 'col_img_id', $values['product-col-img-id'] );
    }
}

That works fine, but I'm having difficulty replicating this in the order e-mail. So far I've come across the following. This shows images in the e-mail, but it's the product's featured image. Of note is the "show_image" key being set to true.

// Add prod IMG to e-mails
function jwd_add_images_woocommerce_emails( $output, $order ) {

    // set a flag so we don't recursively call this filter
    static $run = 0;

    // if we've already run this filter, bail out
    if ( $run ) {
        return $output;
    }

    $args = array(
        'show_image'    => true,
        //'image_size'    => array( 300, 300 ),
    'image_size' => 'full',
    );

    // increment our flag so we don't run again
    $run++;

    // if first run, give WooComm our updated table
    return wc_get_email_order_items($order, $args);
}
add_filter( 'woocommerce_email_order_items_table', 'jwd_add_images_woocommerce_emails', 10, 2 );

To modify the image, I found this filter, but I'm just having a difficult time figuring out what I need to do to replicate what I've done on the cart page. The closest I've got is having $item_data work, and I do see the product-col-img-id key in the var dump, though it's in a protected object, which I'm not sure how to access. Even if I could access, I'm not sure how I could even set the image from here.

add_filter('woocommerce_order_item_thumbnail', 'jwd_add_colour_img', 10, 2);
function jwd_add_colour_img($image, $item) {
    $item_id = $item->get_id();

    //var_dump($item->get_current_data());

    $product = $item->get_product();
    $product_id = $item->get_product_id();
    $item_data = $item->get_data();
    $col_img_id = false;

    $item->set_image_id(1);

    foreach ($item_data as $key => $item) {
        //current_data

            var_dump($item);




        //echo "<br><br>";
        $col_img_id = $item['product-col-img-id'] ?? false;

        if ($col_img_id) {
            break;
        }
    }

    //var_dump($col_img_id);
    //$item_id = $item->get_product_id();
    //var_dump(wc_get_order_item_meta( $item_id, 'col_img_id', true ) );

    return $image;
}

Answer



Solution:

To get WooCommerce custom meta data, you can use WC_Data method get_meta().

Try the following instead to display your custom image on email notifications:

// Save custom image ID as order item meta
add_action( 'woocommerce_checkout_create_order_line_item', 'save_custom_image_id_to_order_item', 10, 4 );
function save_custom_image_id_to_order_item( $item, $cart_item_key, $values, $order ) {
    if ( isset($values['product-colour']) && ! empty($values['product-colour']) ) {
        $item->add_meta_data('Colour', $values['product-colour'] );
    }

    if ( isset($values['product-col-img-id']) && ! empty($values['product-col-img-id']) ) {
        $item->add_meta_data('_col_img_id', $values['product-col-img-id'] );
    }
}

// (optional) Force display item image on emails
add_filter( 'woocommerce_email_order_items_args', 'show_image_on_email_notifications' );
function show_image_on_email_notifications( $args ) {
    $args['show_image'] = true;

    return $args;
}

// Display custom image on emails
add_filter( 'woocommerce_order_item_thumbnail', 'display_email_order_item_custom_image', 10, 2 );
function display_email_order_item_custom_image( $image, $item ) {
    // Only on email notifications
    if( is_wc_endpoint_url() )
        return $image;

    $image_id = $item->get_meta('_col_img_id');
    
    if( $image_id ) {
        $image = wp_get_attachment_image( $image_id, array( 32, 32 ), false, array() );
    }

    return $image;
}

Code goes in functions.php file of the active child theme (or active theme). It should work.

Source