WooCommerce Subscriptions:为已订阅用户替换注册按钮为自定义字段链接
解决WooCommerce订阅产品替换“加入购物车”为“进入课程”按钮的问题
原代码核心问题分析
- 参数传递错误:
has_active_subscription函数用于检查用户是否有活跃订阅,但调用时错误传入了产品ID而非用户ID,导致逻辑完全失效。 - SQL查询不安全:直接拼接用户ID到SQL语句中,存在注入风险。
- HTML渲染错误:使用HTML实体(如
<、")输出按钮标签,导致页面无法正确解析为可点击的按钮。 - 未限定目标产品:原逻辑会对所有产品生效,无法只针对特定订阅产品替换按钮。
修正后的完整代码
/** * 检查当前登录用户是否拥有指定产品的活跃订阅 * @param int $product_id 目标产品ID * @return bool */ function has_active_product_subscription( $product_id ) { if ( ! is_user_logged_in() ) { return false; } $user_id = get_current_user_id(); global $wpdb; // 安全查询用户是否拥有该产品的活跃订阅 $count = $wpdb->get_var( $wpdb->prepare( " SELECT COUNT(p.ID) FROM {$wpdb->prefix}posts p JOIN {$wpdb->prefix}postmeta pm ON p.ID = pm.post_id JOIN {$wpdb->prefix}woocommerce_order_items oi ON p.post_parent = oi.order_id JOIN {$wpdb->prefix}woocommerce_order_itemmeta oim ON oi.order_item_id = oim.order_item_id WHERE p.post_type = 'shop_subscription' AND p.post_status = 'wc-active' AND pm.meta_key = '_customer_user' AND pm.meta_value = %d AND oim.meta_key = '_product_id' AND oim.meta_value = %d ", $user_id, $product_id ) ); return $count > 0; } // 产品列表页:替换加入购物车按钮为进入课程按钮 add_filter( 'woocommerce_loop_add_to_cart_link', 'replace_loop_subscription_add_to_cart', 20, 2 ); function replace_loop_subscription_add_to_cart( $html, $product ) { // 仅针对订阅产品生效,且用户已购买该产品的活跃订阅 if ( $product->is_type( 'subscription' ) && has_active_product_subscription( $product->get_id() ) ) { $enter_link = get_field( 'link_enter_class', $product->get_id() ); if ( empty( $enter_link ) ) { return $html; } $html = sprintf( '<a href="%s" class="button alt add_to_cart_button enter_class_button">%s</a>', esc_url( $enter_link ), esc_html__( 'Enter Class', 'woocommerce' ) ); } return $html; } // 产品详情页:替换加入购物车按钮为进入课程按钮 add_action( 'woocommerce_single_product_summary', 'replace_single_subscription_add_to_cart_button', 1 ); function replace_single_subscription_add_to_cart_button() { global $product; if ( ! $product->is_type( 'subscription' ) || ! has_active_product_subscription( $product->get_id() ) ) { return; } // 移除默认加入购物车按钮 if ( $product->is_type( 'variable' ) ) { remove_action( 'woocommerce_single_variation', 'woocommerce_single_variation_add_to_cart_button', 20 ); add_action( 'woocommerce_single_variation', 'custom_single_subscription_enter_button', 20 ); } else { remove_action( 'woocommerce_single_product_summary', 'woocommerce_template_single_add_to_cart', 30 ); add_action( 'woocommerce_single_product_summary', 'custom_single_subscription_enter_button', 30 ); } } // 渲染自定义进入课程按钮 function custom_single_subscription_enter_button() { global $product; $enter_link = get_field( 'link_enter_class', $product->get_id() ); if ( empty( $enter_link ) ) { return; } printf( '<a href="%s" class="button alt add_to_cart_button enter_class_button">%s</a>', esc_url( $enter_link ), esc_html__( 'Enter Class', 'woocommerce' ) ); }
代码说明
has_active_product_subscription函数:- 仅对登录用户生效,检查用户是否拥有当前产品的活跃订阅(通过关联订单项确保是对应产品的订阅)
- 使用
$wpdb->prepare()处理SQL查询,避免注入风险
- 产品列表页钩子:
- 仅针对订阅类型产品生效
- 调用
get_field时传入产品ID,确保获取当前产品的ACF字段值 - 使用
esc_url()和esc_html()做安全转义
- 产品详情页钩子:
- 区分变量订阅产品和普通订阅产品,正确移除默认按钮并添加自定义按钮
- 增加ACF字段为空时的容错处理
内容的提问来源于stack exchange,提问作者Hoàng Nguyễn
相关产品推荐
相关产品推荐

