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

WooCommerce 5.6+:新用户隐藏支票支付脚本的性能优化咨询

问题点分析
  • 全量订单查询冗余:原代码用numberposts => -1拉取当前用户所有已完成订单,而我们仅需确认用户是否存在至少一个符合条件的订单,全量查询会带来不必要的数据库查询和数据传输开销,用户订单越多性能损耗越明显。
  • 钩子触发过于频繁:woocommerce_available_payment_gateways钩子会在多个页面(产品页、购物车页、结账页甚至部分后台页面)触发,每次触发都执行一次数据库查询,重复查询的累积导致页面加载变慢。
  • 无结果缓存机制:每次调用has_bought()都会重新发起数据库查询,相同用户多次访问时会重复执行完全相同的查询操作,没有利用缓存减少重复开销。
优化方案

1. 优化订单查询逻辑

将全量查询改为存在性验证,只确认是否有符合条件的订单存在,大幅减少数据库负载:

function has_bought() {
    $user_id = get_current_user_id();
    if ( $user_id === 0 ) {
        return false; // 未登录用户直接返回false
    }

    // 用wpdb直接执行存在性查询,比get_posts更高效
    global $wpdb;
    $exists = $wpdb->get_var(
        $wpdb->prepare(
            "SELECT COUNT(ID) FROM {$wpdb->posts}
            LEFT JOIN {$wpdb->postmeta} ON {$wpdb->posts}.ID = {$wpdb->postmeta}.post_id
            WHERE {$wpdb->postmeta}.meta_key = '_customer_user'
            AND {$wpdb->postmeta}.meta_value = %d
            AND {$wpdb->posts}.post_type = 'shop_order'
            AND {$wpdb->posts}.post_status = 'wc-completed'
            LIMIT 1",
            $user_id
        )
    );

    return $exists > 0;
}

如果坚持使用get_posts,也可以调整参数减少返回数据:

function has_bought() {
    $user_id = get_current_user_id();
    if ( $user_id === 0 ) {
        return false;
    }

    $customer_orders = get_posts( array(
        'numberposts' => 1, // 仅取1条,确认存在即可
        'meta_key'    => '_customer_user',
        'meta_value'  => $user_id,
        'post_type'   => 'shop_order',
        'post_status' => 'wc-completed',
        'fields'      => 'ids' // 只返回ID,减少数据传输量
    ) );

    return !empty( $customer_orders );
}

2. 添加查询结果缓存

利用WordPress内置缓存机制,对查询结果进行缓存,避免重复查询:

function has_bought() {
    $user_id = get_current_user_id();
    if ( $user_id === 0 ) {
        return false;
    }

    // 定义缓存键
    $cache_key = 'customer_has_completed_order_' . $user_id;
    $has_bought = wp_cache_get( $cache_key, 'woocommerce' );

    if ( false === $has_bought ) {
        global $wpdb;
        $exists = $wpdb->get_var(
            $wpdb->prepare(
                "SELECT COUNT(ID) FROM {$wpdb->posts}
                LEFT JOIN {$wpdb->postmeta} ON {$wpdb->posts}.ID = {$wpdb->postmeta}.post_id
                WHERE {$wpdb->postmeta}.meta_key = '_customer_user'
                AND {$wpdb->postmeta}.meta_value = %d
                AND {$wpdb->posts}.post_type = 'shop_order'
                AND {$wpdb->posts}.post_status = 'wc-completed'
                LIMIT 1",
                $user_id
            )
        );

        $has_bought = $exists > 0;
        // 缓存结果1小时,可根据需求调整有效期
        wp_cache_set( $cache_key, $has_bought, 'woocommerce', 3600 );
    }

    return $has_bought;
}

也可以将结果存储到用户元数据中,在订单完成时更新,进一步减少查询:

// 订单完成时更新用户元数据
add_action( 'woocommerce_order_status_completed', 'update_customer_bought_meta' );
function update_customer_bought_meta( $order_id ) {
    $order = wc_get_order( $order_id );
    $user_id = $order->get_user_id();
    if ( $user_id ) {
        update_user_meta( $user_id, '_has_completed_order', 'yes' );
    }
}

function has_bought() {
    $user_id = get_current_user_id();
    if ( $user_id === 0 ) {
        return false;
    }

    $has_bought = get_user_meta( $user_id, '_has_completed_order', true );
    return $has_bought === 'yes';
}

3. 限制钩子触发场景

只在需要加载支付网关的页面(如结账页、购物车页)执行过滤逻辑,避免无关页面触发:

add_filter('woocommerce_available_payment_gateways', 'customize_payment_gateways');
function customize_payment_gateways($gateways) {
    // 仅在结账页或购物车页执行逻辑
    if ( !is_checkout() && !is_cart() ) {
        return $gateways;
    }

    if (!has_bought()) {
        if (isset($gateways['cheque'])) {
            unset($gateways['cheque']);
        }
    }
    return $gateways;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 14:53:24