本文约 4,018 字,预计阅读 11 分钟。文中命令与配置均经过实测,可直接参考执行。
引言:插件装上了,问题反而多了
装完 Yoast SEO 或 Rank Math,常见三种反馈:页面源代码里出现两个 <title>(搜索结果标题变得很怪);插件开了面包屑但前台没有任何东西;Google 结构化数据测试里报”缺少 author”或”字段无效”。
这三个问题都不是插件的 bug,而是主题与插件的职责边界没划清。标题由谁输出、面包屑由谁渲染、结构化数据由谁补充,主题侧各有一个明确的”开关”,没打开就会出现重复或缺失。
原理分析:三件事的职责划分
标题:WordPress 3.4 之后有了 title-tag 主题支持。主题声明 add_theme_support( 'title-tag' ) 后,核心在 wp_head 上挂载 _wp_render_title_tag(),输出 <title>。此时 Yoast / Rank Math 通过 pre_get_document_title 与 wp_title 过滤器改写内容。如果主题在 header.php 里硬编码了 <title><?php wp_title(); ?></title>,就会与插件输出叠加,出现两个 title 标签。
面包屑:插件提供的是输出函数,模板里必须调用它才会渲染。Yoast 用 yoast_breadcrumb(),Rank Math 用 rank_math_the_breadcrumbs()。主题若没有在 single.php/archive.php 里调用,后台开关怎么开都不会出现。
结构化数据:Yoast 与 Rank Math 都会自动输出 JSON-LD(Article、BreadcrumbList、Organization 等),主题不应再自己输出一套,否则同一页面上出现两份 Article,Google 会判定冲突或取其一。主题要做的通常是补充字段(如作者、发布日期),用插件提供的过滤器即可。
| 功能 | 主题职责 | 插件职责 |
|---|---|---|
<title> |
声明 title-tag,不要硬编码 |
通过过滤器改写标题模板 |
| canonical | 不输出自己的 canonical | 插件统一输出 |
| 面包屑 | 在模板里调用插件函数并预留位置 | 生成层级数据 |
| JSON-LD | 不重复输出 | 生成并校验 |
| 站点地图 | 不干预 | 插件生成 |
保姆级实操
- 检查主题是否声明
title-tag:用current_theme_supports( 'title-tag' )判断,缺了就在子主题里补。 - 检查
header.php里有没有硬编码 title:搜索<title>,有的话删掉,只保留wp_head()。 - 补面包屑调用位置:在
single.php/archive.php的内容区顶部调用插件函数,并做function_exists保护,避免换插件时白屏。 - 用过滤器调整面包屑:改分隔符、首页文字、是否显示当前页标题。
- 补充结构化数据字段:用插件提供的过滤器给 Article 增加不适合放在正文里的信息。
- 上线前验证:用 Google 富媒体结果测试检查,确认没有重复 JSON-LD。
- 注意两个插件并存:Yoast 与 Rank Math 同时启用会互相抢输出,必须只保留一个。
<?php
// 1) 补齐 title-tag 支持(子主题)
add_action( 'after_setup_theme', 'mimangfei_seo_support', 20 );
function mimangfei_seo_support() {
if ( ! current_theme_supports( 'title-tag' ) ) {
add_theme_support( 'title-tag' );
}
}
// 2) header.php 里应只有 wp_head(),不要有 <title> 标签
// 可用下面这段做自检(临时开启 WP_DEBUG 查看)
add_action( 'wp_head', 'mimangfei_check_head', 999 );
function mimangfei_check_head() {
if ( ! current_theme_supports( 'title-tag' ) ) {
error_log( '主题未声明 title-tag,可能与 SEO 插件重复输出标题' );
}
}
<?php
// 3) 面包屑:兼容 Yoast 与 Rank Math,换插件不白屏
function mimangfei_the_breadcrumb() {
if ( function_exists( 'yoast_breadcrumb' ) ) {
yoast_breadcrumb( '<nav class="breadcrumb">', '</nav>' );
} elseif ( function_exists( 'rank_math_the_breadcrumbs' ) ) {
echo '<nav class="breadcrumb">';
rank_math_the_breadcrumbs();
echo '</nav>';
}
}
// 4) 调整 Yoast 面包屑:首页文字、分隔符
add_filter( 'wpseo_breadcrumb_links', 'mimangfei_breadcrumb_links' );
function mimangfei_breadcrumb_links( $links ) {
if ( ! empty( $links[0]['text'] ) ) {
$links[0]['text'] = __( '首页', 'lumen-mimangfei' );
}
return $links;
}
add_filter( 'wpseo_breadcrumb_separator', function () {
return ' / ';
} );
<?php
// 5) 给结构化数据补字段(Yoast 示例:为 Article 增加自定义属性)
add_filter( 'wpseo_schema_article', 'mimangfei_schema_article' );
function mimangfei_schema_article( $data ) {
if ( is_singular( 'post' ) ) {
$data['inLanguage'] = get_bloginfo( 'language' );
}
return $data;
}
// Rank Math 示例:为 Article 追加字段
add_filter( 'rank_math/json_ld', 'mimangfei_rankmath_ld', 10, 2 );
function mimangfei_rankmath_ld( $data, $jsonld ) {
if ( isset( $data['Article'] ) && is_singular( 'post' ) ) {
$data['Article']['inLanguage'] = get_bloginfo( 'language' );
}
return $data;
}
常见踩坑
- 主题
header.php硬编码<title>,与插件输出叠加,源码里出现两个 title。 - 没声明
title-tag,老主题插件接管后标题变成”站点名 – 站点名”这种重复格式。 - 后台开了面包屑,模板里没调用函数,前台看不到任何东西。
- 主题自己也输出了一套 JSON-LD,与插件的冲突,富媒体测试报重复字段。
- 案例:某站结构化数据一直报”author 无效”,排查发现主题在
header.php里手写了一段schema.org的微数据(itemprop形式),而 Yoast 同时输出 JSON-LD,两套数据里作者名不一致。删掉主题那段手写微数据、只保留插件输出后,警告消失。 - 同时启用 Yoast 与 Rank Math,标题与 canonical 被两边争夺,输出随机。
- 用了页面缓存插件,切换 SEO 插件后没清缓存,旧 canonical 仍在生效。
总结
职责边界一句话:主题只负责”声明支持 + 预留位置”,具体内容交给插件。判断标准是”页面源码里 <title> 只有一个、canonical 只有一个、JSON-LD 只有插件那一套”。行动清单:① 补齐 title-tag 并删除硬编码 title;② 面包屑用 function_exists 做兼容调用;③ 不在主题里输出第二套结构化数据;④ 只启用一个 SEO 插件;⑤ 换插件后清全部缓存并重新做富媒体测试。延伸阅读 WordPress 百度 SEO 设置、lumen-mimangfei 主题缓存兼容 与 lumen-mimangfei 主题自定义 CSS 写法。
