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

请求审核WooCommerce自定义优惠券自动应用功能代码并提建议

WooCommerce自动优惠券代码审核与优化建议

原代码存在的问题

  1. 钩子使用错误:woocommerce_applied_coupon是优惠券已被应用后触发的钩子,此时调用apply_coupon会导致重复执行,引发性能问题或错误提示。
  2. 逻辑依赖错误:首单自动应用的逻辑嵌套在第一个复选框的判断中,导致仅勾选“新用户首单自动应用”时功能无法生效,违背了两个复选框独立控制的需求。
  3. 未避免重复应用:未检查优惠券是否已在购物车中,每次购物车更新都会尝试应用,可能造成重复添加。
  4. 访客场景缺失:仅针对登录用户判断首单,未处理访客用户的首单识别,覆盖范围不全。
  5. 订单查询不规范:通过元数据键值对查询用户订单,未使用WooCommerce内置的customer_id参数,代码冗余且不符合规范。
  6. 缺少前置验证:应用优惠券前未提前验证优惠券的有效性(如过期、使用次数限制等),虽然后续apply_coupon会检查,但提前验证能减少无效操作。

优化后的代码

// 添加自定义优惠券设置标签页
function custom_coupon_settings_tab($tabs) {
    $tabs['automatic_apply'] = array(
        'label' => __('自动应用设置', 'mohsen'),
        'target' => 'automatic_apply_coupon_data',
        'class' => 'show_if_coupon',
    );
    return $tabs;
}
add_filter('woocommerce_coupon_data_tabs', 'custom_coupon_settings_tab');

// 渲染标签页内容
function custom_coupon_settings_tab_content() {
    global $thecoupon; // 使用WooCommerce内置的优惠券对象,替代global $post

    // 使用优惠券对象的get_meta方法获取元数据,更符合WooCommerce规范
    $automatic_apply = $thecoupon->get_meta('automatic_apply', true);
    $automatic_apply_first_order = $thecoupon->get_meta('automatic_apply_first_order', true);
    ?>
    <div id="automatic_apply_coupon_data" class="panel woocommerce_options_panel">
        <?php
        woocommerce_wp_checkbox(
            array(
                'id' => 'automatic_apply',
                'label' => __('自动应用到符合条件的产品', 'mohsen'),
                'value' => $automatic_apply,
                'desc_tip' => true,
                'description' => __('勾选后,优惠券将自动应用到符合条件的产品,无需用户手动输入优惠码。', 'mohsen'),
            )
        );

        woocommerce_wp_checkbox(
            array(
                'id' => 'automatic_apply_first_order',
                'label' => __('自动应用到新用户首单', 'mohsen'),
                'value' => $automatic_apply_first_order,
                'desc_tip' => true,
                'description' => __('勾选后,优惠券将自动应用到新用户的首单(需满足优惠券的其他使用条件)。', 'mohsen'),
            )
        );
        ?>
    </div>
    <?php
}
add_action('woocommerce_coupon_data_panels', 'custom_coupon_settings_tab_content');

// 保存自定义优惠券设置
function save_custom_coupon_settings($post_id) {
    // 验证nonce,提升安全性
    if (!isset($_POST['woocommerce_meta_nonce']) || !wp_verify_nonce($_POST['woocommerce_meta_nonce'], 'woocommerce_save_data')) {
        return;
    }

    $automatic_apply = isset($_POST['automatic_apply']) ? 'yes' : 'no';
    $automatic_apply_first_order = isset($_POST['automatic_apply_first_order']) ? 'yes' : 'no';
    
    // 使用优惠券对象更新元数据,替代直接调用update_post_meta
    $coupon = new WC_Coupon($post_id);
    $coupon->update_meta_data('automatic_apply', $automatic_apply);
    $coupon->update_meta_data('automatic_apply_first_order', $automatic_apply_first_order);
    $coupon->save();
}
add_action('woocommerce_coupon_options_save', 'save_custom_coupon_settings');

// 自动应用优惠券核心逻辑
function auto_apply_eligible_coupons() {
    if (!isset(WC()->cart) || !is_a(WC()->cart, 'WC_Cart')) {
        return;
    }

    // 获取所有已发布的优惠券
    $coupons = get_posts(array(
        'post_type' => 'shop_coupon',
        'post_status' => 'publish',
        'numberposts' => -1,
    ));

    foreach ($coupons as $coupon_post) {
        $coupon = new WC_Coupon($coupon_post->ID);
        $coupon_code = $coupon->get_code();
        
        // 跳过已应用的优惠券
        if (WC()->cart->has_discount($coupon_code)) {
            continue;
        }

        // 检查优惠券是否有效
        if (!$coupon->is_valid()) {
            continue;
        }

        // 逻辑1:自动应用到符合条件的产品
        if ($coupon->get_meta('automatic_apply', true) === 'yes') {
            WC()->cart->apply_coupon($coupon_code);
            continue; // 避免同一优惠券被重复应用(如果同时勾选两个选项)
        }

        // 逻辑2:自动应用到新用户首单(独立判断)
        if ($coupon->get_meta('automatic_apply_first_order', true) === 'yes') {
            $user_id = get_current_user_id();
            $is_first_order = false;

            if ($user_id > 0) {
                // 登录用户:查询已完成/处理中的订单数量
                $order_count = wc_get_orders(array(
                    'customer_id' => $user_id,
                    'status' => array('wc-completed', 'wc-processing'),
                    'return' => 'count',
                ));
                $is_first_order = ($order_count === 0);
            } else {
                // 访客用户:通过Cookie判断是否下过单
                if (!isset($_COOKIE['wc_has_placed_order'])) {
                    $is_first_order = true;
                    // 设置Cookie,有效期30天
                    setcookie('wc_has_placed_order', '1', time() + 30 * DAY_IN_SECONDS, COOKIEPATH, COOKIE_DOMAIN);
                }
            }

            if ($is_first_order) {
                WC()->cart->apply_coupon($coupon_code);
            }
        }
    }
}
// 在购物车加载和计算总价时触发,确保逻辑及时执行
add_action('woocommerce_cart_loaded_from_session', 'auto_apply_eligible_coupons');
add_action('woocommerce_before_calculate_totals', 'auto_apply_eligible_coupons');

关键优化点说明

  1. 更换触发钩子:使用woocommerce_cart_loaded_from_session和woocommerce_before_calculate_totals,在购物车初始化和计算总价时执行逻辑,避免重复应用。
  2. 分离独立逻辑:将两个复选框的控制逻辑拆分为独立判断,确保各自功能可单独生效。
  3. 避免重复应用:通过WC()->cart->has_discount()检查优惠券是否已应用,跳过重复操作。
  4. 覆盖访客场景:通过Cookie识别访客用户的首单状态,完善功能覆盖范围。
  5. 规范数据操作:使用WooCommerce优惠券对象的get_meta和update_meta_data方法操作元数据,替代原生的get_post_meta和update_post_meta,符合插件规范。
  6. 添加安全验证:保存设置时添加nonce验证,防止恶意提交。
  7. 前置有效性检查:通过$coupon->is_valid()提前验证优惠券状态,减少无效操作。

内容的提问来源于stack exchange,提问作者MohsenJames Amra

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 23:00:06