如何在不影响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
相关产品推荐
相关产品推荐

