WordPress CPT分页排序问题:分类顺序展示不符合预期
问题根源
你当前的代码是对每个分类单独执行带分页参数的查询,所以每页都会从每个分类里取出20条内容,自然会混合四类酒店。要实现「先展示完featured所有内容,再依次展示后续分类」的效果,需要调整查询逻辑,让整个结果集按分类优先级排序后再分页。
方案一:先收集ID再分页(直观易理解)
这种方法先按分类顺序收集所有符合条件的酒店ID,再根据当前页码截取对应ID段,最后查询这些ID并保持顺序:
<?php $paged = (get_query_var('paged')) ? get_query_var('paged') : 1; $posts_per_page = 20; $tax_slugs = array('featured','mid-range','luxury','budget'); $all_hotel_ids = array(); // 按顺序收集每个分类下的酒店ID foreach($tax_slugs as $slug){ $term = get_term_by('slug', $slug, 'style'); if(!$term) continue; $category_posts = get_posts(array( 'post_type' => 'hotels', 'post_status' => 'publish', 'posts_per_page' => -1, // 获取该分类下所有酒店 'tax_query' => array( array( 'taxonomy' => 'style', 'field' => 'term_id', 'terms' => $term->term_id ) ), 'orderby' => array('menu_order' => 'ASC', 'date' => 'DESC'), 'fields' => 'ids' // 只返回ID,提升性能 )); $all_hotel_ids = array_merge($all_hotel_ids, $category_posts); } // 处理分页逻辑 $total_posts = count($all_hotel_ids); $total_pages = ceil($total_posts / $posts_per_page); // 确保页码在有效范围内 if($paged > $total_pages) $paged = $total_pages; if($paged < 1) $paged = 1; // 截取当前页对应的ID $start_index = ($paged - 1) * $posts_per_page; $current_page_ids = array_slice($all_hotel_ids, $start_index, $posts_per_page); // 查询当前页的酒店 $args = array( 'post_type' => 'hotels', 'post_status' => 'publish', 'post__in' => $current_page_ids, 'orderby' => 'post__in', // 保持ID数组的顺序 'posts_per_page' => $posts_per_page ); $loop = new WP_Query($args); ?> <ul class="hotel-list"> <?php while ($loop->have_posts()) : $loop->the_post(); get_template_part('templates/hotel', 'page'); endwhile; wp_reset_postdata(); // 重置查询 ?> </ul>
方案二:修改数据库排序规则(高效适合大数据量)
直接通过过滤器修改WP_Query的排序逻辑,让结果先按你指定的分类顺序排列,再按原有规则排序,分页自动生效:
<?php $paged = (get_query_var('paged')) ? get_query_var('paged') : 1; // 添加排序过滤器 function hotel_taxonomy_order($orderby, $query){ global $wpdb; // 只针对hotels的查询生效 if($query->get('post_type') !== 'hotels') return $orderby; $tax_slugs = array('featured','mid-range','luxury','budget'); $term_ids = array(); foreach($tax_slugs as $slug){ $term = get_term_by('slug', $slug, 'style'); if($term) $term_ids[] = $term->term_id; } // 用数据库FIELD函数按指定分类顺序排序,再叠加原有排序规则 $orderby = "FIELD({$wpdb->term_relationships}.term_taxonomy_id, " . implode(',', $term_ids) . ") ASC, {$wpdb->posts}.menu_order ASC, {$wpdb->posts}.post_date DESC"; return $orderby; } add_filter('posts_orderby', 'hotel_taxonomy_order', 10, 2); // 执行查询 $args = array( 'post_type' => 'hotels', 'posts_per_page' => 20, 'post_status' => 'publish', 'paged' => $paged, 'tax_query' => array( array( 'taxonomy' => 'style', 'field' => 'slug', 'terms' => array('featured','mid-range','luxury','budget'), 'operator' => 'IN' ) ) ); $loop = new WP_Query($args); // 移除过滤器,避免影响其他查询 remove_filter('posts_orderby', 'hotel_taxonomy_order', 10, 2); ?> <ul class="hotel-list"> <?php while ($loop->have_posts()) : $loop->the_post(); get_template_part('templates/hotel', 'page'); endwhile; wp_reset_postdata(); ?> </ul>
方案对比
- 方案一逻辑直白,适合酒店数量不多的场景,容易调试和修改;
- 方案二直接操作数据库排序,性能更优,适合数据量较大的站点;
- 两种方案都能实现「先展示完
featured所有酒店,再依次展示mid-range、luxury、budget」的分页效果,不会在每页混合不同分类的内容。
内容的提问来源于stack exchange,提问作者Pradeep Singh
相关产品推荐
相关产品推荐

