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

WooCommerce Subscriptions:为已订阅用户替换注册按钮为自定义字段链接

解决WooCommerce订阅产品替换“加入购物车”为“进入课程”按钮的问题

原代码核心问题分析

  1. 参数传递错误:has_active_subscription函数用于检查用户是否有活跃订阅,但调用时错误传入了产品ID而非用户ID,导致逻辑完全失效。
  2. SQL查询不安全:直接拼接用户ID到SQL语句中,存在注入风险。
  3. HTML渲染错误:使用HTML实体(如<、")输出按钮标签,导致页面无法正确解析为可点击的按钮。
  4. 未限定目标产品:原逻辑会对所有产品生效,无法只针对特定订阅产品替换按钮。

修正后的完整代码

/**
 * 检查当前登录用户是否拥有指定产品的活跃订阅
 * @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' )
    );
}

代码说明

  1. has_active_product_subscription函数:
    • 仅对登录用户生效,检查用户是否拥有当前产品的活跃订阅(通过关联订单项确保是对应产品的订阅)
    • 使用$wpdb->prepare()处理SQL查询,避免注入风险
  2. 产品列表页钩子:
    • 仅针对订阅类型产品生效
    • 调用get_field时传入产品ID,确保获取当前产品的ACF字段值
    • 使用esc_url()和esc_html()做安全转义
  3. 产品详情页钩子:
    • 区分变量订阅产品和普通订阅产品,正确移除默认按钮并添加自定义按钮
    • 增加ACF字段为空时的容错处理

内容的提问来源于stack exchange,提问作者Hoàng Nguyễn

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 16:16:06