You are not doing that in the right way and you need to rethink it differently…
Here is a complete example that will allow you to keep the default item price (product price) and to get a calculated cart item subtotal based on your "length" custom cart item data:
// For testing (example): Add a dropdown to product page for lenght
add_action( 'woocommerce_before_add_to_cart_button', 'add_lenght_custom_field');
function add_lenght_custom_field() {
echo '<div class="class_dropdown_length">
<label for="rope_length">Select a length</label>
<select id ="rope_length" name="rope_length">
<option value="">1 m</option>
<option value="5">5 m</option>
<option value="10">10 m</option>
<option value="25">25 m</option>
</select>
</div>';
}
// Add custom cart item data (lenght) on add to cart and calculate the new price
add_filter( 'woocommerce_add_cart_item_data', 'filter_woocommerce_add_cart_item_data', 10, 3 );
function filter_woocommerce_add_cart_item_data( $cart_item_data, $product_id, $variation_id) {
if( isset($_POST['rope_length']) && ! empty($_POST['rope_length']) ) {
$the_id = $variation_id > 0 ? $variation_id : $product_id;
$product = wc_get_product( $the_id );
$length = (float) esc_attr($_POST['rope_length']); // The chosen lenght
// Add the dropdown value as custom cart item data
$cart_item_data['custom'] = array(
'length' => $length, // The lenght value from custom field (if needed)
'price' => $product->get_price(), // The default product price
'new_price' => $product->get_price() * $length, // Calculated price from lenght
'unique_key' => md5(microtime().rand()), // Make each item unique
);
}
return $cart_item_data;
}
// Display the selected lenght value below cart item name
add_filter( 'woocommerce_cart_item_name', 'display_select_length_after_cart_item_name', 10, 3 );
function display_select_length_after_cart_item_name( $name, $cart_item, $cart_item_key ) {
if( is_cart() && isset($cart_item['custom']['length']) ) {
$name .= '<p>'.__("Lenght:") . ' ' . esc_html($cart_item['custom']['length']) . '</p>';
}
return $name;
}
// Display the default product price (instead of the calculated one)
add_filter( 'woocommerce_cart_item_price', 'filter_woocommerce_cart_item_price', 10, 3 );
function filter_woocommerce_cart_item_price( $product_price, $cart_item, $cart_item_key ) {
if( isset($cart_item['custom']['price']) ) {
$product_price = wc_price( wc_get_price_to_display( $cart_item['data'], array('price' => $cart_item['custom']['price']) ) );
}
return $product_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 based on lenght
if( isset($cart_item['custom']['new_price']) ) {
$cart_item['data']->set_price( $cart_item['custom']['new_price'] );
}
}
}
This code goes in function.php file of your active child theme (or active theme). Tested and works.
You can see that the product price is different that the custom calculated subtotal (price x length):
$cart_item
defined ? – Romain B.