WordPress自定义文章类型分类层级展示:父分类去重优化求助
问题解决:WordPress自定义分类层级下文章分组展示(父分类仅显示一次)
核心问题分析
原代码使用拼接后的HTML字符串作为数组$q的键,导致同一父分类下的不同子分类会生成不同的键,最终渲染时父分类重复输出。要实现层级化展示,需要基于分类的term_id构建多维数组,按「父分类→子分类→文章」的层级存储数据,而非用HTML字符串作为分组依据。
改进后的完整代码
1. 数据收集与层级分组
<?php $query = new WP_Query([ 'post_type' => 'afdigit', 'posts_per_page' => -1, 'orderby' => 'none', ]); if ($query->have_posts()) { // 初始化层级数组:键为父分类term_id,值包含分类信息、子分类列表 $taxonomy_groups = []; $taxonomy = 'afd-cats'; while ($query->have_posts()) { $query->the_post(); $post_id = get_the_ID(); // 获取文章对应的所有分类 $terms = get_the_terms($post_id, $taxonomy); if (!$terms || is_wp_error($terms)) continue; foreach ($terms as $term) { // 获取当前分类的顶级父分类 $top_term = get_top_term($taxonomy, $post_id); $top_term_id = $top_term->term_id; // 初始化顶级父分类的数组结构 if (!isset($taxonomy_groups[$top_term_id])) { $taxonomy_groups[$top_term_id] = [ 'term' => $top_term, 'children' => [], // 子分类列表:键为子分类term_id 'direct_posts' => [] // 直接属于父分类的文章 ]; } // 判断当前分类是否是顶级父分类本身 if ($term->term_id === $top_term_id) { // 文章直接属于父分类,添加到direct_posts $taxonomy_groups[$top_term_id]['direct_posts'][] = [ 'title' => get_the_title(), 'link' => get_permalink() ]; } else { // 文章属于子分类,初始化子分类结构(如果不存在) if (!isset($taxonomy_groups[$top_term_id]['children'][$term->term_id])) { $taxonomy_groups[$top_term_id]['children'][$term->term_id] = [ 'term' => $term, 'posts' => [] ]; } // 添加文章到对应子分类 $taxonomy_groups[$top_term_id]['children'][$term->term_id]['posts'][] = [ 'title' => get_the_title(), 'link' => get_permalink() ]; } } } wp_reset_postdata(); ?>
2. 层级化渲染输出
<div class="cat"> <?php foreach ($taxonomy_groups as $group) : ?> <div class="term"> <!-- 输出顶级父分类 --> <div class="top term_"> <a href="<?php echo get_term_link($group['term']); ?>"> <?php echo esc_html($group['term']->name); ?> </a> </div> <!-- 输出直接属于父分类的文章 --> <?php if (!empty($group['direct_posts'])) : ?> <ul class="posts"> <?php foreach ($group['direct_posts'] as $post) : ?> <li class="post"> <a href="<?php echo esc_url($post['link']); ?>"> <?php echo esc_html($post['title']); ?> </a> </li> <?php endforeach; ?> </ul> <?php endif; ?> <!-- 输出子分类及其文章 --> <?php foreach ($group['children'] as $child) : ?> <div class="child"> <a href="<?php echo get_term_link($child['term']); ?>"> <?php echo esc_html($child['term']->name); ?> </a> </div> <ul class="posts"> <?php foreach ($child['posts'] as $post) : ?> <li class="post"> <a href="<?php echo esc_url($post['link']); ?>"> <?php echo esc_html($post['title']); ?> </a> </li> <?php endforeach; ?> </ul> <?php endforeach; ?> </div> <?php endforeach; ?> </div> <?php } ?>
3. 优化get_top_term函数(增强健壮性)
function get_top_term($taxonomy, $post_id = 0) { // 处理post_id参数:支持传入WP_Post对象或ID if (is_object($post_id) && isset($post_id->ID)) { $post_id = $post_id->ID; } $post_id = $post_id ?: get_the_ID(); $terms = get_the_terms($post_id, $taxonomy); if (!$terms || is_wp_error($terms)) { return false; } // 取第一个分类(如果文章有多个分类,可根据需求调整) $term = reset($terms); // 向上遍历直到找到顶级父分类 while ($term->parent > 0) { $parent_term = get_term_by('id', $term->parent, $taxonomy); if (!$parent_term || is_wp_error($parent_term)) break; $term = $parent_term; } return $term; }
关键改进点说明
- 数据结构重构:用
term_id作为数组键,避免HTML字符串导致的重复分组,确保同一父分类下的子分类和文章都归到同一个父分类节点下。 - 安全输出:使用
esc_html()和esc_url()处理输出内容,避免XSS安全风险(原代码未做转义,存在隐患)。 - 逻辑拆分:将数据收集和渲染分离,代码更易维护和调试。
- 空值处理:增加对分类不存在或错误的判断,避免页面报错。
最终输出效果
Category 1 Post Post Post Category 2 Post Post Post Parent category 1 Child category 1 Post Post Post Child category 2 Post Post Post Category 3 Post Post Post
内容的提问来源于stack exchange,提问作者Sergey Pervushin
相关产品推荐
相关产品推荐

