基于产品及购票数量的WooCommerce自定义结账字段开发需求
嘿,针对你这个WooCommerce可变产品门票的参会人字段需求,我给你整理了一套完整的实现方案,直接用代码就能落地,还预留了扩展空间,一起来看看:
实现WooCommerce结账页动态生成参会人字段组
核心思路
根据购物车中门票的总数量,在结账页自动渲染对应数量的参会人信息字段组,完成表单验证后把数据绑定到订单中,同时支持后台查看这些信息。
完整代码实现
你可以把这些代码放到主题的functions.php文件里,或者做成独立的自定义插件(更推荐,避免主题更新丢失代码):
1. 计算购物车中门票总数量
function get_total_ticket_quantity() { $total = 0; foreach (WC()->cart->get_cart() as $cart_item) { // 这里可以自定义判断逻辑:比如检查产品是否属于"门票"分类/标签 if ($cart_item['data']->is_type('variable')) { $total += $cart_item['quantity']; } } return $total; }
2. 在结账页渲染参会人字段组
function render_attendee_fields() { $total_tickets = get_total_ticket_quantity(); if ($total_tickets <= 0) return; echo '<div id="attendee-fields" class="woocommerce-form-row woocommerce-form-row--wide form-row form-row-wide">'; echo '<h3>' . __('参会人信息', 'woocommerce') . '</h3>'; for ($i = 0; $i < $total_tickets; $i++) { echo '<div class="attendee-group" style="margin: 20px 0; padding: 15px; border: 1px solid #eee;">'; echo '<h4>' . __('参会人 #' . ($i+1), 'woocommerce') . '</h4>'; // 称谓下拉框 woocommerce_form_field( "attendee[$i][title]", array( 'type' => 'select', 'label' => __('称谓', 'woocommerce'), 'required' => true, 'options' => array( '' => __('请选择', 'woocommerce'), 'Mr' => __('先生', 'woocommerce'), 'Ms' => __('女士', 'woocommerce'), 'Dr' => __('博士', 'woocommerce'), 'Prof' => __('教授', 'woocommerce') ) ), WC()->checkout->get_value("attendee[$i][title]") ); // 姓名输入框 woocommerce_form_field( "attendee[$i][name]", array( 'type' => 'text', 'label' => __('姓名', 'woocommerce'), 'required' => true, 'placeholder' => __('请输入姓名', 'woocommerce') ), WC()->checkout->get_value("attendee[$i][name]") ); // 机构输入框 woocommerce_form_field( "attendee[$i][organisation]", array( 'type' => 'text', 'label' => __('机构', 'woocommerce'), 'required' => true, 'placeholder' => __('请输入机构名称', 'woocommerce') ), WC()->checkout->get_value("attendee[$i][organisation]") ); // 职位输入框 woocommerce_form_field( "attendee[$i][position]", array( 'type' => 'text', 'label' => __('职位', 'woocommerce'), 'required' => true, 'placeholder' => __('请输入职位', 'woocommerce') ), WC()->checkout->get_value("attendee[$i][position]") ); // 邮箱输入框 woocommerce_form_field( "attendee[$i][email]", array( 'type' => 'email', 'label' => __('邮箱', 'woocommerce'), 'required' => true, 'placeholder' => __('请输入邮箱', 'woocommerce') ), WC()->checkout->get_value("attendee[$i][email]") ); // 电话输入框 woocommerce_form_field( "attendee[$i][tel]", array( 'type' => 'tel', 'label' => __('电话', 'woocommerce'), 'required' => true, 'placeholder' => __('请输入电话', 'woocommerce') ), WC()->checkout->get_value("attendee[$i][tel]") ); echo '</div>'; } echo '</div>'; } add_action('woocommerce_checkout_after_customer_details', 'render_attendee_fields');
3. 表单验证(确保必填字段都填写)
function validate_attendee_fields() { $total_tickets = get_total_ticket_quantity(); if ($total_tickets <= 0) return; if (!isset($_POST['attendee']) || !is_array($_POST['attendee'])) { wc_add_notice(__('请填写所有参会人信息', 'woocommerce'), 'error'); return; } foreach ($_POST['attendee'] as $index => $attendee) { if (empty($attendee['title'])) { wc_add_notice(__('参会人 #' . ($index+1) . ' 的称谓不能为空', 'woocommerce'), 'error'); } if (empty($attendee['name'])) { wc_add_notice(__('参会人 #' . ($index+1) . ' 的姓名不能为空', 'woocommerce'), 'error'); } if (empty($attendee['organisation'])) { wc_add_notice(__('参会人 #' . ($index+1) . ' 的机构不能为空', 'woocommerce'), 'error'); } if (empty($attendee['position'])) { wc_add_notice(__('参会人 #' . ($index+1) . ' 的职位不能为空', 'woocommerce'), 'error'); } if (empty($attendee['email']) || !is_email($attendee['email'])) { wc_add_notice(__('参会人 #' . ($index+1) . ' 的邮箱格式不正确', 'woocommerce'), 'error'); } if (empty($attendee['tel'])) { wc_add_notice(__('参会人 #' . ($index+1) . ' 的电话不能为空', 'woocommerce'), 'error'); } } } add_action('woocommerce_checkout_process', 'validate_attendee_fields');
4. 保存参会人数据到订单
function save_attendee_data($order_id) { if (isset($_POST['attendee']) && is_array($_POST['attendee'])) { $attendees = array_map(function($attendee) { return array_filter($attendee); // 过滤空值 }, $_POST['attendee']); update_post_meta($order_id, '_attendee_details', $attendees); } } add_action('woocommerce_checkout_update_order_meta', 'save_attendee_data');
5. 在后台订单页展示参会人信息
function display_attendee_data_in_admin($order) { $attendees = get_post_meta($order->get_id(), '_attendee_details', true); if (!empty($attendees) && is_array($attendees)) { echo '<div class="attendee-details">'; echo '<h3>' . __('参会人信息', 'woocommerce') . '</h3>'; echo '<table class="widefat fixed">'; echo '<thead><tr><th>序号</th><th>称谓</th><th>姓名</th><th>机构</th><th>职位</th><th>邮箱</th><th>电话</th></tr></thead>'; echo '<tbody>'; foreach ($attendees as $index => $attendee) { echo '<tr>'; echo '<td>' . ($index+1) . '</td>'; echo '<td>' . esc_html($attendee['title']) . '</td>'; echo '<td>' . esc_html($attendee['name']) . '</td>'; echo '<td>' . esc_html($attendee['organisation']) . '</td>'; echo '<td>' . esc_html($attendee['position']) . '</td>'; echo '<td>' . esc_html($attendee['email']) . '</td>'; echo '<td>' . esc_html($attendee['tel']) . '</td>'; echo '</tr>'; } echo '</tbody></table>'; echo '</div>'; } } add_action('woocommerce_admin_order_data_after_billing_address', 'display_attendee_data_in_admin', 10, 1);
扩展性建议
如果后续需要扩展功能,可以从这几个方向入手:
- 可配置字段:添加WooCommerce后台设置页面,让商家自定义需要显示的字段(比如要不要"饮食偏好"字段),用
get_option获取配置动态生成字段。 - 门票类型区分:针对不同类型的门票(比如VIP/普通票),生成不同的字段组(比如VIP票额外添加"住宿需求"字段)。
- AJAX动态更新:用户在结账页修改购物车数量时,实时更新参会人字段组,不用刷新页面。
- 数据导出:添加功能把订单中的参会人信息导出为CSV,方便活动签到统计。
- 邮件通知:在订单确认邮件中插入参会人信息,同步发送给用户和管理员。
内容的提问来源于stack exchange,提问作者PixelBorder
相关产品推荐
相关产品推荐

