1
votes

I'm building a woocommerce shop to sell antique maps, both originals and digital prints. The maps therefore are set as two variations of the same product: "Original" and "Print". "Original" is just the original antique map but "Print" has a load of options such as framing, mounting and print size and these are set by the user in the single-product page using jquery.

I've succeeded in allowing users to choose from a series of options in the single product page and thereby dynamically generate a price for the product they're buying based on what size, quantity, framing and mounting options they select.

This is done using jquery and the options (including the price) are passed to the cart using hidden fields and custom data as follows, where isset($_REQUEST['price']) refers to the hidden price field set by jquery (thwre are a load of these for framing, mounting, size etc but this gives an idea:

if(isset($_REQUEST['price']) && ! empty( 'price' )) {

    $order_item_price = sanitize_text_field($_REQUEST['price']);

    $cart_item_data['custom_data']['order_price'] = array(
      'label' => 'Total this item',
      'value' => '£' . $order_item_price
    );
}

...this works fine. The price and total price (along with other custom information about the product) are displayed in the cart and the total at the bottom of the cart tallies with the product prices. I use this function to achieve this:

function update_price_in_cart( $cart_obj ) {
    if ( is_admin() && ! defined( 'DOING_AJAX' ) ) {
        return;
    }
    if( ! is_cart() ) {
        return;
    }  
    // Iterate through each cart item
    foreach( $cart_obj->get_cart() as $item_key=>$cart_item ) {

        if( isset( $cart_item['total_price'] ) || isset( $cart_item['total_price_original'] ) ) {
            $price = $cart_item['total_price'] + $cart_item['total_price_original'];
            $cart_item['data']->set_price( ( $price ) );
        }
    }
}
add_action( 'woocommerce_before_calculate_totals', 'update_price_in_cart', 10, 1 );

The problem is when the user proceeds to the checkout. All the data created using hidden fields (frame type, mount type, size, price) displays on the left side of the page under where it says product but the totals on the right next to each product ordered are set to the original price set for the variation 'Print' set in the woocommerce product in wordpress.

I've tried up dating using something like this (the below is a test using static values):

function update_price_in_checkout($cart_obj) {

    if ( is_admin() && ! defined( 'DOING_AJAX' ) )
        return;

    var_dump($cart_item_data['custom_data']['order_price']);

    if( isset( $cart_item['total_price'] ) || isset( $cart_item['total_price_original'] ) ) {
         WC()->cart->total = 597;
    } else {
        WC()->cart->total = 1;
    }
}
add_action( 'woocommerce_review_order_before_order_total', 'update_price_in_checkout' );

...but a. this only accepts a static number as it doesn't pick up the hidden fields and b. it doesn't touch the individual product prices on the right of the checkout.

In summary - I need to find a way to replace the base variation product price on which is appearing on the right with the calculated totals based on user input. It all works fine in the cart page but doesn't transfer to the checkout page.

Delving through stackoverflow I think setting it in woocommerce_checkout_create_order_line_item might be an idea but I can't work out how to do this.

Any ideas?

1

1 Answers

1
votes

The following code will add as custom to cart item data the price of your product select options (from the hidden product field) and will update the cart item price:

// Get custom field value, calculate new item price, save it as custom cart item data
add_filter( 'woocommerce_add_cart_item_data', 'add_custom_field_data', 20, 3 );
function add_custom_field_data( $cart_item_data, $product_id, $variation_id ) {
    if (isset($_REQUEST['price']) && !empty($_REQUEST['price'])) {
        $cart_item_data['custom_price'] = sanitize_text_field($_REQUEST['price']);
        $cart_item_data['unique_key']   = md5(microtime().rand());
    }
    return $cart_item_data;
}

// Update price
add_action( 'woocommerce_before_calculate_totals', 'update_price_in_cart', 10, 1 );
function update_price_in_cart( $cart ) {
    if ( is_admin() && ! defined( 'DOING_AJAX' ) )
        return;

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

    // Loop through cart items
    foreach( $cart->get_cart() as $cart_item ) {
        if( isset( $cart_item['custom_price'] ) ) {
            // Add options to the product price
            $cart_item['data']->set_price( $cart_item['data']->get_price() + $cart_item['custom_price'] );
        }
    }
}

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