为WooCommerce后台优惠券添加自定义多选字段(代码异常)
在WooCommerce优惠券后台添加带条件显示的多选产品字段
问题描述
需要在WooCommerce后台的「添加优惠券」页面新增一个名为「免费产品」的开关字段(包含「是」「否」选项),当选择「是」时,动态显示支持多选的产品选择框,可选择店铺内1个或多个产品。用户尝试的代码未实现预期效果。
原代码存在的问题
- 静态产品选项:产品选择框使用硬编码的静态选项,无法拉取店铺内实际存在的产品
- 无实时交互:仅在页面加载时判断是否显示产品框,用户切换开关后需刷新页面才会生效
- 数据处理不严谨:多选产品的数组数据未做安全过滤,存在潜在风险
- 字段布局问题:使用的钩子可能导致字段显示位置或样式不符合后台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' ); } }
代码说明
- 开关字段:使用
woocommerce_coupon_options钩子添加,字段ID前缀下划线(WooCommerce规范),获取并回显已保存的值 - 动态产品选择:拉取店铺内所有已发布产品,生成选项列表,使用多选属性,同时添加容器用于条件显示
- 实时交互JS:仅在优惠券页面加载,监听开关变化,实时显示/隐藏产品选择框,隐藏时清空选择值
- 数据保存:对开关值做文本过滤,对产品ID数组做整数过滤,开关为「否」时自动清空产品ID记录
内容的提问来源于stack exchange,提问作者Reshad Karim Navid
相关产品推荐
相关产品推荐

