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

如何通过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();
        }
    });
});

关键优势说明

  1. 彻底摆脱JS数据收集:PHP自动解析数组,再也不用怕JS同步bug
  2. 数据更安全:全程用WP自带的sanitize函数处理输入,避免XSS
  3. 渲染更准确:用WP的selected()和checked()函数自动处理下拉、复选框的状态
  4. 可维护性更高:所有逻辑集中在PHP,不用跨JS/PHP调试数据格式

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.08 08:29:30