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
相关产品推荐
相关产品推荐

