2

Based on WooCommerce modify cart totals programmatically, im trying to get cart meta inside the 'woocommerce_cart_product_subtotal' filter hook, but I'm stuck. I've tried $a_variable = $cart_item['length']; , but it doesn't work.

Here's my code:

add_filter( 'woocommerce_cart_product_subtotal', 'filter_woocommerce_cart_product_subtotal', 10, 6); 
function filter_woocommerce_cart_product_subtotal( $product_subtotal, $product, $quantity, $instance) { 

$prisen = $product->get_price();
$rope_length =$cart_item['length'];
$product_subtotal = ($prisen*$rope_length)*$quantity;
return $product_subtotal; 
}; 

Does anyone have any ideas?

LoicTheAztec
  • 229,944
  • 23
  • 356
  • 399
Paudun
  • 287
  • 1
  • 6
  • 15

2 Answers2

2

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):

enter image description here

LoicTheAztec
  • 229,944
  • 23
  • 356
  • 399
  • You are a lifesaver <3 It works great. How much time do you typically spend on an answer like this? – Paudun Mar 20 '19 at 09:49
  • 1
    @Paudun It depends of my chaotic and capricious mind :) – LoicTheAztec Mar 20 '19 at 09:53
  • To make the item details like length show up on the checkout page I added it to $other_data[] = array(). But $other_data also displays on the cart page, so the item details like length shows up twice. Do you know how to hide $other_data on the cart_page? – Paudun Mar 20 '19 at 10:04
  • I guess I could just not add the length to the filter woocommerce_cart_item_name. – Paudun Mar 20 '19 at 10:22
  • Hi, i' trying to add an additionnal service with a specific price as a checkable option in the product page, Would you know how i can create a separate row for this service in cart tables and checkout order review table ? – jst Oct 11 '20 at 19:14
1
add_filter('woocommerce_cart_product_subtotal', 'filter_woocommerce_cart_product_subtotal', 10, 4);

function filter_woocommerce_cart_product_subtotal($product_subtotal, $product, $quantity, $cart) {

    $newproduct_subtotal = 0;
    $prisen = $product->get_price();
    $rope_length = $product->get_length();
    if ($prisen && $rope_length)
        $newproduct_subtotal += ($prisen * $rope_length) * $quantity;

    return ($newproduct_subtotal) ? wc_price($newproduct_subtotal) : $product_subtotal;
}
mujuonly
  • 11,370
  • 5
  • 45
  • 75
  • The subtotal on the cart page disappears when I try the code above. Just like in my on code in the question. – Paudun Mar 18 '19 at 10:49