Williams
Williams

Reputation: 451

Save product custom-field as custom order item metadata for WooCommerce admin manual orders

Using Pass custom product meta data to the order in Woocommerce 3 answer code, Is it possible to save and display custom metadata when the product is added manually from backend when creating orders manually from the backend?

That is my code (lightly changed):

// Admin products: Display custom Field
add_action( 'woocommerce_product_options_general_product_data', 'product_options_general_product_data_add_field' );
function product_options_general_product_data_add_field() {
    global $post;

    echo '<div class="options_group">';

    woocommerce_wp_select( array(
        'id'      => '_cost_centre',
        'label'   => __( 'Cost Centre', 'woocommerce' ),
        'options' => array(
            'MFEG'   => __( 'MFEG', 'woocommerce' ), // Default displayed option value
            'YDIT'   => __( 'YDIT', 'woocommerce' ),
        )
    ) );

    echo '</div>';
}

// Admin products: Save custom Field
add_action( 'woocommerce_process_product_meta', 'product_options_general_product_data_save_field' );
function product_options_general_product_data_save_field( $post_id ){
    if( isset( $_POST['_cost_centre'] ) )
        update_post_meta( $post_id, '_cost_centre', esc_attr( $_POST['_cost_centre'] ) );
}

// Order items: Save product "Cost centre" as hidden order item meta data
add_action('woocommerce_checkout_create_order_line_item', 'save_file_type_as_order_item_meta', 20, 4);
function save_file_type_as_order_item_meta($item, $cart_item_key, $values, $order) {
    if ( $cost_centre = $values['data']->get_meta('_cost_centre') ) {
        $item->update_meta_data( '_cost_centre', $cost_centre ); // Save as order item (visble on admin only)
    }
}

This works fine when the order is created by the client from the frontend. But when admin creates an order manually from the backend and adds the product, the custom metadata is not visible.

How to solve this problem for orders created manually, allowing to add product custom field as custom order item data?

Upvotes: 4

Views: 1377

Answers (1)

LoicTheAztec
LoicTheAztec

Reputation: 254448

Update 3

For manual backend orders, you can try to use woocommerce_before_save_order_item dedicated action hook as follow (code based on your question code):

add_action( 'woocommerce_before_save_order_item', 'action_before_save_order_item_callback' );
function action_before_save_order_item_callback( $item ) {
    $cost_centre = $item->get_meta('_cost_centre');
    // If custom meta data is not saved as order item
    if ( empty($cost_centre) ) {
        // Get custom meta data from the product
        $cost_centre = get_post_meta( $item->get_product_id(), '_cost_centre', true );
        $cost_centre = empty($cost_centre) ? 'MFEG' : $cost_centre;
        
        // Save it as custom order item (if defined)
        $item->update_meta_data( '_cost_centre', $cost_centre );
    }
}

Code goes in functions.php file of your active child theme (or active theme). Tested and works.


Addition: Make the order item custom meta data visible to customer

If you want this order item meta data to be visible on customer orders and email notifications, you will replace the order item meta key from '_cost_centre' to 'Cost centre' as follow:

add_action( 'woocommerce_before_save_order_item', 'action_before_save_order_item_callback' );
function action_before_save_order_item_callback( $item ) {
    $cost_centre = $item->get_meta('_cost_centre');
    // If custom meta data is not saved as order item
    if ( empty($cost_centre) ) {
        // Get custom meta data from the product
        $cost_centre = get_post_meta( $item->get_product_id(), 'Cost centre', true );
        $cost_centre = empty($cost_centre) ? 'MFEG' : $cost_centre;
        
        // Save it as custom order item (if defined)
        $item->update_meta_data( 'Cost centre', $cost_centre );
    }
}

This time it will be visible on customer orders and emails.

You will need also to change your last function on your question code to:

// Order items: Save product "Cost centre" as visible order item meta data
add_action('woocommerce_checkout_create_order_line_item', 'save_file_type_as_order_item_meta', 20, 4);
function save_file_type_as_order_item_meta($item, $cart_item_key, $values, $order) {
    if ( $cost_centre = $values['data']->get_meta('_cost_centre') ) {
        $item->update_meta_data( 'Cost centre', $cost_centre ); // Save as order item (visible everywhere)
    }
}

Note: When the order item custom meta key starts with an underscore, it's hidden.

Upvotes: 3

Related Questions