在主題開發、數據統計、側邊欄展示中,常需獲取「某分類下的文章數」。本文提供四種單分類統計方法(性能遞增),及一種**遞歸統計分類及其所有子孫分類文章總數**的通用函數,並給出性能對比與選型建議。
| 方法 | 代碼 | 執行時間 | 特點 |
|---|---|---|---|
| 1. 直接 SQL(最快) | global $wpdb;
$count = $wpdb->get_var($wpdb->prepare(
"SELECT count FROM {$wpdb->term_taxonomy}
JOIN {$wpdb->terms} ON {$wpdb->terms}.term_id = {$wpdb->term_taxonomy}.term_id
WHERE {$wpdb->terms}.slug = %s", $slug)); | ~0.002s | 單次查詢,無對象開銷,適合高頻調用 |
| 2. get_category() | $cat = get_category($cat_id); $count = $cat->count; | ~0.004s | 返回完整分類對象,利用緩存,推薦通用 |
| 3. get_category_by_slug() | $cat = get_category_by_slug($slug); $count = $cat->count; | ~0.008s | 需按 slug 查詢,額外開銷 |
| 4. wp_list_categories() | echo strip_tags(wp_list_categories([
'include' => $cat_id,
'show_count' => 1,
'echo' => 0,
'style' => 'none',
])); | ~0.015s | 輸出 HTML 後再 strip_tags,最慢,僅供顯示用 |
注意:以上方法**均不包含子分類文章數**,僅統計該分類直接掛載的文章。
<?php
/**
* 獲取分類及其所有子孫分類的文章總數
* @param int $cat_id 分類 ID
* @return int 總文章數
*/
function ludou_get_cat_tree_post_count($cat_id) {
$cat = get_category($cat_id);
if (!$cat) return 0;
$count = (int) $cat->count; // 當前分類文章數
// 獲取所有子孫分類(child_of 參數遞歸查詢)
$children = get_terms([
'taxonomy' => 'category',
'child_of' => $cat_id,
'hide_empty' => false, // 包含空分類
'fields' => 'ids', // 僅返回 ID,提升性能
]);
if ($children) {
// 批量獲取子分類對象並累加 count
$child_cats = get_categories([
'include' => $children,
'hide_empty' => false,
]);
foreach ($child_cats as $child) {
$count += $child->count;
}
}
return $count;
}
// 單分類
echo '分類 "news" 文章數:' . ludou_get_cat_tree_post_count(get_category_by_slug('news')->term_id);
// 模板中顯示
$cat_id = 123;
printf(
'分類 %s 及其子分類共有 %d 篇文章',
get_cat_name($cat_id),
ludou_get_cat_tree_post_count($cat_id)
);
function ludou_get_cat_tree_post_count_fast($cat_id) {
global $wpdb;
// 利用 term_taxonomy 表的 parent 字段遞歸查詢所有子孫 term_id
$sql = "SELECT SUM(count) FROM {$wpdb->term_taxonomy}
WHERE term_id IN (
SELECT term_id FROM (
SELECT term_id FROM {$wpdb->term_taxonomy}
WHERE taxonomy = 'category'
START WITH term_id = %d
CONNECT BY PRIOR term_id = parent
) t
)";
// MySQL 8.0+ 支援 WITH RECURSIVE,MariaDB 10.2+ 支援 CONNECT BY
// 低版本需用存儲過程或 PHP 端遞歸
return (int) $wpdb->get_var($wpdb->prepare($sql, $cat_id));
}
MySQL 8.0+ 標準遞歸 CTE 寫法:
WITH RECURSIVE cat_tree AS (
SELECT term_id FROM {$wpdb->term_taxonomy} WHERE term_id = %d AND taxonomy = 'category'
UNION ALL
SELECT tt.term_id FROM {$wpdb->term_taxonomy} tt
JOIN cat_tree ct ON tt.parent = ct.term_id
WHERE tt.taxonomy = 'category'
)
SELECT SUM(count) FROM {$wpdb->term_taxonomy}
WHERE term_id IN (SELECT term_id FROM cat_tree);
// 緩存 1 小時,發布/刪除文章時清理
function ludou_get_cat_count_cached($cat_id, $with_children = false) {
$key = 'cat_count_' . $cat_id . ($with_children ? '_tree' : '');
$count = wp_cache_get($key, 'ludou_counts');
if ($count !== false) return $count;
$count = $with_children
? ludou_get_cat_tree_post_count($cat_id)
: get_category($cat_id)->count;
wp_cache_set($key, $count, 'ludou_counts', HOUR_IN_SECONDS);
return $count;
}
// 掛載清理鉤子
add_action('transition_post_status', function($new, $old, $post) {
if ($post->post_type === 'post') {
wp_cache_flush('ludou_counts');
}
});
掌握單分類與樹狀統計的區別,選對方法並加上緩存,能讓分類文章數顯示既準確又高效。