面包屑需要同时解决三件事:帮助用户理解当前位置、提供可点击的上级路径、让结构化数据与页面实际导航一致。旧的 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 是否完全一致。