基于WooCommerce购物车商品及数量的嵌套循环改造需求
按商品变体分组生成WooCommerce结账参与者字段
需求说明
原代码根据购物车总数量生成统一的参与者信息字段,现需改造为按商品变体分组:例如购物车中有2份Day1活动票、1份Day2活动票时,分别生成Day1组(2个参与者字段)和Day2组(1个参与者字段)。
修改后的完整代码
1. 生成分组的参与者字段
// 按商品变体分组生成WooCommerce结账参与者字段 add_action( 'woocommerce_before_order_notes', 'person_details_by_variant' ); function person_details_by_variant($checkout) { global $woocommerce; $cart_items = $woocommerce->cart->get_cart(); $global_attendee_num = 1; // 全局参与者序号,确保表单字段唯一 foreach ($cart_items as $cart_item_key => $cart_item) { $product = $cart_item['data']; $variant_name = $product->get_name(); // 获取商品变体名称(如Day1、Day2) $quantity = $cart_item['quantity']; // 当前变体的购买数量 // 输出分组标题 echo '<h3>'.$variant_name.' 参与者信息 (共'.$quantity.'人)</h3>'; // 内层循环:为当前变体的每个数量生成字段组 for ($j = 1; $j <= $quantity; $j++) { $field_suffix = $variant_name . '_' . $global_attendee_num; // 学年选择字段 woocommerce_form_field( 'school_year_' . $field_suffix, array( 'type' => 'radio', 'required' => true, 'class' => array('my-field-class form-row-wide'), 'label' => __('学年'), 'options' => array( 'Reception' => 'Reception', 'Year 1' => 'Year 1', 'Year 2' => 'Year 2', 'Year 3' => 'Year 3', 'Year 4' => 'Year 4', 'Year 5' => 'Year 5', 'Year 6' => 'Year 6', 'Year 7' => 'Year 7', ), ), $checkout->get_value( 'school_year_' . $field_suffix )); // 孩子全名字段 woocommerce_form_field( 'cstm_full_name_' . $field_suffix, array( 'type' => 'text', 'required' => true, 'class' => array('my-field-class form-row-wide'), 'label' => __('孩子全名'), 'placeholder' => __('输入全名'), ), $checkout->get_value( 'cstm_full_name_' . $field_suffix )); echo '<div class="clear"></div>'; // 紧急联系电话字段 woocommerce_form_field( 'cstm_phone_' . $field_suffix, array( 'type' => 'tel', 'required' => true, 'class' => array('my-field-class form-row-first'), 'label' => __('紧急联系电话'), 'placeholder' => __('输入电话号码'), ), $checkout->get_value( 'cstm_phone_' . $field_suffix )); echo '<div class="clear"></div>'; // 照片授权字段 woocommerce_form_field( 'photo_consent_' . $field_suffix, array( 'type' => 'radio', 'required' => true, 'class' => array('my-field-class form-row-wide'), 'label' => __('照片授权同意?'), 'options' => array( 'Yes' => '同意', 'No' => '不同意', ), ), $checkout->get_value( 'photo_consent_' . $field_suffix )); $global_attendee_num++; } } }
2. 保存分组字段的订单元数据
// 保存分组参与者字段到订单元数据 add_action('woocommerce_checkout_update_order_meta', 'customise_checkout_field_update_order_meta_by_variant'); function customise_checkout_field_update_order_meta_by_variant($order_id) { global $woocommerce; $cart_items = $woocommerce->cart->get_cart(); $global_attendee_num = 1; foreach ($cart_items as $cart_item_key => $cart_item) { $product = $cart_item['data']; $variant_name = $product->get_name(); $quantity = $cart_item['quantity']; for ($j = 1; $j <= $quantity; $j++) { $field_suffix = $variant_name . '_' . $global_attendee_num; $attendee_label = $variant_name . ' 参与者 ' . $j; // 保存学年信息 if (!empty($_POST['school_year_' . $field_suffix])) { update_post_meta($order_id, $attendee_label . ' - 学年', sanitize_text_field($_POST['school_year_' . $field_suffix])); } // 保存姓名信息 if (!empty($_POST['cstm_full_name_' . $field_suffix])) { update_post_meta($order_id, $attendee_label . ' - 姓名', sanitize_text_field($_POST['cstm_full_name_' . $field_suffix])); } // 保存紧急联系电话 if (!empty($_POST['cstm_phone_' . $field_suffix])) { update_post_meta($order_id, $attendee_label . ' - 紧急联系电话', sanitize_text_field($_POST['cstm_phone_' . $field_suffix])); } // 保存照片授权状态 if (!empty($_POST['photo_consent_' . $field_suffix])) { update_post_meta($order_id, $attendee_label . ' - 照片授权', sanitize_text_field($_POST['photo_consent_' . $field_suffix])); } $global_attendee_num++; } } }
3. 在订单邮件中显示分组字段
// 在订单邮件中显示分组参与者字段 add_filter('woocommerce_email_order_meta_fields', 'my_custom_checkout_field_order_meta_fields_by_variant', 10, 3); function my_custom_checkout_field_order_meta_fields_by_variant( $fields, $sent_to_admin, $order ) { $order_meta = get_post_meta($order->get_id()); $variant_attendee_fields = array(); // 筛选出所有参与者相关的元数据 foreach ($order_meta as $key => $value) { if (strpos($key, '参与者') !== false) { $variant_attendee_fields[$key] = $value[0]; } } // 按变体分组排序后添加到邮件字段 if (!empty($variant_attendee_fields)) { ksort($variant_attendee_fields); foreach ($variant_attendee_fields as $key => $value) { $fields[$key] = array( 'label' => $key, 'value' => $value, ); } } return $fields; }
关键改动说明
- 嵌套循环结构:外层遍历购物车中的每个商品变体,内层根据变体购买数量生成对应字段组
- 字段唯一标识:字段名加入变体名称+全局序号,避免不同变体的字段冲突
- 分组可视化:结账页面按变体名称分组展示,用户能清晰区分不同场次的参与者信息
- 元数据优化:订单元数据加入变体标识,便于后台查看和管理
- 邮件动态适配:不再硬编码固定数量字段,而是动态读取订单中已保存的参与者数据,适配任意数量的变体和购票数
内容的提问来源于stack exchange,提问作者Blakar1988
相关产品推荐
相关产品推荐

