2
votes

I am creating products that vary greatly in size and weight. I am not using WooCommerce product variants to help me with this as my products are heavily customized. I am using a third-party plugin to select from many variant options and I plan on checking these options to determine the products weight.

The issue is I want to set the product weight before the product is added to the cart. A shipping calculator on the cart will then calculate your shipping based off your cart's total weight (WooCommerce Weight Based Shipping).

I have tried 2 WooCommerce hooks pretty extensively to do this with no luck.

add_filter( 'woocommerce_add_cart_item_data', 'update_weight_on_add_to_cart', 10, 3);

and

add_action( 'woocommerce_add_to_cart', 'update_weight_on_add_to_cart', 10, 6 );

I am able to set custom fields using the add_filter. Doing this I am able to see that I successfully set the product weight to something new. BUT once I get to the cart page, the weight is reverted back to what is set on the edit product page.

This is the function I am currently using to check that:

function update_weight_on_add_to_cart( $cart_item_data, $product_id, $variation_id )
{
    $product = wc_get_product( $product_id );

    $weight1 = $product->get_weight();

    $product->set_weight(3.45);
    $weight2 = $product->get_weight();

    $cart_item_data['weight1'] = $weight1;
    $cart_item_data['weight2'] = $weight2;

    return $cart_item_data;
}

Then I display these fields on the cart to see if I changed the data successfully using the following hook and function. (I grabbed most of this from blog posts or other StackOverflow posts)

add_filter( 'woocommerce_get_item_data', 'display_weight', 10, 2 );
function display_weight( $item_data, $cart_item ) {
    $item_id = $cart_item['variation_id'];
    if($item_id == 0) $item_id = $cart_item['product_id'];
    $product_qty = $cart_item['quantity'];
    $product = wc_get_product($item_id);
    $weight3 = $product->get_weight();

    $item_data[] = array(
        'key'       => __('Weight3', 'woocommerce'),
        'value'     => wc_clean( $weight3 ),
        'display'   => ''
    );
     $item_data[] = array(
        'key'     => __( 'Weight1', 'woocommerce' ),
        'value'   => wc_clean( $cart_item['weight1'] ),
        'display' => ''
    );
     $item_data[] = array(
        'key'     => __( 'Weight2', 'woocommerce' ),
        'value'   => wc_clean( $cart_item['weight2'] ),
        'display' => ''
    );

    return $item_data;
}

My most recent effort using the above code resulted in the following on the cart page.

Weight3: 1

Weight1: 1

Weight2: 3.45

Any help would be appreciated! If this can't be done this way, is there a better way to approach this issue? Maybe this needs to be done on the cart?

1

1 Answers

3
votes

There is some errors, mistakes and missing part… Here it's the way to do it (for all products types including product variations):

// make and save a calculated weight as custom cart item data
add_filter( 'woocommerce_add_cart_item_data', 'add_weight_custom_cart_item_data', 10, 3 );
function add_weight_custom_cart_item_data( $cart_item_data, $product_id, $variation_id ){
    // For product variations handling
    $product_id = $variation_id > 0 ? $variation_id : $product_id;

    // Get an instance of the product object
    $product = wc_get_product( $product_id );

    // The default product weight
    $cart_item_data['weight']['default'] = $product->get_weight();

    ## ====> HERE YOU CAN MAKE YOUR WEIGHT CALCULATIONS <==== ##
    $new_weight_value = 3.45;

    // Set the new calculated weight
    $cart_item_data['weight']['new'] = 3.45;

    return $cart_item_data;
}

add_filter( 'woocommerce_get_item_data', 'display_cart_item_weight', 10, 2 );
function display_cart_item_weight( $item_data, $cart_item ) {
    if ( isset($cart_item['weight']) ) {
        // Display original weight
        if ( isset($cart_item['weight']['default']) ) {
            $item_data[] = array(
                'key'       => __('Weight (original)', 'woocommerce'),
                'value'     => wc_format_weight( $cart_item['weight']['default'] ),
            );
        }

        // Display calculated weight
        if ( isset($cart_item['weight']['new']) ) {
            $item_data[] = array(
                'key'     => __( 'Weight (new)', 'woocommerce' ),
                'value'   => wc_format_weight( $cart_item['weight']['new'] ),
            );
        }
    }
    return $item_data;
}

// Set the new weight in cart items
add_action( 'woocommerce_before_calculate_totals', 'set_custom_cart_item_weight', 25, 1 );
function set_custom_cart_item_weight( $cart ) {
    if ( is_admin() && ! defined( 'DOING_AJAX' ) )
        return;

    if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 )
        return;

    foreach( $cart->get_cart() as $cart_item ){
        if ( isset($cart_item['weight']['new']) ) {
            $cart_item['data']->set_weight($cart_item['weight']['new']);
        }
    }
}

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

enter image description here