2
votes

In WooCommerce, with this code, i'm using product custom fields to add some custom metadata to order items when making a purchase. I also need to auto add some of this custom metadata to the customer Order Notes (basically so it gets sent to my shipping fulfillment service).

Below is the code i'm currently using:

add_action('woocommerce_checkout_create_order', 'before_checkout_create_order', 20, 2);
function before_checkout_create_order( $order, $data ) {

    $items_in_order=array();

    foreach( $order->get_items() as $item_id => $item ) {

        $product = $order->get_product_from_item( $item );

        $text = $product->get_sku();

        $bags_count = array(
            'neutral_bags' => 0,
            'bright_bags' => 0,
            'pastel_bags' => 0,
            'reg_tendons' => 0,
            'gid_tendons' => 0
        );

        $meta_key1  = __('Neutral Bags', 'woocommerce');
        $meta_key2  = __('Bright Bags', 'woocommerce');
        $meta_key3  = __('Pastel Bags', 'woocommerce');
        $meta_key4  = __('Reg Tendons', 'woocommerce');
        $meta_key5  = __('GID Tendons', 'woocommerce');

        $bags_count['neutral_bags'] += wc_get_order_item_meta( $item_id, $meta_key1, true );
        $bags_count['bright_bags']  += wc_get_order_item_meta( $item_id, $meta_key2, true );
        $bags_count['pastel_bags']  += wc_get_order_item_meta( $item_id, $meta_key3, true );
        $bags_count['reg_tendons']  += wc_get_order_item_meta( $item_id, $meta_key4, true );
        $bags_count['gid_tendons']  += wc_get_order_item_meta( $item_id, $meta_key5, true );

        $text .= ' | ' . $bags_count['neutral_bags'];
        $text .= ' | ' . $bags_count['bright_bags'];
        $text .= ' | ' . $bags_count['pastel_bags'];
        $text .= ' | ' . $bags_count['reg_tendons'];
        $text .= ' | ' . $bags_count['gid_tendons'];

        array_push( $items_in_order , $text );

    }

    $text = implode('<br/>', $items_in_order );

    // get customer note
    $note = $order->get_customer_note();

    // Merging existing customer note with bags count (if it exist)
    $note = empty( $note ) ? $text : $note . '<br/>' . $text . ' V1';

    // Set the new customer note before saving
    $order->set_customer_note( $note );

}

As per the below screenshot, you'll see the data is saved to the product, but doesn't get pulled into the order notes section correctly.

Any ideas why this might be?

enter image description here

1

1 Answers

2
votes

As this is related to your other question and my answer there, so the meta keys are a bit different:

  • neutral_bag_count meta key is replaced by: Neutral Bags,
  • bright_bag_count meta key is replaced by: Bright Bags.

Update: I have revisited completely all your existing code, avoiding repetitions, making it more effective and compact.

I have set your custom fields keys and labels in a function that I call in all other hooked functions and I use foreach loops everywhere now. If you want to change a label, you will do it just once in this utility function.

The new code:

// Utility function (keys + translatable labels)
function bags_and_sheets_labels_keys(){
    $domain = 'woocommerce';
    return array(
        'neutral_bag' => __('Neutral Bags', $domain),
        'bright_bag'  => __('Bright Bags', $domain),
        'pastel_bag'  => __('Pastel Bags', $domain),
        'reg_tendon'  => __('Regular Tendon Sheets', $domain),
        'gid_tendon'  => __('GID Tendon Sheets', $domain),
    );
}

// Add custom fields to single product pages
add_action( 'woocommerce_before_add_to_cart_button', 'add_custom_fields_single_product', 20 );
function add_custom_fields_single_product(){
    global $product;
    $bags = bags_and_sheets_labels_keys();
    ?>
        <div class="product-custom-fields">
            <?php foreach($bags as $key => $value ): ?>
            <input type="text" placeholder="<?php echo $value; ?>" name="<?php echo $key; ?>">
            <?php endforeach; ?>
        </div>
        <div class="clear"></div>
    <?php
}

// Save custom fields to cart object
add_filter( 'woocommerce_add_cart_item_data', 'save_custom_fields_cart_item_data', 10, 2 );
function save_custom_fields_cart_item_data( $cart_item_data, $product_id ){
    $bags = bags_and_sheets_labels_keys();
    foreach($bags as $key => $value ):
        if(isset($_POST[$key]))
            $cart_item_data['custom_data'][$key] = sanitize_text_field($_POST[$key]);
    endforeach;

    $cart_item_data['custom_data']['unique_key'] = md5( microtime().rand() );
    WC()->session->set( 'custom_data', $cart_item_data['custom_data'] );
    return $cart_item_data;
}

// Display custom fields in cart items (cart and checkout pages)
add_filter( 'woocommerce_get_item_data', 'display_custom_fields_cart_item_data', 10, 2 );
function display_custom_fields_cart_item_data($item_data, $cart_item){
    if( ! array_key_exists( 'custom_data', $cart_item ) )
        return $item_data;

    $bags = bags_and_sheets_labels_keys();
    foreach($bags as $key => $value ):
        if( array_key_exists( $key, $cart_item['custom_data'] ) )
            $item_data[] = array(
                'key'   => $value,
                'value' => $cart_item['custom_data'][$key]
            );
    endforeach;
    return $item_data;
}

// Save and display custom fields in order item meta
add_action( 'woocommerce_add_order_item_meta', 'add_custom_fields_order_item_meta', 20, 3 );
function add_custom_fields_order_item_meta( $item_id, $cart_item, $cart_item_key ) {
    $bags = bags_and_sheets_labels_keys();
    foreach($bags as $key => $meta_key_label ):
        if( array_key_exists($key, $cart_item['custom_data']) )
            wc_update_order_item_meta( $item_id, $meta_key_label, $cart_item['custom_data'][$key] );
    endforeach;
}

// Add products SKUs and cutom fields as formated data in customer note
add_action('woocommerce_checkout_update_order_meta', 'after_checkout_create_order', 20, 2);
function after_checkout_create_order( $order_id, $data ) {
    $skus = $counts = $output = array();
    $bags  = bags_and_sheets_labels_keys();

    // Get the WC_Order Object (instance)
    $order = wc_get_order($order_id);

    // Loop through order items
    foreach( $order->get_items() as $item_id => $item ) {
        $product = $item->get_product();
        $skus[] = $product->get_sku(); // Set SKUs in an array
        // Add metakeys to the array (if they exist)
        foreach( $bags as $meta_key_label ){
            $item_meta = wc_get_order_item_meta( $item_id, $meta_key_label, true );
            if( ! empty($item_meta) ){
                $counts[$meta_key_label] += $item_meta;
                $count = true;
            }
        }
    }
    // Add Products SKUs
    $text = __('Products SKUs', 'woocommerce') . ': ' . implode(' - ', $skus ). ' | ';

    // Get each custom item meta data count (if they exist)
    if( isset($count)){
        foreach( $counts as $key_label => $value ){
            $output[] = $key_label . __(' count: ', 'woocommerce') . $value;
        }
        // Format all data as a text string
        $text .= implode(' - ', $output );
    }
    // Get customer note
    $note = $order->get_customer_note();
    // Merging existing customer note with bags count (if it exist)
    $note = empty( $note ) ? $text : $note . '<br/>' . $text;
    // Set the new customer note before saving
    $order->set_customer_note( $note );
    $order->save();
}

Code goes in function.php file of the active child theme (or active theme).

Tested and works as expected.

enter image description here