WordPress自定义分类:指定分类术语始终显示在末尾的实现问题
问题:自定义分类按文章数排序并将特定分类固定在末尾
我已创建名为Jobs的自定义文章类型,关联work-category自定义分类,当前使用以下代码可按分类下文章数量降序展示分类及对应文章(代码正常运行):
<div class="col-lg-10"> <?php $terms = get_terms([ 'taxonomy' => 'work-category', 'hide_empty' => true, 'orderby' => 'count', 'order' => 'DESC', ]); if ($terms) { foreach ($terms as $category) { ?> <h2 class="category-h2"> <?= $category->name ?> </h2> <?php $posts = get_posts(array( 'posts_per_page' => -1, 'post_type' => 'jobs', 'tax_query' => [ [ 'taxonomy' => 'work-category', 'field' => 'term_id', 'terms' => $category->term_id, ] ] )); if ( $posts ) { foreach( $posts as $post ) { setup_postdata( $post ); include 'WorkView.php'; }; wp_reset_postdata(); } } } else { //no categories $posts = get_posts(array( 'posts_per_page' => -1, 'post_type' => 'career' )); if ( $posts ) { foreach( $posts as $post ) { setup_postdata( $post ); include 'JobListThumb.php'; }; wp_reset_postdata(); } } ?> </div>
新增需求:给work-category分类添加了名为stick_to_end的自定义字段,要求所有分类按文章数量降序排列,但标记该字段的分类始终显示在末尾。我尝试了两种方法均无效:
- 在
orderby中使用数组:'orderby' => array ('count' => DESC, 'stick_to_end' => ASC) - 使用
meta_query:
'meta_query' => array( 'relation' => 'AND', array( 'key' => 'count', 'value' => EXISTS, ), array( 'key' => 'stick_to_end', 'compare' => '=', 'value' => false, ), )
问题分析
你之前的方法无效的原因:
get_terms的orderby参数默认不支持直接将自定义元字段与分类自带的count字段组合排序,因为默认查询不会加载分类元数据,所以数组排序规则无法生效。- 第二种方法中的
meta_query逻辑错误:count是分类自带的文章数字段,不是自定义元字段,且该查询是筛选分类而非排序,只会过滤掉stick_to_end为true的分类,无法实现将它们放在末尾的效果。
解决方案
方案一:PHP层面手动拆分排序(简单直观)
先获取所有分类,再按stick_to_end字段拆分两组,最后合并正常组在前、末尾组在后:
<div class="col-lg-10"> <?php // 获取所有work-category分类,包含元数据查询 $terms = get_terms([ 'taxonomy' => 'work-category', 'hide_empty' => true, 'orderby' => 'count', 'order' => 'DESC', // 确保查询包含有stick_to_end字段和没有该字段的分类 'meta_query' => [ 'relation' => 'OR', ['key' => 'stick_to_end', 'compare' => 'EXISTS'], ['key' => 'stick_to_end', 'compare' => 'NOT EXISTS'] ] ]); // 拆分分类为两组 $normal_terms = []; $sticky_end_terms = []; foreach ($terms as $term) { // 获取自定义字段值,默认返回false $stick_to_end = get_term_meta($term->term_id, 'stick_to_end', true); if ($stick_to_end) { $sticky_end_terms[] = $term; } else { $normal_terms[] = $term; } } // 合并两组:正常分类在前,需要固定在末尾的分类在后 $sorted_terms = array_merge($normal_terms, $sticky_end_terms); if ($sorted_terms) { foreach ($sorted_terms as $category) { ?> <h2 class="category-h2"> <?= $category->name ?> </h2> <?php $posts = get_posts(array( 'posts_per_page' => -1, 'post_type' => 'jobs', 'tax_query' => [ [ 'taxonomy' => 'work-category', 'field' => 'term_id', 'terms' => $category->term_id, ] ] )); if ( $posts ) { foreach( $posts as $post ) { setup_postdata( $post ); include 'WorkView.php'; }; wp_reset_postdata(); } } } else { //no categories $posts = get_posts(array( 'posts_per_page' => -1, 'post_type' => 'career' )); if ( $posts ) { foreach( $posts as $post ) { setup_postdata( $post ); include 'JobListThumb.php'; }; wp_reset_postdata(); } } ?> </div>
方案二:数据库层面修改排序(性能更优)
通过terms_clauses过滤器修改SQL查询,直接在数据库层面实现先按stick_to_end分组排序,再按文章数降序:
在主题的functions.php中添加以下代码:
add_filter('terms_clauses', function($clauses, $taxonomy, $args) { // 仅针对work-category分类,且按count排序时生效 if ($taxonomy !== 'work-category' || ($args['orderby'] ?? '') !== 'count') { return $clauses; } global $wpdb; // 关联termmeta表,查询stick_to_end字段 $clauses['join'] .= " LEFT JOIN {$wpdb->termmeta} tm ON t.term_id = tm.term_id AND tm.meta_key = 'stick_to_end'"; // 修改排序规则:先将stick_to_end为true的分类放到后面,再按count降序 $clauses['orderby'] = "CASE WHEN tm.meta_value = '1' THEN 1 ELSE 0 END ASC, {$clauses['orderby']}"; return $clauses; }, 10, 3);
添加后,你原来的get_terms代码无需修改,查询出的分类会自动将标记stick_to_end的分类放在末尾,其他分类仍按文章数降序排列。
方案对比
- 方案一:无需修改全局代码,逻辑简单易懂,适合分类数量较少的场景。
- 方案二:直接在数据库层面处理,性能更优,适合分类数量较多的场景,但需要添加全局过滤器,注意限定生效范围。
内容的提问来源于stack exchange,提问作者Julia Galden
相关产品推荐
相关产品推荐

