按分类输出文章,并可靠高亮当前分类与文章

按分类输出文章,并可靠高亮当前分类与文章

侧边栏按分类展示视频或文章,并高亮当前分类、当前详情时,应比较 term ID 和 post ID。解析 URL 文本既无法处理别名变化,也会在多语言、分页和子目录站点中失效。

以下示例假设自定义文章类型为 video,分层分类法也名为 video_category

<?php
$current_term_id = 0;
$current_post_id = is_singular( 'video' )
    ? get_queried_object_id()
    : 0;

if ( is_tax( 'video_category' ) ) {
    $current_term_id = get_queried_object_id();
}

$terms = get_terms(
    array(
        'taxonomy'   => 'video_category',
        'parent'     => 0,
        'hide_empty' => true,
        'orderby'    => 'name',
    )
);

if ( is_wp_error( $terms ) ) {
    return;
}
?>

<nav aria-label="视频分类">
    <ul class="video-navigation">
        <?php foreach ( $terms as $term ) : ?>
            <?php
            $term_url = get_term_link( $term );

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

            $videos = new WP_Query(
                array(
                    'post_type'              => 'video',
                    'post_status'            => 'publish',
                    'posts_per_page'         => 3,
                    'no_found_rows'          => true,
                    'ignore_sticky_posts'    => true,
                    'tax_query'              => array(
                        array(
                            'taxonomy' => 'video_category',
                            'field'    => 'term_id',
                            'terms'    => array( $term->term_id ),
                        ),
                    ),
                )
            );
            ?>

            <li>
                <a
                    href="<?php echo esc_url( $term_url ); ?>"
                    <?php
                    if ( $term->term_id === $current_term_id ) {
                        echo 'aria-current="page"';
                    }
                    ?>
                >
                    <?php echo esc_html( $term->name ); ?>
                </a>

                <?php if ( $videos->have_posts() ) : ?>
                    <ul>
                        <?php while ( $videos->have_posts() ) : ?>
                            <?php $videos->the_post(); ?>
                            <li>
                                <a
                                    href="<?php the_permalink(); ?>"
                                    <?php
                                    if ( get_the_ID() === $current_post_id ) {
                                        echo 'aria-current="page"';
                                    }
                                    ?>
                                >
                                    <?php the_title(); ?>
                                </a>
                            </li>
                        <?php endwhile; ?>
                    </ul>
                <?php endif; ?>

                <?php wp_reset_postdata(); ?>
            </li>
        <?php endforeach; ?>
    </ul>
</nav>

CSS 可以基于语义属性高亮,不需要额外把 URL 转成 class:

.video-navigation [aria-current="page"] {
  color: #0b57d0;
  font-weight: 700;
  text-decoration-thickness: 0.15em;
}

分层分类如何处理

如果导航需要顶级和二级分类,可以:

  1. 先查询顶级 term。
  2. 为每个顶级 term 查询 parent => $term->term_id 的直属子项。
  3. 使用当前 term 的 get_ancestors() 判断哪个父级应展开。
  4. 用递归模板函数渲染,并限制最大层级。

不要把所有 term 塞进数组后默认每个父项都有 child 键;没有子分类时必须正常输出。

不建议在列表里直接嵌入多个 iframe

旧实现为每篇视频创建 YouTube iframe,会增加网络请求、拖慢首屏并带来 Cookie/隐私问题。导航只输出缩略图和链接更稳妥;真正的视频播放器放在详情页,并使用允许的嵌入方式、懒加载和清晰标题。

如果分类很多或每组都查询文章,这同样会形成 N+1 查询。大规模站点应缓存导航、限制展示项或改成异步按需加载。

最后更新于

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