在自定义文章类型归档页按分类法分组输出内容

在自定义文章类型归档页按分类法分组输出内容

产品总页需要按分类展示产品时,可以先查询分类,再为每个分类建立独立的 WP_Query。旧代码使用 query_posts() 覆盖主查询,会破坏分页和全局状态,WordPress 官方也明确不建议这样做。

以下示例假设文章类型为 product,分类法为 product_category

<?php
$terms = get_terms(
    array(
        'taxonomy'   => 'product_category',
        'parent'     => 0,
        'hide_empty' => true,
        'orderby'    => 'name',
    )
);

if ( is_wp_error( $terms ) || empty( $terms ) ) {
    get_template_part( 'template-parts/content', 'none' );
    return;
}

foreach ( $terms as $term ) :
    $term_url = get_term_link( $term );

    if ( is_wp_error( $term_url ) ) {
        continue;
    }

    $products = new WP_Query(
        array(
            'post_type'              => 'product',
            'post_status'            => 'publish',
            'posts_per_page'         => 6,
            'no_found_rows'          => true,
            'ignore_sticky_posts'    => true,
            'orderby'                => 'menu_order title',
            'order'                  => 'ASC',
            'tax_query'              => array(
                array(
                    'taxonomy' => 'product_category',
                    'field'    => 'term_id',
                    'terms'    => array( $term->term_id ),
                ),
            ),
        )
    );
    ?>

    <section
        class="product-group"
        aria-labelledby="term-<?php echo esc_attr( $term->term_id ); ?>"
    >
        <h2 id="term-<?php echo esc_attr( $term->term_id ); ?>">
            <a href="<?php echo esc_url( $term_url ); ?>">
                <?php echo esc_html( $term->name ); ?>
            </a>
        </h2>

        <?php if ( $products->have_posts() ) : ?>
            <div class="product-grid">
                <?php while ( $products->have_posts() ) : ?>
                    <?php
                    $products->the_post();
                    get_template_part(
                        'template-parts/content',
                        'product'
                    );
                    ?>
                <?php endwhile; ?>
            </div>
        <?php else : ?>
            <p>该分类暂无产品。</p>
        <?php endif; ?>
    </section>

    <?php wp_reset_postdata(); ?>
<?php endforeach; ?>

为什么使用模板片段

产品图片、标题、摘要和链接放在 template-parts/content-product.php,归档页、搜索页和分类页就能复用同一输出规则。图片建议使用特色图或附件 ID:

<?php if ( has_post_thumbnail() ) : ?>
    <a href="<?php the_permalink(); ?>">
        <?php
        the_post_thumbnail(
            'medium',
            array(
                'alt' => the_title_attribute(
                    array( 'echo' => false )
                ),
            )
        );
        ?>
    </a>
<?php endif; ?>

性能与分页

“每个分类一次查询”适合分类数量少、每组只展示几项的聚合页。若有几十个分类,会形成大量数据库查询。此时应考虑:

  • 只展示重点分类,由编辑在后台选择。
  • 缓存整个聚合区块,并在产品更新时失效。
  • 一次查询产品后在 PHP 中按 term 分组,但要明确一个产品属于多个分类时的重复规则。
  • 把归档页改成普通分页列表,分类仅作为筛选项。

如果只是修改当前归档主查询的筛选或排序,应使用 pre_get_posts,而不是创建第二个查询。

官方参考:WP_Queryquery_posts() 警告pre_get_posts

最后更新于

ihopeful Blog 由博主亲笔撰写,重要信息可放心引用。