WooCommerce单产品页:Ajax实现按数量生成树木名称字段(无刷新)
解决WooCommerce动态生成对应数量的树木名称输入框问题
需求说明
在WordPress的WooCommerce站点销售树木时,需要根据用户选择的购买数量,无刷新动态生成对应数量的树木名称输入字段,用户下单时需填写每棵树的名称。
原代码的问题
你之前尝试用AJAX传递数量值到PHP,但核心问题在于:PHP是服务器端脚本,页面加载完成后就已经执行完毕,无法在不刷新页面的情况下通过JS修改PHP变量并重新渲染输入框。直接提交到single-product.php的AJAX请求也不符合WooCommerce规范,且无法触发PHP代码重新生成字段。
正确解决方案
改用前端JavaScript动态操作DOM来添加/移除输入框,同时配合PHP处理字段的保存与验证,确保数据能正确存入订单。
完整代码实现
1. PHP部分(字段注册、验证与数据保存)
将以下代码添加到主题的functions.php文件中:
// 在添加到购物车前显示初始的树木名称输入框 add_action('woocommerce_before_add_to_cart_button', 'render_tree_name_fields'); function render_tree_name_fields() { // 默认显示1个输入框 woocommerce_form_field('tree_name_1', array( 'type' => 'text', 'label' => '树木名称 1', 'placeholder' => '请填写树木名称', 'class' => array('my-field-class form-row-wide tree-name-field'), 'required' => true, ), ''); } // 验证输入字段是否完整 add_action('woocommerce_add_to_cart_validation', 'validate_tree_name_fields', 10, 3); function validate_tree_name_fields($passed, $product_id, $quantity) { // 检查每个对应数量的输入框是否都已填写 for ($i = 1; $i <= $quantity; $i++) { if (empty($_POST['tree_name_' . $i])) { wc_add_notice('请填写第 ' . $i . ' 棵树木的名称', 'error'); $passed = false; break; } } return $passed; } // 将树木名称保存到订单项元数据 add_action('woocommerce_add_order_item_meta', 'save_tree_name_to_order', 10, 3); function save_tree_name_to_order($item_id, $values, $cart_item_key) { $quantity = $values['quantity']; for ($i = 1; $i <= $quantity; $i++) { if (!empty($_POST['tree_name_' . $i])) { wc_add_order_item_meta($item_id, '树木名称 ' . $i, sanitize_text_field($_POST['tree_name_' . $i])); } } }
2. JavaScript部分(动态生成/移除输入框)
将以下代码添加到单产品页面的自定义脚本中(可通过主题自定义JS功能,或添加到single-product.php的合适位置):
jQuery(document).ready(function($) { // 获取数量输入框和字段容器 const $quantityField = $('form.cart input[name="quantity"]'); const $fieldsContainer = $('form.cart .tree-name-field').parent(); // 监听数量变化 $quantityField.on('change input', function() { const targetQuantity = parseInt($(this).val()) || 1; const currentFieldsCount = $('.tree-name-field').length; // 当目标数量大于当前字段数时,添加新字段 if (targetQuantity > currentFieldsCount) { for (let i = currentFieldsCount + 1; i <= targetQuantity; i++) { const newField = ` <p class="form-row form-row-wide my-field-class"> <label for="tree_name_${i}" class="">树木名称 ${i} <abbr class="required" title="必填">*</abbr></label> <span class="woocommerce-input-wrapper"> <input type="text" class="input-text tree-name-field" name="tree_name_${i}" id="tree_name_${i}" placeholder="请填写树木名称" required> </span> </p> `; $fieldsContainer.append(newField); } } // 当目标数量小于当前字段数时,移除多余字段 else if (targetQuantity < currentFieldsCount) { $('.tree-name-field').slice(targetQuantity).parent().remove(); } }); });
代码说明
- 前端JS:监听数量输入框的变化,对比当前已有的输入框数量,动态添加或移除对应的字段,确保字段数量和选择的购买数量一致。
- PHP验证:添加到购物车时,检查所有对应数量的输入框是否都已填写,避免空值提交。
- 数据保存:将填写的树木名称保存为订单项的元数据,后续在订单详情、邮件中都能查看这些信息。
内容的提问来源于stack exchange,提问作者seyed ehsan ghazi marashi
相关产品推荐
相关产品推荐

