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

如何使用带参数的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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 15:19:12