本文约 5,100 字,预计阅读 13 分钟。文中命令与配置均经过实测,可直接参考执行。
引言:搜索结果里那一行小字,是可以自己控制的三百个像素
在 Google 搜索结果里,.URL 从原来的一行 URL 变成了”首页 › 分类 › 标题”这样的面包屑结构。这不是 Google 自动猜的,而是读取了页面里的 BreadcrumbList 结构化数据。很多国内站长的页面 URL 里带着 /category/general/uncategorized/ 之类乱七八糟的路径,搜索结果展示出来非常难看,而面包屑结构化数据可以完全覆盖掉真实 URL 路径,展示一条干净、可读的路径。
问题在于 WordPress 核心本身不提供面包屑。这一块有四个来源:SEO 插件自带(Yoast SEO、Rank Math、SEOPress)、专用插件(Breadcrumb NavXT)、主题自带(Astra、GeneratePress、Kadence 都有内置开关)、自己写代码。四者混用会输出两套 breadcrumb HTML,轻则页面上出现两条路径,重则 Schema 里出现两个 BreadcrumbList,Google Rich Results Test 直接报 duplicate field 错误。本文把检测方法和统一方案讲清楚。
原理分析:面包屑的两层——可见 HTML 与结构化数据
面包屑必须由两部分组成,缺一不可。
| 层级 | 作用 | 常见实现 |
|---|---|---|
可见 HTML <nav>/<ol> |
给用户看,影响站内浏览与跳出 | 主题模板 single.php 输出 |
| JSON-LD BreadcrumbList | 给搜索引擎看的机器可读数据 | Yoast / Rank Math / NavXT 自动输出 |
| (可选)microdata / RDFa | 旧式标记,Yoast 已弃用 | 老主题里还能见到 |
Home › Category › Post 是最通用的三层结构。WooCommerce 产品页会变成 Home › Shop › Product Category › Product。这里的关键在于:“分类”这一层应该选哪一个,是面包屑最容易出错的地方。WordPress 一篇文章可以挂多个分类(尤其国内的”最新文章”和”教程”双挂),插件必须挑出一个作为唯一父级,否则你看到的就是”首页 › 杂谈 › 标题”,而用户明明是从”教程”点进来的。
Yoast 的做法:按 term_id 最小那个作为主分类(可通过 Yoast 的 primary category 手动指定层级)。Rank Math 同理支持 primary taxonomy 设定。理解这一点,才能理解为什么同一篇文章在更新之后面包屑会变。
另外要注意:Yoast SEO 从 14.0 起把默认的 microdata 标记改成了 JSON-LD;Rank Math 默认输出 JSON-LD。两者同时激活会出现双份 Schema。
前置知识:Yoast SEO 结构化数据配置
保姆级实操
步骤 1:先摸清站点现在有几套面包屑
用 Chrome 打开文章页,Ctrl+U 查看源代码,搜索三个关键词,判断当前的来源与数量:
# 在网页源码里统计面包屑线索(本地对已保存的页面 html 做检查)
grep -o 'BreadcrumbList' page.html | wc -l
grep -o 'breadcrumb' page.html | wc -l
grep -o 'crumbs' page.html | wc -l
BreadcrumbList 出现大于 1 次,说明 Schema 重复;breadcrumb 出现很多次是正常的(CSS class 也会命中),重点看 <nav 标签里带 breadcrumb class 的数量。
步骤 2:选定唯一数据源
三个决策分支:
- 已装 Yoast 或 Rank Math:关闭主题自带面包屑,统一用插件。Astra 在「外观 → 自定义 → Layout → Breadcrumb」里关;GeneratePress 在「自定义 → Layout → Breadcrumbs」用 Disable elements 里的 Breadcrumbs 排除项处理。
- 用 Breadcrumb NavXT:它的优势是支持 attachment 层级、作者归档层级和自定义 taxonomy,适合 WooCommerce + 多 taxonomy 站点。NavXT 输出 Schema 需要在「Settings → Breadcrumb NavXT → General → Include Home Breadcrumb / Output JSON-LD」里开启。
- 主题自带且不装 SEO 插件:必须用
wpseo_breadcrumb_links之外的方式补 Schema,这种组合最不推荐,建议至少补一个 Schema 插件。
步骤 3:Yoast 面包屑的输出代码
Yoast 不自动在前台显示面包屑 HTML,必须在主题模板里调用。找到主题的 single.php(或 template-parts/content-single.php),插到文章标题之前:
<?php if ( function_exists( 'yoast_breadcrumb' ) ) : ?>
<nav class="mf-breadcrumb" aria-label="面包屑导航">
<?php yoast_breadcrumb( '<p id="breadcrumbs">', '</p>' ); ?>
</nav>
<?php endif; ?>
同理,Rank Math 用短代码,可以放在任意位置:
// Rank Math 面包屑短代码调用
echo do_shortcode( '' );
步骤 4:修正”主分类”——让面包屑指向正确的父级
Yoast 支持用过滤器强制指定某一层的链接和文本。比如外贸站有一篇同时挂在 News 和 Blog 的文章,希望面包屑固定走 Blog:
add_filter( 'wpseo_breadcrumb_links', function( $links ) {
global $post;
if ( is_singular( 'post' ) && ! empty( $links[2]['term'] ) ) {
$blog_term = get_term_by( 'slug', 'blog', 'category' );
if ( $blog_term ) {
$links[2]['term'] = $blog_term;
$links[2]['text'] = $blog_term->name;
$links[2]['url'] = get_category_link( $blog_term->term_id );
}
}
return $links;
} );
(Rank Math 对应钩子是 rank_math/frontend/breadcrumb/args 与 rank_math/frontend/breadcrumb/main_crumbs。)
步骤 5:样式控制
.mf-breadcrumb {
font-size: 13px;
color: #6b7280;
margin-bottom: 12px;
}
.mf-breadcrumb a { color: #6b7280; text-decoration: none; }
.mf-breadcrumb a:hover { color: #c0392b; text-decoration: underline; }
/* Yoast 自动插入的分隔符 span */
.mf-breadcrumb span { margin: 0 6px; color: #9ca3af; }
@media (max-width: 640px) {
.mf-breadcrumb { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
}
步骤 6:Rich Results Test 校验
把文章 URL 贴进 Google 富媒体搜索结果测试工具,确认 Breadcrumbs 检测通过、位置层级正确。如果报 “Missing field ‘item'”(Google 老版要求)或 “Invalid value for field item”,多半是最后一级(当前页)也带了 item.url,把当前页这一层留空 url 即可修正。
常见踩坑
- WooCommerce 站点面包屑层级错乱:WC 自带
woocommerce_breadcrumb(),和 Yoast 同时输出。用remove_action( 'woocommerce_before_main_content', 'woocommerce_breadcrumb', 20 );移除 WC 自带的那份,只留 Yoast 的。 - Home 层显示为 “Home”:中文站要在 Yoast 的「Search Appearance → Breadcrumbs → Homepage anchor text」里改成”首页”;Rank Math 在「General Settings → Breadcrumbs → Homepage Label」。
- 案例:某外贸站同时装 Yoast 与 Astra Pro,两边都开了面包屑,前台出现两条路径。更糟的是 Schema 里两个 BreadcrumbList 的 itemListElement 顺序不一致(一条含 category,一条不含),Google 直接判定 conflict,富媒体三条字段全部丢失,CTR 掉了近 8%。关闭 Astra 自带的面包屑、清 Purge Yoast 缓存后一周恢复。
- 面包屑把 URL 里的 /tag/ 也带了进来:这是主题自己写的拼接逻辑,没有处理 tag 归档。切回插件方案最省事。
- 静态/JAMStack 前段被缓存:面包屑属于用户无关内容,可以放心缓存;但如果用了上面那种针对特定文章的
wpseo_breadcrumb_links改逻辑,记得在更新 Settings/term 后清一次页面缓存(Nginx FastCGI Cache 或 Redis),否则改了不生效。 - 首页不该显示面包屑:记得
if ( is_front_page() ) return;,否则结构化数据里会出现一个只有一层的 BreadcrumbList,属于无效数据。 - 中文 URL 导致
item取值异常:务必让 URL 走get_permalink()而不是手写拼接,get_permalink()内部会做urlencode,手写拼接遇到中文 slug 会裂开。
总结
面包屑的决策口径:只留一个数据源。装了 Yoast / Rank Math 就关掉主题与 WooCommerce 自带的;没装 SEO 插件又超出 Hello Custom Theme 的需求,就单独装 Breadcrumb NavXT 并开启其 JSON-LD 输出。落地后一定要用 Google Rich Results Test 验证 BreadcrumbList 只有一份、层级正确、当前页不带 url;然后检查 wpseo_breadcrumb_links 过滤器有没有把主分类定死——尤其是”一文多挂”的站点,这一步决定了搜索结果展示的那一行是否好看。
扩展阅读:WordPress XML Sitemap 结构优化
