如何通过WooCommerce Settings API创建可重复字段并保存为PHP数组(无需自定义JavaScript工作流)
如何通过WooCommerce Settings API创建可重复字段并保存为PHP数组(无需自定义JavaScript工作流)
我明白你现在的痛点——用JS同步隐藏字段存JSON不仅容易出bug,还绕了弯路。其实完全可以利用PHP的数组式表单name属性,让提交的数据直接解析成二维数组,全程不用JSON转码,JS只需要保留最基础的添加/删除行DOM操作就行。下面一步步给你重构:
核心思路
把每个表单字段的name属性改成二维数组格式(比如qwc_form_fields[][name]),这样表单提交时PHP会自动把所有行的字段组装成一个二维数组。我们直接把这个数组存到WP选项,加载时遍历数组渲染表单,彻底摆脱自定义JS收集数据的环节。
1. 重构表单HTML(渲染部分)
替换你原来的repeater table代码,重点修改name属性、补全表单状态渲染(比如下拉选中、复选框勾选):
<div class="qwc_form"> <table class="qwc_repeater_options"> <thead> <tr> <th>Name</th> <th>Type</th> <th>Class</th> <th>Placeholder</th> <th>Validation</th> <th>Required</th> <th>Connect to</th> <th>Remove</th> </tr> </thead> <tbody> <!-- 模板行(用于添加新行,默认隐藏) --> <tr class="hidden qwc-repeater-template"> <td><input name="qwc_form_fields[][name]" placeholder="Enter field name..." type="text" value="" /></td> <td> <select name="qwc_form_fields[][type]"> <?php foreach($type_options as $option) { ?> <option value="<?php echo esc_attr($option); ?>"><?php echo esc_html(ucwords($option)); ?></option> <?php } ?> </select> </td> <td><input name="qwc_form_fields[][classes]" type="text" placeholder="Enter class names without commas, separate by space." value="" /></td> <td><input name="qwc_form_fields[][placeholder]" type="text" placeholder="Field placeholder" value="" /></td> <td><input name="qwc_form_fields[][validation]" type="checkbox" value="1" /></td> <td><input name="qwc_form_fields[][required]" type="checkbox" value="1" /></td> <td class="connect"> <select name="qwc_form_fields[][connection]"> <?php foreach($connection_options as $meta => $option) { ?> <option value="<?php echo esc_attr($meta); ?>"><?php echo esc_html($option); ?></option> <?php } ?> </select> <input type="text" class="cf_connect" style="display:none;" /> </td> <td><button class="remove">X</button></td> </tr> <!-- 渲染已保存的行 --> <?php $saved_fields = get_option('qwc_form_fields', array()); if(!empty($saved_fields) && is_array($saved_fields)) { foreach($saved_fields as $row) { // 给空字段设置默认值,避免报错 $row = wp_parse_args($row, array( 'name' => '', 'type' => reset($type_options), 'classes' => '', 'placeholder' => '', 'validation' => 0, 'required' => 0, 'connection' => reset(array_keys($connection_options)) )); ?> <tr> <td><input name="qwc_form_fields[][name]" placeholder="Enter field name..." type="text" value="<?php echo esc_attr($row['name']); ?>" /></td> <td> <select name="qwc_form_fields[][type]"> <?php foreach($type_options as $option) { ?> <option value="<?php echo esc_attr($option); ?>" <?php selected($row['type'], $option); ?>><?php echo esc_html(ucwords($option)); ?></option> <?php } ?> </select> </td> <td><input name="qwc_form_fields[][classes]" type="text" placeholder="Enter class names without commas, separate by space." value="<?php echo esc_attr($row['classes']); ?>" /></td> <td><input name="qwc_form_fields[][placeholder]" type="text" placeholder="Field placeholder" value="<?php echo esc_attr($row['placeholder']); ?>" /></td> <td><input name="qwc_form_fields[][validation]" type="checkbox" value="1" <?php checked($row['validation'], 1); ?> /></td> <td><input name="qwc_form_fields[][required]" type="checkbox" value="1" <?php checked($row['required'], 1); ?> /></td> <td class="connect"> <select name="qwc_form_fields[][connection]"> <?php foreach($connection_options as $meta => $option) { ?> <option value="<?php echo esc_attr($meta); ?>" <?php selected($row['connection'], $meta); ?>><?php echo esc_html($option); ?></option> <?php } ?> </select> <input type="text" class="cf_connect" style="display:none;" /> </td> <td><button class="remove">X</button></td> </tr> <?php } ?> </tbody> </table> <button class="button addrow">Add Row</button> <!-- 彻底删掉那个麻烦的隐藏input! --> </div>
2. 重构保存逻辑(直接存PHP数组)
替换你原来的qwc_save_repeater_form函数,直接从$_POST拿数组,安全验证后保存:
add_action( 'woocommerce_settings_save_qwc_quote_settings', 'qwc_save_repeater_form' ); function qwc_save_repeater_form() { // 权限与CSRF验证,必须加 if ( ! current_user_can( 'manage_woocommerce' ) || ! wp_verify_nonce( $_POST['_wpnonce'], 'woocommerce-settings' ) ) { return; } // 处理提交的表单数组 $submitted_fields = isset( $_POST['qwc_form_fields'] ) ? $_POST['qwc_form_fields'] : array(); // 过滤并 sanitize 每一行数据 $sanitized_fields = array_map( 'qwc_sanitize_form_row', $submitted_fields ); // 移除空行(比如用户添加了新行但没填内容) $sanitized_fields = array_filter( $sanitized_fields, function( $row ) { return !empty( $row['name'] ) || !empty( $row['type'] ); }); // 直接保存PHP数组到选项表,不用JSON! update_option( 'qwc_form_fields', $sanitized_fields ); } // 单独的字段安全处理函数 function qwc_sanitize_form_row( $row ) { return array( 'name' => sanitize_text_field( $row['name'] ?? '' ), 'type' => sanitize_text_field( $row['type'] ?? '' ), 'classes' => sanitize_text_field( $row['classes'] ?? '' ), 'placeholder' => sanitize_text_field( $row['placeholder'] ?? '' ), // 复选框没选中不会提交,默认设为0 'validation' => isset( $row['validation'] ) ? 1 : 0, 'required' => isset( $row['required'] ) ? 1 : 0, 'connection' => sanitize_text_field( $row['connection'] ?? '' ) ); }
3. JS只处理DOM增删(不用管数据)
保留最基础的添加/删除行逻辑,完全不用碰数据收集:
jQuery(document).ready(function($) { // 添加新行 $('.addrow').on('click', function(e) { e.preventDefault(); // 克隆模板行并移除隐藏类 const newRow = $('.qwc-repeater-template').clone().removeClass('hidden qwc-repeater-template'); $('.qwc_repeater_options tbody').append(newRow); }); // 删除行 $(document).on('click', '.remove', function(e) { e.preventDefault(); // 不要删除模板行 if(!$(this).closest('tr').hasClass('qwc-repeater-template')) { $(this).closest('tr').remove(); } }); });
关键优势说明
- 彻底摆脱JS数据收集:PHP自动解析数组,再也不用怕JS同步bug
- 数据更安全:全程用WP自带的sanitize函数处理输入,避免XSS
- 渲染更准确:用WP的
selected()和checked()函数自动处理下拉、复选框的状态 - 可维护性更高:所有逻辑集中在PHP,不用跨JS/PHP调试数据格式
内容来源于stack exchange
相关产品推荐
相关产品推荐

