WordPress开发笔记

WordPress分类文章总数计算的实现方法及代码

WordPress分类文章总数计算并非那么简洁,很多时候,我们需要满足以下条件:

1、如果该分类存在子分类或多层级子分类,应将该分类及其下所有层级子分类中的文章全部计算在内。

2、如果该分类没有子分类,则计算该分类中的文章总数。

SQL 版本

public function get_tax_posts_count_with_children($term, $taxonomy) {
    // 确保 $term 是有效的术语对象
    if (is_numeric($term)) {
        $term = get_term($term, $taxonomy);
    }

    if (is_wp_error($term) || !$term) {
        return 0;
    }

    // 获取所有子分类ID(包括子孙分类)
    $child_terms = get_term_children($term->term_id, $taxonomy);
    $term_ids = [];

    // 添加当前分类ID
    $term_ids[] = (int) $term->term_id;

    // 添加所有有效的子分类ID
    if (!is_wp_error($child_terms) && !empty($child_terms)) {
        foreach ($child_terms as $child_term_id) {
            $term_ids[] = (int) $child_term_id;
        }
    }

    // 去重
    $term_ids = array_unique($term_ids);

    // 如果只有一个分类(没有子分类),直接查询该分类的文章数量
    if (count($term_ids) === 1) {
        return (int) $term->count;
    }

    // 多个分类时进行联表查询
    global $wpdb;

    $placeholders = implode(',', array_fill(0, count($term_ids), '%d'));

    // 获取所有公开的文章类型
    $post_types = get_post_types(array('public' => true));
    $post_type_placeholders = implode(',', array_fill(0, count($post_types), '%s'));

    // 合并所有参数
    $params = array_merge($term_ids, $post_types, [$taxonomy]);

    $query = $wpdb->prepare(
        "SELECT COUNT(DISTINCT p.ID)
        FROM {$wpdb->posts} p
        INNER JOIN {$wpdb->term_relationships} tr ON p.ID = tr.object_id
        INNER JOIN {$wpdb->term_taxonomy} tt ON tr.term_taxonomy_id = tt.term_taxonomy_id
        WHERE tt.term_id IN ($placeholders)
        AND p.post_status = 'publish'
        AND p.post_type IN ($post_type_placeholders)
        AND tt.taxonomy = %s",
        $params
    );

    $count = (int) $wpdb->get_var($query);

    return $count;
}

主要实现:

  1. 获取所有公开的文章类型:使用 get_post_types(array('public' => true)) 获取所有公开的文章类型
  2. 动态构建文章类型条件:使用 IN 条件来包含所有公开的文章类型
  3. 参数处理:正确合并术语ID、文章类型和分类法参数

WP_Query 版本

如果您更喜欢使用 WordPress 原生函数,这里是一个使用 WP_Query 的版本:

public function get_tax_posts_count_with_children($term, $taxonomy) {
    // 确保 $term 是有效的术语对象
    if (is_numeric($term)) {
        $term = get_term($term, $taxonomy);
    }

    if (is_wp_error($term) || !$term) {
        return 0;
    }

    // 获取所有子分类ID(包括当前分类)
    $child_terms = get_term_children($term->term_id, $taxonomy);
    $term_ids = [(int) $term->term_id];

    if (!is_wp_error($child_terms) && !empty($child_terms)) {
        $term_ids = array_merge($term_ids, array_map('intval', $child_terms));
        $term_ids = array_unique($term_ids);

        // 使用 WP_Query 统计所有公开文章类型的文章数量
        $query_args = [
            'post_type' => get_post_types(array('public' => true)), // 所有公开文章类型
            'post_status' => 'publish',
            'fields' => 'ids',
            'posts_per_page' => -1,
            'tax_query' => [
                [
                    'taxonomy' => $taxonomy,
                    'field' => 'term_id',
                    'terms' => $term_ids,
                    'operator' => 'IN',
                ]
            ]
        ];

        $query = new WP_Query($query_args);
        return (int) $query->found_posts;
    }

    // 没有子分类时直接返回当前分类计数
    return (int) $term->count;
}

两种方案的比较

  • SQL 版本:性能更好,适合处理大量数据
  • WP_Query 版本:更符合 WordPress 开发规范,更容易维护

两个版本都能正确统计所有公开文章类型(post, page, 以及任何自定义的公开文章类型)在指定分类及其子分类中的文章总数。

推荐使用 SQL 版本,因为它在处理大量分类和文章时性能更优。