WordPress 面包屑导航:层级、语义与结构化数据

WordPress 面包屑导航:层级、语义与结构化数据

面包屑需要同时解决三件事:帮助用户理解当前位置、提供可点击的上级路径、让结构化数据与页面实际导航一致。旧的 data-vocabulary.org 标记已经不应继续使用,结构化数据应采用 Schema.org BreadcrumbList

优先使用成熟 SEO 插件

如果站点已经使用 Yoast SEO、Rank Math 或其他维护中的 SEO 插件,优先调用它提供的面包屑 API。插件通常已经处理分页、搜索、作者、日期、自定义文章类型、多语言和 JSON-LD,重复实现容易让页面导航与结构化数据不一致。

自定义主题确实需要自己的面包屑时,再建立一个统一的数据数组,同时驱动 HTML 和 JSON-LD。

构建基础数据

下面覆盖首页以外的页面、文章类型归档和 taxonomy 归档。真实项目还应补充搜索、404、日期与作者页规则。

<?php
function site_get_breadcrumb_items(): array {
    if ( is_front_page() ) {
        return array();
    }

    $items = array(
        array(
            'label' => '首页',
            'url'   => home_url( '/' ),
        ),
    );

    if ( is_singular() ) {
        $post = get_queried_object();

        if ( ! $post instanceof WP_Post ) {
            return $items;
        }

        $post_type = get_post_type_object(
            $post->post_type
        );

        if (
            $post_type &&
            $post_type->has_archive
        ) {
            $archive_url = get_post_type_archive_link(
                $post->post_type
            );

            if ( $archive_url ) {
                $items[] = array(
                    'label' => $post_type->labels->name,
                    'url'   => $archive_url,
                );
            }
        }

        foreach (
            array_reverse( get_post_ancestors( $post ) )
            as $ancestor_id
        ) {
            $items[] = array(
                'label' => get_the_title( $ancestor_id ),
                'url'   => get_permalink( $ancestor_id ),
            );
        }

        $items[] = array(
            'label' => get_the_title( $post ),
            'url'   => '',
        );

        return $items;
    }

    if ( is_category() || is_tax() ) {
        $term = get_queried_object();

        if ( ! $term instanceof WP_Term ) {
            return $items;
        }

        $ancestor_ids = array_reverse(
            get_ancestors(
                $term->term_id,
                $term->taxonomy,
                'taxonomy'
            )
        );

        foreach ( $ancestor_ids as $ancestor_id ) {
            $ancestor = get_term(
                $ancestor_id,
                $term->taxonomy
            );

            if ( ! $ancestor instanceof WP_Term ) {
                continue;
            }

            $url = get_term_link( $ancestor );

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

            $items[] = array(
                'label' => $ancestor->name,
                'url'   => $url,
            );
        }

        $items[] = array(
            'label' => $term->name,
            'url'   => '',
        );

        return $items;
    }

    $items[] = array(
        'label' => wp_get_document_title(),
        'url'   => '',
    );

    return $items;
}

输出语义化 HTML

<?php $items = site_get_breadcrumb_items(); ?>

<?php if ( $items ) : ?>
    <nav class="breadcrumb" aria-label="面包屑">
        <ol>
            <?php foreach ( $items as $item ) : ?>
                <li>
                    <?php if ( $item['url'] ) : ?>
                        <a href="<?php echo esc_url( $item['url'] ); ?>">
                            <?php echo esc_html( $item['label'] ); ?>
                        </a>
                    <?php else : ?>
                        <span aria-current="page">
                            <?php echo esc_html( $item['label'] ); ?>
                        </span>
                    <?php endif; ?>
                </li>
            <?php endforeach; ?>
        </ol>
    </nav>
<?php endif; ?>

分隔符应由 CSS 伪元素生成,不要让屏幕阅读器把每个“>”都读出来。

结构化数据

JSON-LD 的 itemListElement 必须与可见面包屑顺序相同,并使用绝对 canonical URL。最后一项是否带 item 应按搜索引擎当前规范处理。若 SEO 插件已经输出 BreadcrumbList,不要再输出第二份。

最重要的测试不是“结构化数据工具显示通过”,而是:

  • 页面层级是否符合用户理解,而不是仅复制 URL。
  • 当前页不再链接自己。
  • 分类、父页面和归档链接是否真实可访问。
  • 多语言页面是否落在正确语言路径。
  • HTML 与 JSON-LD 是否完全一致。

最后更新于

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