Save and display selected product option and cost as cart item data in WooCommerce

The following revisited code will change cart item subtotal to the calculated sum of product + color option and will reflect this change to cart totals. It will save the option as order item meta data, when order is placed.

The code:

// Display Select field before add to cart button
add_action( 'woocommerce_before_add_to_cart_button', 'colors_options_before_add_to_cart_button' );
function colors_options_before_add_to_cart_button() {
    global $product;

    // Only on simple products
    if( ! $product->is_type('simple') ) return;

    $colors = $product->get_attribute( 'color' );

    // When product colors are available
    if ( ! empty($colors) && $color_price = $product->get_meta('avp-ral-paint-price') ) :

    $options  = array( '' => __("Choose your color") );

    foreach ( (array) explode( ',', $colors ) as $color ) {
        $options[$color] = $color;
    }

    echo '<p><strong>' . __("Standard Powder Coat") . ':</strong> ' . wc_price( $color_price ) .'</p>';

    woocommerce_form_field( 'color', array(
        'type'     => 'select',
        'class'    => array('form-row-wide product-color'),
        'label'    => __('Standard Colors'),
        'options'  => $options,
        'required' => true,
    ), '' );

    echo '<br>';
    endif;
}

// Color option validation
add_filter( 'woocommerce_add_to_cart_validation', 'filter_add_to_cart_validation', 10, 2 );
function filter_add_to_cart_validation( $passed, $product_id ) {
    $product = wc_get_product($product_id);

    if( $product->is_type('simple') && $product->get_attribute('color') &&
    $product->get_meta('avp-ral-paint-price') && isset($_POST['pa-color']) && empty($_POST['pa-color']) ) {
        wc_add_notice( __("Choose a Color (Mill for No Paint)", "woocommerce" ), 'error' );
        $passed = false;
    }
    return $passed;
}

// Add color option as custom cart item data (+ prices)
add_filter( 'woocommerce_add_cart_item_data', 'add_color_option_as_cart_item_data', 10, 2 );
function add_color_option_as_cart_item_data( $cart_item_data, $product_id ) {
    if( isset($_POST['color']) && ! empty($_POST['color']) ) {
        $product = wc_get_product($product_id);

        if( $color_price = $product->get_meta('avp-ral-paint-price') ) {
            $cart_item_data['color']         = esc_attr($_POST['color']);
            $cart_item_data['color-price']   = $color_price;
            $cart_item_data['default-price'] = wc_get_price_to_display($product);
            $cart_item_data['new-price']     = $product->get_price() + $color_price;
        }
    }
    return $cart_item_data;
}

// Display select color option on cart item
add_filter( 'woocommerce_get_item_data', 'display_color_option_on_cart_item', 10, 2 );
function display_color_option_on_cart_item( $cart_item_data, $cart_item ) {
    if ( isset($cart_item['color']) && isset($cart_item['color-price']) ){
        $cart_item_data[] = array(
            'name' => __('Color'),
            'value' => $cart_item['color'] . ' (' . wc_price($cart_item['color-price']) . ')',
        );
    }
    return $cart_item_data;
}

// Display the default product price (instead of the calculated one)
add_filter( 'woocommerce_cart_item_price', 'filter_cart_item_price', 10, 2 );
function filter_cart_item_price( $price, $cart_item ) {
    if ( isset($cart_item['color']) && isset($cart_item['default-price']) ){
        $price = wc_price($cart_item['default-price']);
    }
    return $price;
}

// Customizing cart item price subtotal
add_action( 'woocommerce_before_calculate_totals', 'set_cart_item_calculated_price', 10, 1 );
function set_cart_item_calculated_price( $cart ) {
    if ( is_admin() && ! defined( 'DOING_AJAX' ) )
        return;

    // Required since Woocommerce version 3.2 for cart items properties changes
    if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 )
        return;

    // Loop through cart items
    foreach ( $cart->get_cart() as $cart_item ) {
        // Set the new calculated price
        if( isset($cart_item['color']) && isset($cart_item['new-price']) ) {
            $cart_item['data']->set_price( $cart_item['new-price'] );
        }
    }
}

// Save save color option as order item meta data (and display it everywhere)
add_filter( 'woocommerce_checkout_create_order_line_item', 'save_color_option_as_order_item_meta_data', 10, 4 );
function save_color_option_as_order_item_meta_data( $item, $cart_item_key, $cart_item, $order ) {
    if( isset($cart_item['color']) && isset($cart_item['color-price']) ) {
        $item->update_meta_data( 'pa_color', $cart_item['color'] . ' (' . wc_price($cart_item['color-price']) . ')' );
    }
    return $item;
}

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


On single Product page:

enter image description here


On cart page (and checkout):

enter image description here


On Orders pages (and email notifications):

enter image description here