产品总页需要按分类展示产品时,可以先查询分类,再为每个分类建立独立的 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,而不是创建第二个查询。