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

为WooCommerce后台优惠券添加自定义多选字段(代码异常)

在WooCommerce优惠券后台添加带条件显示的多选产品字段

问题描述

需要在WooCommerce后台的「添加优惠券」页面新增一个名为「免费产品」的开关字段(包含「是」「否」选项),当选择「是」时,动态显示支持多选的产品选择框,可选择店铺内1个或多个产品。用户尝试的代码未实现预期效果。

原代码存在的问题

  1. 静态产品选项:产品选择框使用硬编码的静态选项,无法拉取店铺内实际存在的产品
  2. 无实时交互:仅在页面加载时判断是否显示产品框,用户切换开关后需刷新页面才会生效
  3. 数据处理不严谨:多选产品的数组数据未做安全过滤,存在潜在风险
  4. 字段布局问题:使用的钩子可能导致字段显示位置或样式不符合后台UI规范

修正后的完整代码

// 添加「免费产品」开关字段到优惠券编辑页面
add_action( 'woocommerce_coupon_options', 'add_free_product_switch_field', 10 );
function add_free_product_switch_field() {
    global $post;
    
    // 获取已保存的字段值,默认'no'
    $free_product = get_post_meta( $post->ID, '_free_product', true ) ?: 'no';

    woocommerce_wp_select( array(
        'id'          => '_free_product',
        'label'       => __( '免费产品', 'woocommerce' ),
        'options'     => array(
            'no'  => __( '否', 'woocommerce' ),
            'yes' => __( '是', 'woocommerce' ),
        ),
        'value'       => $free_product,
        'desc_tip'    => true,
        'description' => __( '启用后可选择随优惠券赠送的免费产品', 'woocommerce' )
    ) );
}

// 添加动态产品多选框(条件显示)
add_action( 'woocommerce_coupon_options', 'add_multi_product_select_field', 20 );
function add_multi_product_select_field() {
    global $post;
    
    $free_product = get_post_meta( $post->ID, '_free_product', true ) ?: 'no';
    
    // 仅当开关为「是」时显示,同时添加CSS隐藏默认状态
    $style = $free_product !== 'yes' ? 'style="display:none;"' : '';
    ?>
    <div id="free_product_select_container" <?php echo $style; ?>>
        <?php
        // 拉取店铺内所有已发布的产品
        $products = get_posts( array(
            'post_type'      => 'product',
            'post_status'    => 'publish',
            'numberposts'    => -1,
            'orderby'        => 'title',
            'order'          => 'ASC',
            'suppress_filters' => true
        ) );
        
        $product_options = array();
        foreach ( $products as $product ) {
            $product_options[$product->ID] = $product->post_title;
        }
        
        // 获取已保存的选中产品ID数组
        $selected_products = get_post_meta( $post->ID, '_free_product_ids', true ) ?: array();
        
        woocommerce_wp_select( array(
            'id'          => '_free_product_ids',
            'label'       => __( '选择免费产品', 'woocommerce' ),
            'options'     => $product_options,
            'multiple'    => true,
            'value'       => $selected_products,
            'desc_tip'    => true,
            'description' => __( '可选择多个产品作为优惠券赠品', 'woocommerce' ),
            'class'       => 'wc-product-search' // 借用WooCommerce产品选择样式
        ) );
        ?>
    </div>
    <?php
}

// 添加前端JS实现实时条件显示
add_action( 'admin_footer', 'free_product_field_conditional_js' );
function free_product_field_conditional_js() {
    global $pagenow;
    
    // 仅在优惠券编辑/添加页面加载JS
    if ( ( $pagenow === 'post.php' && get_post_type() === 'shop_coupon' ) || ( $pagenow === 'post-new.php' && $_GET['post_type'] === 'shop_coupon' ) ) {
        ?>
        <script type="text/javascript">
            jQuery(document).ready(function($){
                // 监听开关变化
                $('#_free_product').change(function(){
                    var switchValue = $(this).val();
                    if(switchValue === 'yes'){
                        $('#free_product_select_container').show();
                    } else {
                        $('#free_product_select_container').hide();
                        // 隐藏时清空选择框值
                        $('#_free_product_ids').val([]).trigger('change');
                    }
                });
            });
        </script>
        <?php
    }
}

// 保存自定义字段数据
add_action( 'woocommerce_coupon_options_save', 'save_free_product_coupon_fields', 10, 2 );
function save_free_product_coupon_fields( $post_id, $coupon ) {
    // 保存开关状态
    $free_product = isset( $_POST['_free_product'] ) ? sanitize_text_field( $_POST['_free_product'] ) : 'no';
    update_post_meta( $post_id, '_free_product', $free_product );
    
    // 保存选中的产品ID数组
    if ( $free_product === 'yes' ) {
        $product_ids = isset( $_POST['_free_product_ids'] ) ? array_map( 'absint', $_POST['_free_product_ids'] ) : array();
        update_post_meta( $post_id, '_free_product_ids', $product_ids );
    } else {
        // 开关为「否」时清空已保存的产品ID
        delete_post_meta( $post_id, '_free_product_ids' );
    }
}

代码说明

  1. 开关字段:使用woocommerce_coupon_options钩子添加,字段ID前缀下划线(WooCommerce规范),获取并回显已保存的值
  2. 动态产品选择:拉取店铺内所有已发布产品,生成选项列表,使用多选属性,同时添加容器用于条件显示
  3. 实时交互JS:仅在优惠券页面加载,监听开关变化,实时显示/隐藏产品选择框,隐藏时清空选择值
  4. 数据保存:对开关值做文本过滤,对产品ID数组做整数过滤,开关为「否」时自动清空产品ID记录

内容的提问来源于stack exchange,提问作者Reshad Karim Navid

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 02:45:01