1

The first part of the question is HERE.

I need to get a list of items from a suborder that have received the status 'shipped' or 'readytocollect' inside $message_body = .

To do this, I was advised to use $order->get_items() in a foreach loop, as described HERE.

The problems are:

  1. I only manage to receive 1 item from my order. If there are 2 or more items in an order, I still receive 1 item in the letter. those. I only get: gold ring, when to order: Gold ring, chain, glasses

  2. How can I get each product's image?

Any help is really appreciated.

// Enable custom statuses for WooCommerce Orders
add_action('init', 'register_custom_order_statuses');
function register_custom_order_statuses() {
    register_post_status('wc-shipped', array(
        'label' => __( 'Shipped', 'woocommerce' ),
        'public' => true,
        'exclude_from_search' => false,
        'show_in_admin_all_list' => true,
        'show_in_admin_status_list' => true,
        'label_count' => _n_noop('Shipped <span class="count">(%s)</span>', 'Shipped <span class="count">(%s)</span>')
    ));
    register_post_status('wc-readytocollect', array(
        'label' => __( 'Ready to collect', 'woocommerce' ),
        'public' => true,
        'exclude_from_search' => false,
        'show_in_admin_all_list' => true,
        'show_in_admin_status_list' => true,
        'label_count' => _n_noop('Ready to collect <span class="count">(%s)</span>', 'Ready to collect <span class="count">(%s)</span>')
    ));
}

// Add a custom order status to list of WC Order statuses
add_filter('wc_order_statuses', 'add_custom_order_statuses');
function add_custom_order_statuses($order_statuses) {
    $new_order_statuses = array();

    // add new order status before processing
    foreach ($order_statuses as $key => $status) {
        $new_order_statuses[$key] = $status;
        if ('wc-processing' === $key) {
            $new_order_statuses['wc-shipped']        = __('Shipped', 'woocommerce' );
            $new_order_statuses['wc-readytocollect'] = __('Ready to collect', 'woocommerce' );
        }
    }
    return $new_order_statuses;
}

// Send custom email notifications to sub orders only
add_action( 'woocommerce_order_status_changed', 'custom_order_statuses_email_notifications', 10, 4 );
function custom_order_statuses_email_notifications ($order_id, $from_status, $to_status, $order) {
    // Targeting sub-orders only
    if ( ! $order->get_parent_id() ) return;

    if ( $to_status === 'shipped' ) {
        $status_label  = __( 'shipped', 'woocommerce' );
        $status_label_soobshenie  = __( 'shipped', 'woocommerce' );
    } 
    elseif ( $to_status === 'readytocollect' ) {
        $status_label  = __( 'readytocollect', 'woocommerce' );
        $status_label_soobshenie  = __( 'readytocollect', 'woocommerce' );
    }

    if ( isset($status_label) ) {
        $mailer        = WC()->mailer(); // load the mailer class.
        $email_subject = sprintf( __( 'readytocollect %s %s' ), $order->get_order_number(), $status_label );

// get an instance of the WC_Order object

foreach( $order->get_items() as $item_id => $item ){
    $product_name  = $item['name']; // The product name
    $item_qty      = $item['quantity']; // The quantity
    $line_total     = $item['subtotal']; // or $item['line_subtotal'] 

        $message_body  = '<html>
        <head></head>
        <body>
            <h1>'.$status_label.'</h1>
            <p>'.$status_label_soobshenie.'</p>
            <p></p>
            <table class="td" cellspacing="0" cellpadding="4"  style="width: 100%; color: #001a34; font-size: 14px; font-weight: normal;" border="0">
                    <thead>
                        <tr>

                            <th width="65%" class="td" style="text-align:left;" scope="col" >'.$product_name.'</th>
                            <th width="10%" class="td" style="text-align:right;" scope="col" >'.$item_qty.'</th>
                            <th width="25%" class="td" style="text-align:right;" scope="col" >'.$line_total.'</th>
                        </tr>
                </table>
        </body>
        </html>'; }
        $message = $mailer->wrap_message( $email_subject, $message_body );
        $mailer->send( $order->get_billing_email(), $email_subject, $message ); // Send email

}
}

2 Answers 2

2

The following will show all suborder items (I have added the product image):

// Send custom email notifications to sub orders only
add_action( 'woocommerce_order_status_changed', 'custom_order_statuses_email_notifications', 10, 4 );
function custom_order_statuses_email_notifications ($order_id, $from_status, $to_status, $order) {
    // Targeting sub-orders only
    if ( ! $order->get_parent_id() ) return;

    if ( $to_status === 'shipped' ) {
        $status_label  = __( 'shipped', 'woocommerce' );
        $status_label_message  = __( 'shipped', 'woocommerce' );
    } 
    elseif ( $to_status === 'readytocollect' ) {
        $status_label  = __( 'readytocollect', 'woocommerce' );
        $status_label_message  = __( 'readytocollect', 'woocommerce' );
    }

    if ( isset($status_label) ) {
        $mailer        = WC()->mailer(); // load the mailer class.
        $email_subject = sprintf( __( 'Order %s %s' ), $order->get_order_number(), $status_label );

        $message_body = '<html><head></head>
        <body>
            <h1>'.$status_label.'</h1>
            <p>'.$status_label_message.'</p>
            <p></p>
            <table class="td" cellspacing="0" cellpadding="4"  style="width: 100%; color: #001a34; font-size: 14px; font-weight: normal;" border="0">
            <thead>';
        
        foreach( $order->get_items() as $item ){
            $product = $item->get_product(); // Get product
            $image   = $product->get_image(array( 32, 32 )); // Get product image 32 x 32 px

            $message_body .= '<tr>
                <th width="65%" class="td" style="text-align:left;" scope="col" >'.$image.' '.$item->get_name().'</th>
                <th width="10%" class="td" style="text-align:right;" scope="col" >'.$item->get_quantity().'</th>
                <th width="25%" class="td" style="text-align:right;" scope="col" >'.$item->get_total().'</th>
            </tr>';
        }

        $message_body .= '</thead></table>
        </body></html>';

        $message = $mailer->wrap_message( $email_subject, $message_body );
        $mailer->send( $order->get_billing_email(), $email_subject, $message ); // Send email
    }
}

It should work as expected.

Related: Get Order items and WC_Order_Item_Product in WooCommerce 3

Sign up to request clarification or add additional context in comments.

1 Comment

You have helped me many times already. Thank you, Wizard!
-1

you're overwriting the $message_body variable inside the foreach loop, which causes it to only contain the last item in the loop. use

$message_body .= '<table>......</table>'

to get each product's image, you can use the wp_get_attachment_image_src() that will return the product image URL

here is sample foreach loop

foreach ($order->get_items() as $item_id => $item) {
    $product      = $item->get_product();
    $product_name = $product->get_name(); // The product name
    $item_qty     = $item->get_quantity(); // The quantity
    $line_total   = $item->get_total(); // or $item->get_subtotal()

    // Get the product image URL
    $product_image_url = '';
    $product_image_id  = $product->get_image_id();
    if ($product_image_id) {
        $image_data = wp_get_attachment_image_src($product_image_id, 'full');
        if ($image_data) {
            $product_image_url = $image_data[0];
        }
    }

    // Concatenate item details to the message body
    $message_body .= '
        <table class="td" cellspacing="0" cellpadding="4" style="width: 100%; color: #001a34; font-size: 14px; font-weight: normal;" border="0">
            <thead>
                <tr>
                    <th width="15%" class="td" style="text-align:left;" scope="col"><img src="' . $product_image_url . '" alt="' . $product_name . '" width="100"></th>
                    <th width="50%" class="td" style="text-align:left;" scope="col">' . $product_name . '</th>
                    <th width="10%" class="td" style="text-align:right;" scope="col">' . $item_qty . '</th>
                    <th width="25%" class="td" style="text-align:right;" scope="col">' . $line_total . '</th>
                </tr>
            </thead>
        </table>';
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.