如何使用带参数的WooCommerce钩子并解决结账页面函数中$number变量未定义的PHP通知错误
解决WooCommerce中
Undefined variable: number错误及钩子配合问题 首先得明确这个错误的核心原因:PHP变量作用域限制。你在display_cart_item_custom_meta_data函数里定义的$number是局部变量,只能在该函数内部访问;而my_custom_checkout_field是完全独立的另一个函数,根本无法获取到这个变量,所以才会抛出“未定义变量”的通知。
下面给你两种靠谱的解决方案,你可以根据业务需求选择:
方案1:利用WooCommerce会话存储总人数
这个方案会把计算好的总人数存入WooCommerce会话,让结账字段函数可以轻松读取到数据:
// 计算购物车项总人数并存入会话 add_filter( 'woocommerce_get_item_data', 'display_cart_item_custom_meta_data', 10, 2 ); function display_cart_item_custom_meta_data( $item_data, $cart_item ) { // 提取自定义元数据(做了空值判断避免报错) $adults = isset( $cart_item['adults'] ) ? intval( $cart_item['adults'] ) : 0; $children = isset( $cart_item['children'] ) ? intval( $cart_item['children'] ) : 0; $infants = isset( $cart_item['infants'] ) ? intval( $cart_item['infants'] ) : 0; // 计算当前项的总人数 $item_total = $adults + $children + $infants; // 累加购物车所有项的总人数到会话 if ( WC()->session ) { $total_passengers = WC()->session->get( 'total_passengers', 0 ); WC()->session->set( 'total_passengers', $total_passengers + $item_total ); } // 保留原有钩子逻辑:在购物车显示该项的总人数 $item_data[] = array( 'key' => '总人数', 'value' => $item_total, 'display' => '', ); return $item_data; } // 在结账页面生成对应数量的乘客输入字段 add_action( 'woocommerce_after_order_notes', 'my_custom_checkout_field' ); function my_custom_checkout_field( $checkout ) { // 从会话中读取总人数 $number = WC()->session->get( 'total_passengers', 0 ); if ( $number > 0 ) { echo '<div id="passenger_fields"><h3>' . __('乘客信息') . '</h3>'; // 循环生成输入字段 for ( $i = 1; $i <= $number; $i++ ) { echo '<p class="form-row form-row-wide">'; woocommerce_form_field( 'passenger_name_' . $i, array( 'type' => 'text', 'class' => array('my-field-class form-row-wide'), 'label' => __('乘客姓名 #' . $i), 'placeholder' => __('请输入姓名'), 'required' => true, ), $checkout->get_value( 'passenger_name_' . $i ) ); echo '</p>'; } echo '</div>'; } } // 订单完成或购物车清空时,清理会话中的乘客数据避免残留 add_action( 'woocommerce_checkout_order_processed', 'clear_passenger_session' ); add_action( 'woocommerce_cart_emptied', 'clear_passenger_session' ); function clear_passenger_session() { if ( WC()->session ) { WC()->session->__unset( 'total_passengers' ); } }
方案2:在结账函数中直接计算总人数(更独立健壮)
这个方案不需要依赖其他函数的执行结果,直接在结账字段函数里遍历购物车所有项计算总人数,避免了会话存储可能带来的异常(比如会话失效、数据残留):
// 原有购物车项元数据显示逻辑保留 add_filter( 'woocommerce_get_item_data', 'display_cart_item_custom_meta_data', 10, 2 ); function display_cart_item_custom_meta_data( $item_data, $cart_item ) { $adults = isset( $cart_item['adults'] ) ? intval( $cart_item['adults'] ) : 0; $children = isset( $cart_item['children'] ) ? intval( $cart_item['children'] ) : 0; $infants = isset( $cart_item['infants'] ) ? intval( $cart_item['infants'] ) : 0; $item_total = $adults + $children + $infants; $item_data[] = array( 'key' => '总人数', 'value' => $item_total, 'display' => '', ); return $item_data; } // 结账页面生成乘客字段,直接从购物车计算总人数 add_action( 'woocommerce_after_order_notes', 'my_custom_checkout_field' ); function my_custom_checkout_field( $checkout ) { $number = 0; // 遍历所有购物车项,累加总人数 foreach ( WC()->cart->get_cart() as $cart_item ) { $adults = isset( $cart_item['adults'] ) ? intval( $cart_item['adults'] ) : 0; $children = isset( $cart_item['children'] ) ? intval( $cart_item['children'] ) : 0; $infants = isset( $cart_item['infants'] ) ? intval( $cart_item['infants'] ) : 0; $number += $adults + $children + $infants; } if ( $number > 0 ) { echo '<div id="passenger_fields"><h3>' . __('乘客信息') . '</h3>'; for ( $i = 1; $i <= $number; $i++ ) { echo '<p class="form-row form-row-wide">'; woocommerce_form_field( 'passenger_name_' . $i, array( 'type' => 'text', 'class' => array('my-field-class form-row-wide'), 'label' => __('乘客姓名 #' . $i), 'placeholder' => __('请输入姓名'), 'required' => true, ), $checkout->get_value( 'passenger_name_' . $i ) ); echo '</p>'; } echo '</div>'; } }
方案推荐
个人更推荐方案2,因为它直接从购物车源数据计算,不依赖其他函数的执行顺序或会话状态,逻辑更独立、容错性更强。
最后提醒:把代码放到主题的functions.php文件或自定义插件中,不要直接修改WooCommerce核心文件,避免更新时丢失修改。
内容的提问来源于stack exchange,提问作者dominotrix
相关产品推荐
相关产品推荐

