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

如何在不影响WooCommerce产品页面加载速度的前提下添加用户专属价目表价格

如何在不影响WooCommerce产品页面加载速度的前提下添加用户专属价目表价格

看起来你已经搞定了用户专属价目表价格的显示逻辑,但产品列表页加载慢的问题确实头疼——现在你的代码每渲染一个产品就执行一次数据库查询,要是列表页有20个产品,就会触发20次SQL请求,这肯定会拖慢页面速度。结合你提到的“价格频繁变动,没法用长时效缓存”的情况,我给你几个针对性的优化方案,既能降数据库压力,又能保证价格的实时性:


核心优化思路:减少数据库查询次数

最影响性能的就是N+1查询问题(每个产品单独查一次),我们要把它改成“1次查询搞定当前页所有产品的专属价格”,再搭配短时效缓存,完美平衡速度和实时性。

1. 预加载产品列表的专属价格(关键优化)

在产品列表开始查询时,提前收集当前页所有产品的SKU,一次性从数据库拉取所有对应的专属价格,存到WP的内存缓存里。这样整个列表页只需要1次数据库查询,而不是每个产品1次。

添加这个钩子函数来实现预加载:

add_action( 'woocommerce_product_query', 'preload_user_pricelist_prices', 10, 2 );
function preload_user_pricelist_prices( $q, $query ) {
    // 后台页面和管理员直接跳过
    if ( is_admin() || current_user_can('manage_options') ) {
        return;
    }

    $current_user_id = get_current_user_id();
    $pricelist_id = get_user_meta( $current_user_id, 'user_pricelist_b2bwoo', true );
    
    // 未登录用户用固定价目表ID=31
    if ( !is_user_logged_in() ) {
        $pricelist_id = 31;
    }

    if ( empty( $pricelist_id ) ) {
        return;
    }

    // 获取当前查询的所有产品
    $products = $q->get_posts();
    if ( empty( $products ) ) {
        return;
    }

    // 收集所有非空的产品SKU
    $skus = array();
    foreach ( $products as $product_post ) {
        $product = wc_get_product( $product_post->ID );
        $sku = $product->get_sku();
        if ( !empty( $sku ) ) {
            $skus[] = $sku;
        }
    }

    if ( empty( $skus ) ) {
        return;
    }

    // 批量查询当前价目表下所有SKU的价格
    global $wpdb;
    $table_name = $wpdb->prefix . 'woo_pricelists_products';
    $sku_placeholders = implode( ', ', array_fill( 0, count( $skus ), '%s' ) );
    $query = $wpdb->prepare(
        "SELECT sku, final_price FROM $table_name WHERE pricelist_id = %d AND sku IN ($sku_placeholders)",
        array_merge( array( $pricelist_id ), $skus )
    );

    $price_rows = $wpdb->get_results( $query, ARRAY_A );
    if ( empty( $price_rows ) ) {
        return;
    }

    // 把结果转成SKU为键的数组,方便后续快速查找
    $price_map = array();
    foreach ( $price_rows as $row ) {
        $price_map[ $row['sku'] ] = $row['final_price'];
    }

    // 缓存10分钟(可根据你的价格更新频率调整,比如5分钟)
    wp_cache_set( 'user_pricelist_prices_' . $pricelist_id, $price_map, '', 600 );
}

2. 重构原有价格替换函数,优先用缓存

修改你现有的show_pricelist_price函数,先从缓存里拿价格,缓存没有的时候再走单个查询(比如单个产品详情页),同时把单个查询的结果也缓存起来:

add_filter( 'woocommerce_product_get_price', array( $this, 'show_pricelist_price' ), 10, 2);
add_filter( 'woocommerce_product_get_sale_price', array( $this, 'show_pricelist_price' ), 10, 2);
add_filter( 'woocommerce_product_variation_get_price', array( $this, 'show_pricelist_price' ), 10, 2);

public function show_pricelist_price($price, $product) {
    // 后台和管理员直接返回原价格
    if ( is_admin() || current_user_can('manage_options') ) {
        return $price;
    }

    $current_user_id = get_current_user_id();
    $pricelist_id = get_user_meta( $current_user_id, 'user_pricelist_b2bwoo', true );
    
    // 未登录用户用固定价目表
    if ( !is_user_logged_in() ) {
        $pricelist_id = 31;
    }

    $sku = $product->get_sku();
    if ( empty( $sku ) || empty( $pricelist_id ) ) {
        return $price;
    }

    // 1. 先尝试从预加载的缓存中获取价格
    $price_map = wp_cache_get( 'user_pricelist_prices_' . $pricelist_id );
    if ( isset( $price_map[ $sku ] ) ) {
        $final_price = $price_map[ $sku ];
        // 保留你原有的逻辑:产品有促销价时返回原价格
        $sale_price = get_post_meta( $product->get_id(), '_sale_price', true );
        return empty( $sale_price ) ? $final_price : $price;
    }

    // 2. 缓存没有的话,执行单个查询(比如详情页)
    global $wpdb;
    $table_name = $wpdb->prefix . 'woo_pricelists_products';
    $query = $wpdb->prepare( 
        "SELECT final_price FROM $table_name WHERE pricelist_id = %d AND sku = %s", 
        $pricelist_id, $sku 
    );
    $final_price = $wpdb->get_var( $query );

    if ( !empty( $final_price ) ) {
        $sale_price = get_post_meta( $product->get_id(), '_sale_price', true );
        if ( empty( $sale_price ) ) {
            // 把单个查询结果也缓存10分钟
            wp_cache_set( 'user_pricelist_price_' . $pricelist_id . '_' . $sku, $final_price, '', 600 );
            return $final_price;
        }
    }

    // 没有找到专属价格时返回原价格
    return $price;
}

3. 给数据库表加索引(进一步提速查询)

现在的查询依赖pricelist_id和sku两个字段,给它们加个联合索引能让数据库查询速度大幅提升。你可以在phpMyAdmin或者数据库管理工具里执行这条SQL:

CREATE INDEX idx_pricelist_sku ON 你的表前缀woo_pricelists_products (pricelist_id, sku);

把你的表前缀换成WordPress实际的数据库表前缀(一般是wp_)。

4. 价格更新时主动清理缓存

因为你说价格变动频繁,除了用短时效缓存,还可以在价目表的产品价格更新时,主动清理对应价目表的缓存,这样用户下次访问就能立刻看到新价格。比如在你编辑价目表产品的保存逻辑里加:

// 假设$pricelist_id是当前编辑的价目表ID
wp_cache_delete( 'user_pricelist_prices_' . $pricelist_id );

优化效果说明

  • 产品列表页:从N次数据库查询变成1次查询,加载速度会有质的提升;
  • 单个产品页:首次查询后缓存10分钟,重复访问不需要再查数据库;
  • 实时性:10分钟的缓存时效(可调整)既保证了性能,又不会让用户看到太久之前的旧价格,结合主动清理缓存,更新后能快速生效。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.08 09:24:53