You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WooCommerce预订产品:取还时间变更后价格无法自动更新问题求助

解决WooCommerce Bookings + Product Add-Ons取还时间修改后价格不更新的问题

问题根源

这个问题其实很常见:你用的booking_form_calculated_booking_cost过滤器,只有当WooCommerce Bookings自带的日历日期字段发生变化时才会被触发。而Product Add-Ons添加的取件/归还时间属于额外自定义字段,它们的变化不会自动触发预订价格的重新计算,所以才会出现改时间价格不动、改日期才更新的情况。

解决思路&代码实现

要搞定这个问题,我们需要做两件事:一是优化你现有的价格计算逻辑(修复原代码里的潜在问题),二是添加前端代码,让取件/归还时间的变化也能触发价格重新计算。


第一步:优化后的价格计算PHP代码

我调整了你原有的代码,移除了可能破坏AJAX响应的echo输出,优化了变量处理逻辑,让价格计算更稳定:

add_filter( 'booking_form_calculated_booking_cost', 'wdm_calculate_hotel_booking_cost', 10, 3 );
function wdm_calculate_hotel_booking_cost( $cost, $book_obj, $posted ) {
    // 获取产品ID和产品对象
    $product_id = isset( $posted['add-to-cart'] ) ? intval( $posted['add-to-cart'] ) : 0;
    if ( ! $product_id ) return $cost;
    
    $product = wc_get_product( $product_id );
    if ( ! $product ) return $cost;
    
    $rent = (float) $product->get_price();
    $qnty_field_key = 'wc_bookings_field_persons_' . ( $product_id + 1 );
    $qnty = isset( $posted[ $qnty_field_key ] ) ? intval( $posted[ $qnty_field_key ] ) : 1;

    // 处理日期范围
    $start_date = sprintf( '%s/%s/%s', 
        $posted['wc_bookings_field_start_date_month'],
        $posted['wc_bookings_field_start_date_day'],
        $posted['wc_bookings_field_start_date_year']
    );
    $fromDate = date( 'Y-m-d', strtotime( $start_date ) );
    
    $to_date = isset( $posted['wc_bookings_field_start_date_to_month'] ) && $posted['wc_bookings_field_start_date_to_month'] !== '' 
        ? sprintf( '%s/%s/%s', 
            $posted['wc_bookings_field_start_date_to_month'],
            $posted['wc_bookings_field_start_date_to_day'],
            $posted['wc_bookings_field_start_date_to_year']
        ) 
        : $start_date;
    $ToDate = date( 'Y-m-d', strtotime( $to_date ) );

    // 处理取件/归还时间等级
    $ptimeRangelevel = '';
    $pickup_time = isset( $posted['addon-' . $product_id . '-pick-up-time-0'] ) ? $posted['addon-' . $product_id . '-pick-up-time-0'] : '';
    if ( $pickup_time ) {
        $ptimeRange = explode( '-', $pickup_time );
        $ptimeRangelevel = isset( $ptimeRange[2] ) ? intval( $ptimeRange[2] ) : '';
    }

    $rtimeRangelevel = '';
    $return_time = isset( $posted['addon-' . $product_id . '-return-time-1'] ) ? $posted['addon-' . $product_id . '-return-time-1'] : '';
    if ( $return_time ) {
        $rtimeRange = explode( '-', $return_time );
        $rtimeRangelevel = isset( $rtimeRange[2] ) ? intval( $rtimeRange[2] ) : '';
    }

    // 计算实际价格
    if ( $ptimeRangelevel !== '' && $rtimeRangelevel !== '' ) {
        $ts1 = strtotime( $fromDate );
        $ts2 = strtotime( $ToDate );
        $timeDiff = abs( $ts2 - $ts1 );
        $numberDays = intval( $timeDiff / 86400 );

        if ( $rtimeRangelevel <= $ptimeRangelevel ) {
            if ( $numberDays > 0 ) {
                $actualCnt = $numberDays;
                $actualPrice = $actualCnt * $qnty * $rent;
                
                if ( $rtimeRangelevel < $ptimeRangelevel ) {
                    if ( $numberDays > 1 ) {
                        $actualPrice = ( $actualCnt + 1 ) * $qnty * $rent;
                        $cost = $actualPrice - ( $rent * $qnty );
                    } else {
                        $cost = $cost - $actualPrice;
                    }
                } else {
                    $cost = $actualPrice;
                }
            }
        } else {
            $actualCnt = $numberDays + 1;
            $actualPrice = $actualCnt * $qnty * $rent;
            
            if ( $actualCnt > 2 && $rtimeRangelevel !== $ptimeRangelevel ) {
                $cost = $actualPrice;
            } else {
                $cost = $actualPrice - $rent;
            }
        }
    }

    return $cost;
}

// 清除结账缓存
add_filter( 'woocommerce_checkout_get_value', '__return_empty_string', 10, 1 );

第二步:添加前端JS触发价格更新

这段代码会监听取件/归还时间字段的变化,一旦用户修改选项,就触发预订日历的日期字段变更事件,从而激活价格重新计算:

add_action( 'wp_footer', 'wdm_trigger_booking_price_update_on_time_change' );
function wdm_trigger_booking_price_update_on_time_change() {
    // 只在产品页面加载
    if ( ! is_product() ) return;
    global $product;
    if ( ! $product || ! $product->is_type( 'booking' ) ) return;
    $product_id = $product->get_id();
    ?>
    <script>
        jQuery(document).ready(function($){
            // 监听取件时间和归还时间选择框
            const pickupField = $('select[name="addon-<?php echo $product_id; ?>-pick-up-time-0"]');
            const returnField = $('select[name="addon-<?php echo $product_id; ?>-return-time-1"]');
            
            // 触发预订价格重新计算的函数
            function triggerBookingPriceRefresh() {
                // 通过触发日期字段的change事件,激活价格计算钩子
                const startDateInput = $('input[name="wc_bookings_field_start_date"]');
                if (startDateInput.length) {
                    startDateInput.trigger('change');
                }
            }
            
            // 字段变化时执行刷新
            pickupField.on('change', triggerBookingPriceRefresh);
            returnField.on('change', triggerBookingPriceRefresh);
        });
    </script>
    <?php
}

效果说明

把这两段代码添加到你的主题functions.php或者自定义插件后,用户无论修改预订日历的日期,还是修改Product Add-Ons里的取件/归还时间,页面都会自动重新计算并更新价格,完美解决你遇到的问题。

内容的提问来源于stack exchange,提问作者Eleni Calibat

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 09:23:04