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

WooCommerce:如何展示近30天内的畅销商品

如何在WooCommerce中展示近30天的畅销商品

Great question! The problem with your current code is that it uses WooCommerce's default total_sales meta field, which tracks cumulative sales across all time. That's why those flash-in-the-pan hot items keep showing up long after their popularity fades. To fix this, we need to calculate sales specifically for the last 30 days—here are two solid approaches to do that:


方法1:实时查询近30天销量(适合小订单量网站)

Since WooCommerce doesn't store a "last 30 days sales" field by default, we can query directly against its order tables to calculate these numbers on the fly. This works well if your site doesn't have thousands of orders cluttering up the database.

Here's the modified code:

<?php
global $wpdb;
// 计算30天前的时间戳
$thirty_days_ago = strtotime('-30 days');

// 先获取近30天的销量统计数据
$sales_data = $wpdb->get_results("
    SELECT 
        order_item_meta.meta_value AS product_id, 
        SUM(order_item_meta2.meta_value) AS sales_count
    FROM {$wpdb->prefix}woocommerce_order_items AS order_items
    LEFT JOIN {$wpdb->prefix}woocommerce_order_itemmeta AS order_item_meta 
        ON order_items.order_item_id = order_item_meta.order_item_id
    LEFT JOIN {$wpdb->prefix}woocommerce_order_itemmeta AS order_item_meta2 
        ON order_items.order_item_id = order_item_meta2.order_item_id
    LEFT JOIN {$wpdb->prefix}posts AS posts 
        ON order_items.order_id = posts.ID
    WHERE 
        order_items.order_item_type = 'line_item'
        AND order_item_meta.meta_key = '_product_id'
        AND order_item_meta2.meta_key = '_qty'
        AND posts.post_status IN ('wc-completed', 'wc-processing') // 只统计有效订单
        AND posts.post_date >= '".date('Y-m-d H:i:s', $thirty_days_ago)."'
    GROUP BY order_item_meta.meta_value
    ORDER BY sales_count DESC
    LIMIT 4
");

// 从销量数据中提取排序后的商品ID
$sorted_product_ids = wp_list_pluck($sales_data, 'product_id');

// 如果有符合条件的商品,查询完整数据并展示
if (!empty($sorted_product_ids)) {
    $loop = new WP_Query(array(
        'post_type'      => 'product',
        'posts_per_page' => 4,
        'post__in'       => $sorted_product_ids,
        'orderby'        => 'post__in', // 保持销量排序的顺序
        'meta_query'     => array(
            array(
                'key'     => '_stock_status',
                'value'   => 'instock',
                'compare' => '=', // 可选:只展示有库存的商品
            ),
        ),
    ));

    if ($loop->have_posts()) {
        while ($loop->have_posts()) : $loop->the_post();
            woocommerce_get_template_part('content', 'product');
        endwhile;
    } else {
        echo __('No products found');
    }
    wp_reset_postdata();
} else {
    echo __('No products found');
}
?>

这个方法的关键细节:

  • 仅统计标记为wc-completed或wc-processing的订单,避免包含已取消/退款的订单
  • 通过post_date >= [timestamp]筛选出近30天内的订单
  • 先计算销量并排序,再获取完整商品数据以保证展示顺序正确

方法2:定时更新自定义销量字段(适合大订单量网站)

如果你的网站订单量很大,上面的实时查询可能会拖慢页面加载速度。更好的方案是设置每日定时任务,计算近30天的销量并存储到自定义元字段中,之后直接用这个字段排序即可。

步骤1:添加定时任务和销量计算函数

将这段代码添加到主题的functions.php或自定义插件中:

// 设置每日定时任务,更新30天销量数据
add_action('wp', 'setup_30day_sales_cron');
function setup_30day_sales_cron() {
    if (!wp_next_scheduled('update_30day_sales')) {
        wp_schedule_event(time(), 'daily', 'update_30day_sales');
    }
}

// 计算并存储每个商品的近30天销量
add_action('update_30day_sales', 'calculate_30day_sales');
function calculate_30day_sales() {
    global $wpdb;
    $thirty_days_ago = strtotime('-30 days');

    // 获取近30天的销量数据
    $sales_data = $wpdb->get_results("
        SELECT 
            order_item_meta.meta_value AS product_id, 
            SUM(order_item_meta2.meta_value) AS sales_count
        FROM {$wpdb->prefix}woocommerce_order_items AS order_items
        LEFT JOIN {$wpdb->prefix}woocommerce_order_itemmeta AS order_item_meta 
            ON order_items.order_item_id = order_item_meta.order_item_id
        LEFT JOIN {$wpdb->prefix}woocommerce_order_itemmeta AS order_item_meta2 
            ON order_items.order_item_id = order_item_meta2.order_item_id
        LEFT JOIN {$wpdb->prefix}posts AS posts 
            ON order_items.order_id = posts.ID
        WHERE 
            order_items.order_item_type = 'line_item'
            AND order_item_meta.meta_key = '_product_id'
            AND order_item_meta2.meta_key = '_qty'
            AND posts.post_status IN ('wc-completed', 'wc-processing')
            AND posts.post_date >= '".date('Y-m-d H:i:s', $thirty_days_ago)."'
        GROUP BY order_item_meta.meta_value
    ");

    // 更新有销量商品的自定义元字段
    foreach ($sales_data as $data) {
        update_post_meta($data->product_id, '_30day_sales', $data->sales_count);
    }

    // 为近30天无销量的商品设置0值(可选)
    $all_products = get_posts(array(
        'post_type' => 'product',
        'posts_per_page' => -1,
        'fields' => 'ids'
    ));
    foreach ($all_products as $product_id) {
        if (!get_post_meta($product_id, '_30day_sales', true)) {
            update_post_meta($product_id, '_30day_sales', 0);
        }
    }
}

步骤2:简化商品查询

现在你可以用简洁的WP_Query获取畅销商品,就像你原来的代码一样,只是换成自定义字段:

<?php
$args = array(
    'post_type'      => 'product',
    'posts_per_page' => 4,
    'meta_key'       => '_30day_sales',
    'orderby'        => 'meta_value_num',
    'order'          => 'DESC',
    'meta_query'     => array(
        array(
            'key'     => '_30day_sales',
            'value'   => 0,
            'compare' => '>', // 可选:排除无销量的商品
        ),
        array(
            'key'     => '_stock_status',
            'value'   => 'instock',
            'compare' => '=', // 可选:只展示有库存的商品
        ),
    ),
);

$loop = new WP_Query($args);

if ($loop->have_posts()) {
    while ($loop->have_posts()) : $loop->the_post();
        woocommerce_get_template_part('content', 'product');
    endwhile;
} else {
    echo __('No products found');
}
wp_reset_postdata();
?>

为什么这个方法适合高流量网站:

  • 销量计算在后台每日运行一次,前端页面加载速度会快很多
  • 既能获得准确的销量数据,又不用在每次页面加载时查询订单表

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 07:03:23