如何延迟WordPress函数2秒执行或优化热销徽章功能?
问题分析与解决方案
你的函数崩溃核心原因不是执行时机,而是实时查询+遍历所有关联订单的性能爆炸——每个产品归档页的商品都会触发一次全量订单查询,再逐个加载订单、遍历订单项求和,数据库和PHP资源直接被耗尽。Argos的延迟显示是前端优化,但其后台肯定提前做了数据预计算,而非实时查询。
一、最优解决方案:预计算销量+前端异步加载(完全对标Argos)
1. 后台预计算周销量(彻底解决性能问题)
通过订单完成钩子和定时任务,提前把每个产品的周销量存在产品元数据里,避免实时查询:
// 订单完成时,累加对应产品的周销量 add_action('woocommerce_order_status_completed', 'update_product_weekly_sales', 10, 1); function update_product_weekly_sales($order_id) { $order = wc_get_order($order_id); $week_start = date('Y-m-d', strtotime('last Monday')); // 以周一为周起始 $meta_key = 'weekly_sales_' . $week_start; foreach ($order->get_items() as $item) { $product_id = $item->get_product_id(); $qty = $item->get_quantity(); // 累加销量到对应周的元字段 $current_sales = get_post_meta($product_id, $meta_key, true); update_post_meta($product_id, $meta_key, absint($current_sales) + $qty); } } // 每周一凌晨自动清理两周前的旧销量数据(避免元数据冗余) add_action('wp_weekly_sales_cleanup', 'cleanup_old_weekly_sales'); function cleanup_old_weekly_sales() { $two_weeks_ago = date('Y-m-d', strtotime('-2 weeks last Monday')); global $wpdb; $wpdb->query($wpdb->prepare( "DELETE FROM $wpdb->postmeta WHERE meta_key = %s", 'weekly_sales_' . $two_weeks_ago )); } // 注册定时任务 add_action('wp', function() { if (!wp_next_scheduled('wp_weekly_sales_cleanup')) { wp_schedule_event(strtotime('next Monday 00:00:00'), 'weekly', 'wp_weekly_sales_cleanup'); } });
2. 前端异步加载徽章(实现页面加载后显示)
不在PHP循环里直接输出徽章,先渲染占位容器,等页面加载完成后批量请求数据:
第一步:PHP渲染占位容器
add_action('woocommerce_before_shop_loop_item_title', 'add_trending_badge_placeholder', 11); function add_trending_badge_placeholder() { global $product; echo '<div class="trending-block-loop" data-product-id="' . $product->get_ID() . '"></div>'; }
第二步:JS批量请求并显示徽章
把这段代码存为主题目录下的js/trending-badge.js:
document.addEventListener('DOMContentLoaded', function() { const badgeContainers = document.querySelectorAll('.trending-block-loop'); const productIds = Array.from(badgeContainers).map(container => container.dataset.productId); if (!productIds.length) return; // 批量请求销量数据 fetch('/wp-admin/admin-ajax.php', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'X-WP-Nonce': wpApiSettings.nonce }, body: `action=get_product_weekly_sales&product_ids=${productIds.join(',')}` }) .then(res => res.json()) .then(salesData => { badgeContainers.forEach(container => { const productId = container.dataset.productId; if (salesData[productId] && salesData[productId] > 20) { container.innerHTML = `<svg width="16" height="16" viewBox="0 0 24 24"><path d="M8.625 0c.61 7.189-5.625 9.664-5.625 15.996 0 4.301 3.069 7.972 9 8.004 5.931.032 9-4.414 9-8.956 0-4.141-2.062-8.046-5.952-10.474.924 2.607-.306 4.988-1.501 5.808.07-3.337-1.125-8.289-4.922-10.378zm4.711 13c3.755 3.989 1.449 9-1.567 9-1.835 0-2.779-1.265-2.769-2.577.019-2.433 2.737-2.435 4.336-6.423z"/></svg> Selling Fast`; } else { container.style.display = 'none'; } }); }); });
第三步:注册AJAX接口并本地化JS
在主题functions.php中添加:
add_action('wp_enqueue_scripts', 'enqueue_trending_badge_script'); function enqueue_trending_badge_script() { wp_enqueue_script('trending-badge', get_template_directory_uri() . '/js/trending-badge.js', [], '1.0', true); // 传递WP安全验证nonce wp_localize_script('trending-badge', 'wpApiSettings', [ 'nonce' => wp_create_nonce('wp_rest') ]); } // AJAX处理函数:返回批量产品的周销量 add_action('wp_ajax_get_product_weekly_sales', 'get_product_weekly_sales'); add_action('wp_ajax_nopriv_get_product_weekly_sales', 'get_product_weekly_sales'); function get_product_weekly_sales() { check_ajax_referer('wp_rest'); $product_ids = explode(',', $_POST['product_ids']); $week_start = date('Y-m-d', strtotime('last Monday')); $meta_key = 'weekly_sales_' . $week_start; $sales_data = []; foreach ($product_ids as $id) { $sales_data[$id] = absint(get_post_meta($id, $meta_key, true)); } wp_send_json($sales_data); wp_die(); }
二、临时治标方案:仅延迟前端执行(不解决后台性能问题)
如果不想改动后端逻辑,仅做前端延迟显示(但后台查询压力依然存在,不推荐):
add_action('woocommerce_before_shop_loop_item_title', 'delayed_trending_badge', 11); function delayed_trending_badge() { global $product; $product_id = $product->get_ID(); echo '<div class="trending-container" data-product-id="' . $product_id . '"></div>'; echo '<script> setTimeout(() => { fetch("/wp-admin/admin-ajax.php", { method: "POST", headers: { "Content-Type": "application/x-www-form-urlencoded", "X-WP-Nonce": wpApiSettings.nonce }, body: `action=check_trending&product_id=' . $product_id . '` }) .then(res => res.text()) .then(html => { document.querySelector("[data-product-id=' . $product_id . ']").innerHTML = html; }); }, 2000); </script>'; } // AJAX处理函数(复用原查询逻辑,性能差) add_action('wp_ajax_check_trending', 'check_trending'); add_action('wp_ajax_nopriv_check_trending', 'check_trending'); function check_trending() { $product_id = $_POST['product_id']; $all_orders = wc_get_orders([ 'limit' => -1, 'status' => array_map('wc_get_order_status_name', wc_get_is_paid_statuses()), 'date_after' => date('Y-m-d', strtotime('-1 week')), 'return' => 'ids', 'meta_query' => [['key' => '_product_id', 'value' => $product_id]] ]); $count = 0; foreach ($all_orders as $order_id) { $order = wc_get_order($order_id); foreach ($order->get_items() as $item) { if ($item->get_product_id() == $product_id) { $count += absint($item['qty']); } } } if ($count > 20) { echo "<div class='trending-block-loop'><svg width='16' height='16' viewBox='0 0 24 24'><path d='M8.625 0c.61 7.189-5.625 9.664-5.625 15.996 0 4.301 3.069 7.972 9 8.004 5.931.032 9-4.414 9-8.956 0-4.141-2.062-8.046-5.952-10.474.924 2.607-.306 4.988-1.501 5.808.07-3.337-1.125-8.289-4.922-10.378zm4.711 13c3.755 3.989 1.449 9-1.567 9-1.835 0-2.779-1.265-2.769-2.577.019-2.433 2.737-2.435 4.336-6.423z'/></svg> Selling Fast</div>"; } wp_die(); }
内容的提问来源于stack exchange,提问作者FoamyMedia
相关产品推荐
相关产品推荐

