请求审核WooCommerce自定义优惠券自动应用功能代码并提建议
WooCommerce自动优惠券代码审核与优化建议
原代码存在的问题
- 钩子使用错误:
woocommerce_applied_coupon是优惠券已被应用后触发的钩子,此时调用apply_coupon会导致重复执行,引发性能问题或错误提示。 - 逻辑依赖错误:首单自动应用的逻辑嵌套在第一个复选框的判断中,导致仅勾选“新用户首单自动应用”时功能无法生效,违背了两个复选框独立控制的需求。
- 未避免重复应用:未检查优惠券是否已在购物车中,每次购物车更新都会尝试应用,可能造成重复添加。
- 访客场景缺失:仅针对登录用户判断首单,未处理访客用户的首单识别,覆盖范围不全。
- 订单查询不规范:通过元数据键值对查询用户订单,未使用WooCommerce内置的
customer_id参数,代码冗余且不符合规范。 - 缺少前置验证:应用优惠券前未提前验证优惠券的有效性(如过期、使用次数限制等),虽然后续
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');
关键优化点说明
- 更换触发钩子:使用
woocommerce_cart_loaded_from_session和woocommerce_before_calculate_totals,在购物车初始化和计算总价时执行逻辑,避免重复应用。 - 分离独立逻辑:将两个复选框的控制逻辑拆分为独立判断,确保各自功能可单独生效。
- 避免重复应用:通过
WC()->cart->has_discount()检查优惠券是否已应用,跳过重复操作。 - 覆盖访客场景:通过Cookie识别访客用户的首单状态,完善功能覆盖范围。
- 规范数据操作:使用WooCommerce优惠券对象的
get_meta和update_meta_data方法操作元数据,替代原生的get_post_meta和update_post_meta,符合插件规范。 - 添加安全验证:保存设置时添加nonce验证,防止恶意提交。
- 前置有效性检查:通过
$coupon->is_valid()提前验证优惠券状态,减少无效操作。
内容的提问来源于stack exchange,提问作者MohsenJames Amra
相关产品推荐
相关产品推荐

