Search code examples
phpwordpresswoocommercehook-woocommercewoocommerce-bookings

Set prices based on WooCommerce Bookings duration


I have a scenario where I need to change the total rental price by adjusting the block cost of a booking based on its duration. Booking duration are customer defined blocks of 4 days.

For 4 days (minimum duration) = base cost + block cost For 8 days (maximum duration) = base cost + block cost + (block cost *0.75).

Based on Change price of product in WooCommerce cart and checkout answer code where I have made some changes. Here is my code:

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

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

    foreach ( $cart->get_cart() as $cart_item ){
        $booking_id = $cart_item['booking']['_booking_id'];
        $booking = get_wc_booking( $booking_id );
        $base_cost  = get_post_meta( $cart_item['product_id'], '_wc_booking_cost', true );
        $block_cost = get_post_meta( $cart_item['product_id'], '_wc_booking_block_cost', true );
        if ( $booking ) {
            $duration   = $cart_item['booking']['duration'];        
            if ($duration == 8) {
                $new_price = $base_cost +$block_cost + ($block_cost * 0.75);    //Calculate the new price           
                $cart_item['data']->set_price( $new_price ); // Set the new price
            }
        }       
    }
}

This works fine but I wonder if there's a way that I can set this permanently using an action such as woocommerce_bookings_pricing_fields so the discounted price gets displayed on the product page itself.


Solution

  • I managed to achieve it by programmatically adding a price range to bookable products:

    add_action( 'woocommerce_process_product_meta_booking', 'modify_product_costs', 100, 1 );
    
    function modify_product_costs( $product_id ){
      $product = wc_get_product( $product_id );
    
      // We check that we have a block cost before
      if ( $product->get_block_cost() > 0 ){
        // Set base cost
        $new_booking_cost = ( $product->get_block_cost() * 0.5 ) + 100;
    
        $product->set_cost( $new_booking_cost ); 
        $product->save(); // Save the product data
    
        //Adjust cost for 8 days
        $pricing = array(
        array(
        'type' => 'blocks',
        'cost' => 0.875,
        'modifier' => 'times',
        'base_cost' => $new_booking_cost,
        'base_modifier' => 'equals',
        'from' => 2,
        'to' => 2
        )
        );
    
        update_post_meta( $product_id, '_wc_booking_pricing', $pricing );
     }
    }
    

    When a product is saved after entering the block cost, it generates the base cost and adds a pricing line to give the desired outcome.

    enter image description here

    Inspirations came from here, here, here and here