Woocommerce change price by hook (or another way) from "Woocommerce bookings and appointments" plugin by luginhive.com

210 Views Asked by At

General background of my website

The website rent rooms based on hourly rental.

I use "WooCommerce Bookings And Appointments" plugin for my website. The plugin URL is https://www.pluginhive.com/product/woocommerce-booking-and-appointments/

The plugin support Cost Rules and I control prices for all hours. But I can't find solution for specific scenario.

My goal is to add rule that:

If customer choose time between 10PM to 10AM.

And the minimum order hours as bigger then 6 hours.

Then the price will be for 6 hours.

Sample room price

Booking Period set in general setting with blocks of 30 minutes.

Booking costs setting: Minimum price for 3 hours is 300$ (we use rules for block 1 to 6).

Base cost of room: 300$ (the customer can order less then 3 hours but the price will be at least for 3 hours).

Block cost: 50$ (start from block number 7).

Scenario for example:

if customer order 4 hours from 11PM to 3AM (total blocks: 8) the price will be regular: 400$ (Base cost: 300$ + 100$ [2 blocks of 50$ each])

if customer order 5 hours from 11PM to 4AM (total blocks: 10) the price will be regular: 500$

if customer order 6 hours from 11PM to 5AM (total blocks: 12) the price will be regular: 600$

If customer order 7 hours from 11PM to 6AM (total blocks: 14) the price will be 600$ instead 700$

If customer order 8 hours from 11PM to 7AM (total blocks: 16) the price will be 600$ instead 800$

If customer order 6 hours from 9PM to 3AM (total blocks: 12) the price will be 600$

If customer order 7 hours from 9PM to 4AM (total blocks: 14) the price will be 600$ instead 700$

  • 9PM to 10PM = 100$
  • 10PM to 4AM = 600$

If customer order 8 hours from 9PM to 5AM (total blocks: 16) the price will be 600$ instead 800$

  • 9PM to 10PM = 100$
  • 10PM to 5AM = 600$ (Rule trigger because the order bigger then 6 hours)

If customer order 14 hours from 9PM to 11AM (total blocks: 28) the price will be 800$ instead 1400$

  • 9PM to 10PM = 100$
  • 10PM to 10AM = 600$ (Rule trigger because the order bigger then 6 hours)
  • 10AM to 11AM = 100$

I tried follow this post Set prices based on WooCommerce Bookings duration and make adjustments to my issue without success.

2

There are 2 best solutions below

0
Itay Maor On

I created snippet and I don't see any change. Check this link to live preview

<?php
// Calculates price based on selected booking start time and minimum order hours
add_action( 'woocommerce_before_calculate_totals', 'cwpai_booking_price_calculation', 10, 1 );
function cwpai_booking_price_calculation( $cart ) {
    if ( is_admin() && ! defined( 'DOING_AJAX' ) ) {
        return;
    }
    
    foreach ( $cart->get_cart() as $cart_item ) {
        $product_id = $cart_item['product_id'];

        // Get start time and minimum order hours
        $start_time = strtotime($_POST['wc_bookings_field_start_date'][0] . ' ' . $_POST['wc_bookings_field_start_time'][0]);
        $minimum_hours = get_post_meta( $product_id, '_minimum_duration', true );

        // Check if start time and minimum order hours meet condition
        if ( date('H:i', $start_time) >= '22:00' && date('H:i', $start_time) <= '10:00' && $minimum_hours >= 6 ) {
            // Calculate maximum cost for 6 hours
            $max_cost = $cart_item['data']->get_price() * 6;

            // Get current cost based on duration
            $duration = WC_Bookings_Cart::calculate_booking_duration( $cart_item['booking'], true, true );
            $current_cost = $duration['cost'];

            // Update cost to maximum cost for 6 hours
            if ( $current_cost > $max_cost ) {
                $cart_item['data']->set_price( $max_cost );
            }
        }
    }
}

// Update post meta when product is saved
add_action( 'woocommerce_process_product_meta', 'cwpai_update_booking_meta' );
function cwpai_update_booking_meta( $post_id ) {
    // Only run for bookable products
    if ( get_post_meta( $post_id, '_wc_booking_type', true ) !== 'booking' ) {
        return;
    }
    
    // Get minimum order hours
    $minimum_hours = isset( $_POST['_minimum_duration'] ) ? absint( $_POST['_minimum_duration'] ) : 0;

    // Update post meta with new booking cost
    if ( $minimum_hours >= 6 ) {
        $max_cost = get_post_meta( $post_id, '_price', true ) * 6;
        update_post_meta( $post_id, '_new_booking_cost', $max_cost );
    } else {
        delete_post_meta( $post_id, '_new_booking_cost' );
    }
}

// Modify product costs to new booking cost
add_filter( 'woocommerce_product_get_price', 'cwpai_modify_product_costs', 10, 2 );
add_filter( 'woocommerce_product_get_regular_price', 'cwpai_modify_product_costs', 10, 2 );
function cwpai_modify_product_costs( $price, $product ) {
    $new_booking_cost = get_post_meta( $product->get_id(), '_new_booking_cost', true );

    if ( $new_booking_cost ) {
        $price = $new_booking_cost;
    }

    return $price;
}
0
Itay Maor On

I miss something :) Check this link to live preview

/**
 * Custom price calculation for WooCommerce Bookings and Appointments plugin.
 */

// Hook into the 'woocommerce_before_calculate_totals' action
add_action('woocommerce_before_calculate_totals', 'custom_booking_price_calculation', 10, 1);
function custom_booking_price_calculation($cart) {
    if (is_admin() && !defined('DOING_AJAX'))
        return;

    // Get current time
    $current_time = current_time('timestamp');

    foreach ($cart->get_cart() as $cart_item_key => $cart_item) {
        $product = $cart_item['data'];

        if ($product->is_type('booking')) {
            $booking_data = $product->get_data();
            $start_time = strtotime($booking_data['date_from']);
            $end_time = strtotime($booking_data['date_to']);
            $selected_blocks = ceil(($end_time - $start_time) / 1800); // 1800 seconds = 30 minutes

            // Condition #1: Start time is between 10:00 PM and 10:00 AM
            $start_hour = date('H', $start_time);
            if ($start_hour >= 22 || $start_hour <= 10) {
                // Condition #2: Minimum order blocks greater than or equal to 12
                if ($selected_blocks >= 12) {
                    // Condition #3: Calculate price for maximum 12 blocks based on rules
                    $base_cost = 300; // Base cost from product settings
                    $cost_per_block = 50; // Cost per block from product settings

                    $max_blocks = min($selected_blocks, 12);
                    $price = $base_cost + ($cost_per_block * $max_blocks);

                    // Set new price for the booking
                    $booking_data['cost'] = $price;
                    $booking = new WC_Booking($booking_data['booking_id']);
                    $booking->set_cost($price);

                    // Update booking data
                    $product->set_props($booking_data);
                    $product->save();

                    // Update cart item data
                    $cart_item['data'] = $product;
                    $cart->cart_contents[$cart_item_key] = $cart_item;

                    // Update cart totals
                    $cart->set_cart_contents_total();
                    $cart->set_cart_contents_tax();
                    $cart->set_total($cart->subtotal + $cart->tax_total, $cart->shipping_total);
                }
            }
        }
    }
}

// Hook into the 'update_post_meta' action
add_action('update_post_meta', 'custom_booking_price_update_post_meta', 10, 3);
function custom_booking_price_update_post_meta($meta_id, $object_id, $meta_key) {
    if ($meta_key === '_cost') {
        $booking = new WC_Booking($object_id);
        $booking_data = $booking->get_data();
        $booking_cost = $booking_data['cost'];

        // Update booking cost if necessary
        if ($booking_cost) {
            update_post_meta($object_id, '_cost', $booking_cost);
        }
    }
}

// Hook into the 'new_booking_cost' filter
add_filter('new_booking_cost', 'custom_booking_price_new_booking_cost', 10, 4);
function custom_booking_price_new_booking_cost($cost, $resource_id, $start, $end) {
    // Check if the calculation has already been performed
    if (did_action('woocommerce_before_calculate_totals') >= 2) {
        return $cost;
    }

    // Calculate the number of blocks
    $selected_blocks = ceil(($end - $start) / 1800);

    // Condition #1: Start time is between 10:00 PM and 10:00 AM
    $start_hour = date('H', $start);
    $start_minute = date('i', $start);
    if (($start_hour == 22 && $start_minute >= 0) || ($start_hour >= 23 || $start_hour <= 9)) {
        // Condition #2: Minimum order blocks greater than or equal to 12
        if ($selected_blocks >= 12) {
            // Condition #3: Calculate price for maximum 12 blocks based on rules
            $base_cost = 300; // Base cost from product settings
            $cost_per_block = 50; // Cost per block from product settings

            $max_blocks = min($selected_blocks, 12);
            $price = $base_cost + ($cost_per_block * $max_blocks);

            return $price;
        }
    }

    return $cost;
}




// Function to modify the base cost of a bookable product
function modify_baseprice($base_cost, $product_id, $booking_id) {
    $product = wc_get_product($product_id);

    if ($product->is_type('booking')) {
        $booking_base_cost = $product->get_meta('_cost');

        if ($booking_base_cost) {
            $booking_base_cost = max(0, (float)$booking_base_cost);
            $product->set_base_cost($booking_base_cost);
            $product->save();
            return $booking_base_cost;
        }
    }

    return $base_cost;
}


// Hook into the 'woocommerce_bookings_after_booking_base_cost' action
add_action('woocommerce_bookings_after_booking_base_cost', 'modify_baseprice', 10, 3);




// Hook into the 'woocommerce_process_product_meta_booking' action
add_action('woocommerce_process_product_meta_booking', 'modify_bookable_product_base_cost', 100, 1);
function modify_bookable_product_base_cost($product_id) {
    if (isset($_POST['_cost'])) {
        $booking_base_cost = max(0, (float)$_POST['_cost']);
        update_post_meta($product_id, '_base_cost', $booking_base_cost);
    }
}