本文约 3,883 字,预计阅读 10 分钟。文中命令与配置均经过实测,可直接参考执行。
引言:标题标签重复两次,Google 抓到的是错的
装完 Yoast SEO 或 Rank Math 之后,很多人会发现页面源代码里出现了两个 <title>、两段 <meta name="description">、两个 canonical 链接。Google Search Console 的「重复提交的网址」和「标题缺失/重复」类提示开始冒出来,排名也随之波动。
根源在于:主题自己也带了一套 SEO 输出。市面上不少商业主题在「主题选项 → SEO」里提供了标题格式、描述、OG 标签、甚至站点地图的设置项,功能上和 SEO 插件高度重叠。两套系统同时工作,谁也不会主动让位,结果就是重复输出。而对搜索引擎来说,重复的标题标签等于没有明确信号——抓取时会挑一个,可能挑到你不想要的那个。本文给出判断重复的方法、关闭主题 SEO 的四种途径(从最省事到最彻底),以及「什么情况下可以只留主题」的取舍原则。
原理分析:重复是怎么产生的
WordPress 的 <title> 由主题通过 add_theme_support( 'title-tag' ) 声明,核心随后把 _wp_render_title_tag() 挂到 wp_head 上输出。这一步本身只会输出一次。
重复来自两处叠加:
- 主题自己又往
wp_head挂了一套输出<title>、<meta name="description">、rel="canonical"的函数; - SEO 插件也往
wp_head挂了一套,并且插件会接管核心的标题渲染(Yoast 通过wpseo_title等过滤器改写标题,Rank Math 同理)。
由于两者都挂在 wp_head,优先级不同但都会执行,最终 HTML 里就出现了两份。<meta name="description"> 同理。
| 输出项 | 核心/主题默认来源 | 插件来源 | 重复后果 |
|---|---|---|---|
<title> |
_wp_render_title_tag() |
Yoast / Rank Math 改写 | 搜索结果标题不可控 |
| description | 主题 SEO 模块 | 插件模板变量 | 摘要随机取一个 |
| canonical | rel_canonical() |
插件接管 | 收录 URL 不确定 |
| OG / Twitter 卡片 | 主题或插件 | 另一套 | 社交分享预览错乱 |
| 站点地图 | 主题内置 | 插件 /sitemap.xml |
两个站点地图冲突 |
判断是否有重复,最可靠的办法是看页面源代码,而不是看后台设置。搜索引擎的选择逻辑是「取出现的第一个」或「取它认为最合理的那个」,没有保证——所以必须主动留一套。取舍原则很明确:SEO 是长期工程,插件的能力、可维护性与数据可迁移性都远好于主题内置模块。主题换了,设置就没了;插件换了,数据还能导。
保姆级实操
- 确认是否有重复:前台右键「查看源代码」,搜索
<title、name="description"、rel="canonical",数一下个数。出现两次即确认冲突。 - 优先在主题选项里关:多数主题提供「主题选项 → SEO / 常规 → 启用 SEO」开关。这是最省事且最安全的方式,改完清一次缓存。
- 主题没开关就用钩子摘:找到主题注册 SEO 输出的函数名(在主题里搜索
add_action( 'wp_head'与description),用remove_action摘掉,优先级必须与注册时一致。 - 确实关不掉时,让插件接管:用插件的过滤器统一改写标题和描述,保证最终值可控;同时用
document_title_parts兜底修正核心渲染的标题部分。 - 核对 canonical:
rel_canonical()是核心自带的函数,插件启用后通常会接管它。若主题也输出了一份,务必摘掉主题的那一处。 - 验证:清缓存后重新抓取源代码,确认
<title>、description、canonical各只剩一份,再到 Google 的富媒体结果测试工具里看标题解析是否正常。
<?php
// 子主题 functions.php:摘掉主题自带的 SEO 输出
// 函数名与优先级需在主题里搜索确认,常见写法如下
remove_action( 'wp_head', 'theme_seo_meta_tags', 10 );
remove_action( 'wp_head', 'theme_output_og_tags', 5 );
remove_action( 'wp_head', 'theme_output_canonical', 10 );
<?php
// 让 Yoast 统一接管标题与描述(主题关不掉时的兜底)
add_filter( 'wpseo_title', function( $title ) {
if ( is_front_page() ) {
return '站点主标题 | 核心业务关键词';
}
return $title;
} );
add_filter( 'wpseo_metadesc', function( $desc ) {
if ( '' === trim( $desc ) && is_single() ) {
$desc = wp_trim_words( wp_strip_all_tags( get_the_excerpt() ), 60, '…' );
}
return $desc;
} );
add_filter( 'wpseo_canonical', function( $canonical ) {
// 强制 https 与去除分页参数,保证收录 URL 唯一
return preg_replace( '#/page/\d+/?$#', '/', $canonical );
} );
<?php
// 与插件无关的核心层兜底:只保留一处标题
add_filter( 'document_title_parts', function( $parts ) {
if ( is_home() ) {
unset( $parts['tagline'] ); // 首页不要副标题,避免标题过长
}
if ( isset( $parts['page'] ) && '1' === $parts['page'] ) {
unset( $parts['page'] );
}
return $parts;
} );
# 命令行快速数一下重复项
curl -s https://example.com/ | grep -o '<title>' | wc -l
curl -s https://example.com/ | grep -o 'name="description"' | wc -l
curl -s https://example.com/ | grep -o 'rel="canonical"' | wc -l
# 输出大于 1 即为重复
常见踩坑
- 只关了主题的标题没关描述:
<title>只剩一份,但 description 和 OG 标签仍重复,社交分享预览依旧错乱。要逐项核对。 remove_action优先级写错:注册是 10,移除写 5 或省略都摘不掉。必须与注册时一致。- 移除时机早于主题注册:包在
after_setup_theme或wp_loaded里执行,别在插件文件顶层直接调用。 - 两个 SEO 插件同时启用:Yoast 与 Rank Math 并存会互相抢钩子,比主题冲突更难处理。只能留一个。
- 关掉主题 SEO 后描述全空:主题之前一直在提供描述,关掉后插件没有配置模板,需要到插件的「搜索外观 → 内容类型」里补模板变量。
- 案例:一个资讯站同时开着主题的 SEO 模块和 Yoast,三个月内标题在搜索结果里反复变化,收录量掉了三成。运营一直以为是算法波动。后来用
curl数了一下,页面里有两个<title>和两个 description,主题的在前、Yoast 的在后,Google 有时取前者。关闭主题 SEO 模块后两个月,标题稳定下来,收录逐步恢复。这类问题靠后台设置看不出来,必须看源代码。 - 结构化数据也会重复:主题与插件各输出一份 JSON-LD 是同类问题的另一面,处理方式见
主题结构化数据重复处理。
总结
判断原则一句话:标题、描述、canonical 各留一份,且留给专业 SEO 插件。操作顺序是「主题选项关 → 钩子摘 → 插件过滤器接管 → 源代码验证」。关闭前记得在插件里配好标题与描述模板,避免出现描述为空。若站点只是简单的展示型官网、没有长期 SEO 规划,也可以只留主题内置模块而完全不装插件——但一旦开始做内容运营,就应当尽早迁到插件,避免数据绑死在主题上。迁移与配置细节可参考 WordPress SEO 插件配置。
