如何快速准确获取Woocommerce各层级自定义分类销售总额?
WooCommerce自定义分类销售总额导出性能优化
问题背景
站点使用自定义产品分类my_taxonomy,层级结构为Level0→Level1→Level2,需要统计Level1和Level2分类的销售总额并导出CSV。原代码在订单量、分类数量较多时,因多层循环嵌套、重复数据库查询导致执行超时或站点崩溃。
核心优化方案
1. 用SQL直接统计总额,替代多层循环遍历
原代码通过wc_get_orders获取所有订单后,嵌套循环订单、商品、分类进行判断累加,时间复杂度极高。改为直接通过SQL关联订单、订单项、产品分类表,一次性计算出各分类的销售总额,大幅减少数据库查询次数和内存占用。
2. 批量获取分类并构建层级映射
原代码嵌套调用get_terms三次,每次都会发起数据库请求。改为一次性获取所有my_taxonomy分类,然后通过父ID构建Level1和Level2的映射关系,减少数据库查询次数。
3. 直接输出CSV,跳过服务器中间文件
原代码先将CSV写入服务器文件再读取输出,增加了磁盘IO开销。改为直接通过php://output输出CSV内容,省去文件读写步骤。
4. 优化旧文件清理逻辑
原代码每次导出都删除所有旧文件,改为只删除7天前的旧文件,避免不必要的磁盘操作。
优化后的完整代码
function handle_csv_export() { if (!wp_verify_nonce($_POST['_wpnonce'], 'generate-csv')) { wp_die('非法请求'); } global $wpdb; // 一次性获取所有my_taxonomy分类,构建层级映射 $all_terms = get_terms(array( 'taxonomy' => 'my_taxonomy', 'hide_empty' => false, 'fields' => 'all' )); $level1_map = []; // key: term_id, value: term_name $level2_map = []; // key: term_id, value: term_name foreach ($all_terms as $term) { // 筛选Level0下的Level1(父ID为Level0分类ID) $parent_term = get_term($term->parent, 'my_taxonomy'); if ($parent_term && $parent_term->parent === 0) { $level1_map[$term->term_id] = $term->name; } // 筛选Level1下的Level2(父ID为Level1分类ID) elseif (isset($level1_map[$term->parent])) { $level2_map[$term->term_id] = $term->name; } } // SQL查询Level1分类的销售总额 $level1_term_ids = !empty($level1_map) ? implode(',', array_keys($level1_map)) : '0'; $level1_sql = " SELECT t.name AS term_name, SUM(oim.meta_value) AS total_amount FROM {$wpdb->prefix}woocommerce_order_items oi JOIN {$wpdb->prefix}woocommerce_order_itemmeta oim ON oi.order_item_id = oim.order_item_id JOIN {$wpdb->prefix}posts p ON oi.order_id = p.ID JOIN {$wpdb->prefix}term_relationships tr ON oi.product_id = tr.object_id JOIN {$wpdb->prefix}term_taxonomy tt ON tr.term_taxonomy_id = tt.term_taxonomy_id JOIN {$wpdb->prefix}terms t ON tt.term_id = t.term_id WHERE p.post_status IN ('wc-completed', 'wc-processing', 'wc-on-hold') AND oim.meta_key = '_line_total' AND tt.taxonomy = 'my_taxonomy' AND tt.term_id IN ($level1_term_ids) GROUP BY t.term_id "; $level1_results = $wpdb->get_results($level1_sql, ARRAY_A); // SQL查询Level2分类的销售总额 $level2_term_ids = !empty($level2_map) ? implode(',', array_keys($level2_map)) : '0'; $level2_sql = " SELECT t.name AS term_name, SUM(oim.meta_value) AS total_amount FROM {$wpdb->prefix}woocommerce_order_items oi JOIN {$wpdb->prefix}woocommerce_order_itemmeta oim ON oi.order_item_id = oim.order_item_id JOIN {$wpdb->prefix}posts p ON oi.order_id = p.ID JOIN {$wpdb->prefix}term_relationships tr ON oi.product_id = tr.object_id JOIN {$wpdb->prefix}term_taxonomy tt ON tr.term_taxonomy_id = tt.term_taxonomy_id JOIN {$wpdb->prefix}terms t ON tt.term_id = t.term_id WHERE p.post_status IN ('wc-completed', 'wc-processing', 'wc-on-hold') AND oim.meta_key = '_line_total' AND tt.taxonomy = 'my_taxonomy' AND tt.term_id IN ($level2_term_ids) GROUP BY t.term_id "; $level2_results = $wpdb->get_results($level2_sql, ARRAY_A); // 准备CSV内容并直接输出到浏览器 header('Content-Type: text/csv'); header('Content-Disposition: attachment; filename="taxonomy-sales-export.csv"'); $output = fopen('php://output', 'w'); // 写入Level1数据 fputcsv($output, ['Level1分类', '销售总额']); foreach ($level1_results as $row) { fputcsv($output, [$row['term_name'], number_format($row['total_amount'], 2) . '$']); } // 空行分隔 fputcsv($output, []); // 写入Level2数据 fputcsv($output, ['Level2分类', '销售总额']); foreach ($level2_results as $row) { fputcsv($output, [$row['term_name'], number_format($row['total_amount'], 2) . '$']); } fclose($output); // 清理7天前的旧导出文件 $upload_dir = wp_upload_dir(); $folder_path = $upload_dir['basedir'] . '/myorders'; if (file_exists($folder_path)) { $expire_time = time() - (7 * 24 * 60 * 60); $files = glob($folder_path . '/*.csv'); foreach ($files as $file) { if (filemtime($file) < $expire_time) { unlink($file); } } } exit; }
优化效果说明
- 时间复杂度大幅降低:原代码需要遍历所有订单×所有商品×所有分类,优化后仅通过2次SQL查询完成统计,性能提升显著。
- 减少数据库查询次数:原代码多次调用
get_terms和has_term,优化后仅1次分类查询+2次统计查询。 - 降低内存占用:无需加载所有订单和商品数据到内存,直接通过数据库计算结果。
- 减少磁盘IO:直接输出CSV,避免中间文件的读写操作。
内容的提问来源于stack exchange,提问作者Dias
相关产品推荐
相关产品推荐

