你那篇”ChatGPT 插件”是 2023 年发的。上个月刚重写过——新截图、新模型名、新例子——可 frontmatter 里的 publishedAt 还是 2023-03-14。SERP 摘要在你标题旁显示”Mar 14, 2023”,读者跳过你去看更新鲜的对手,Google 的新鲜度信号把这页当陈旧处理。内容确实刷新了,只是日期没动。
最快的修法: 在 content schema 里加一个可选的 updatedAt 字段,给那些真正重写过的文章设上,页面上只显示这一个日期并标”Updated”,再把它作为 Article JSON-LD 的 dateModified 发出去,让可见日期和结构化日期完全一致。不要把所有页面一把撞到今天——那比原来的陈旧日期伤得更深。
反向陷阱代价一样高:每次小修都撞日期。如果你的 sitemap lastmod 或署名日期每改个错别字就跳到今天,Google 会学会”你的日期是噪声”然后不再信任它。Google 对你日期信号的信任近乎二元——要么全信、要么不信——一段造假”假新鲜”的历史会连累全站每一页(见 John Mueller 反复强调的说法)。
你属于哪一种?
| 症状 | 根因 | 修法 |
|---|---|---|
| SERP 显示老日期,你确实重写过这页 | 没有 updatedAt 字段,或有但没人设 | 加上/设上 updatedAt;用它驱动可见日期 + dateModified |
updatedAt 是新的,SERP 还显示老日期 | 可见日期和 schema 日期对不上,Google 干脆忽略 schema | 让可见署名和 JSON-LD dateModified 完全相同 |
| 同时显示”Published”和”Updated”,CTR 反而掉 | 两个都在时,Google 常挑较老的 datePublished 来展示 | 只显示一个日期(刷新内容显示 Updated) |
| 每页都写着”今天更新” | 小修也撞日期;sitemap lastmod 自动设成构建时间 | 只在实质改动时撞;让 lastmod 反映真实变化 |
| 时间敏感页(定价/限额)悄悄过期 | 没标 volatile,没有刷新节奏 | 加 volatile: true,配季度陈旧度审计 |
常见原因
1. 只有一个日期字段——永不移动
schema 里只有 publishedAt,再无其它。于是日期要么永不动(页面看起来陈旧),要么你直接撞 publishedAt(这会毁掉真实的首发日期,看起来还像在操纵日期)。两种都错。
如何判断: 打开你的 content collection schema,看有没有独立的 updatedAt / updatedDate 字段。没有——你的设计本身就带这病。
2. updatedAt 有,但作者不设
字段在 schema 里,但作者真刷文章时忘了设。页面 header 显示”Updated: 2023-03-14”,可文章上周才重写。
如何判断: 拿 git 历史对照 frontmatter。最后一次实质提交比 updatedAt 新好几个月的,就是被错标成陈旧的。
# 文件最后一次提交日期 vs frontmatter
git log -1 --format=%cs -- src/content/articles/zh/troubleshooting/your-slug.mdx
3. 可见日期和 schema 日期对不上
这是”updatedAt 明明是对的却还是不显示”最常见的原因。Google 不把你的结构化数据当真理来源——它会拿 JSON-LD 日期去和页面上醒目的日期、sitemap lastmod 以及其它信号交叉核对。一旦冲突,Google 可能直接忽略你的 schema,转而展示它更信任的那个日期(往往是较老的署名)。截至 2026 年 6 月,Search Central 的指引说得很明确:“Ensure that the date (and optional time and timezone) match between the equivalent user-visible and structured values.”
如何判断: view-source 看一篇刷新过的文章,确认可见署名里的日期和 dateModified 里的一致。
curl -s https://site.com/zh/articles/your-slug/ | grep -Eo 'dateModified":"[^"]+'
4. 同时显示”Published”和”Updated”——CTR 反而掉
反直觉:同时显示两个日期反而伤你。2026 年一项被广泛引用的测试发现,加上发布日期和更新日期后 CTR 大约掉了 22%,因为即便两个都做了标记,Google 还是开始在摘要里展示较老的 datePublished。对频繁刷新的内容,只显示一个日期——“Updated”——让 datePublished 只活在 schema 里。
如何判断: 如果你的模板印了两个日期、而刷新过的文章在搜索里还是显示老的,就收敛成单个可见的”Updated”日期。
5. 每次小修都撞日期
作者改个错别字撞一下日期,一周后又一个错别字、又撞。文章一年没实质改动,日期却周周动。Google 自家指引说,错别字、语法这类小修不构成更新 dateModified 的理由。更糟的是,如果你的 sitemap lastmod 也是同样的噪声模式,Google 对这个标签的信任是二元的——一旦看到一段不准确的 lastmod 历史,它会全站忽略 lastmod。
如何判断: 对日期字段跑 git log -p。如果大多数撞动都对应单行 diff,你就有 date-spam。
6. 快变话题没标 volatile
一篇”当前 ChatGPT 定价”天然每季度就过期。没有 volatile: true flag,它就和常青内容共用同一套发布节奏,在两次刷新之间悄悄烂掉。
如何判断: 列出含”current”/“latest”/年份数字/“pricing”/“limits”等关键词的文章。没有 volatile flag 的就该加。
最短修复路径
Step 1:加一个真的 updatedAt 字段
更新 content collection schema,让它带两个日期。publishedAt 一次设定、永不动;updatedAt 可选,只在实质刷新时设。
// src/content.config.ts (Astro 的 content 配置;老项目用的是 src/content/config.ts)
import { defineCollection, z } from "astro:content";
import { glob } from "astro/loaders";
const articles = defineCollection({
loader: glob({ pattern: "**/*.mdx", base: "./src/content/articles" }),
schema: z.object({
title: z.string(),
publishedAt: z.coerce.date(),
updatedAt: z.coerce.date().optional(),
volatile: z.boolean().default(false),
// ...
}),
});
export const collections = { articles };
z.coerce.date() 让你 frontmatter 里照旧写 2026-05-24 这种字符串,在 layout 里拿到的却是真正的 Date 对象。
Step 2:只显示一个日期,并接到 dateModified
在 article layout 里,把最近的那个日期算一次,渲染成单个可见署名,再把同一个值发到 dateModified。datePublished 只留在 JSON-LD 里。
---
const { article } = Astro.props;
const lastUpdate = article.data.updatedAt ?? article.data.publishedAt;
const wasUpdated = !!article.data.updatedAt;
const fmt = (d) => d.toLocaleDateString("zh-CN", { year: "numeric", month: "short", day: "numeric" });
---
<time datetime={lastUpdate.toISOString()}>
{wasUpdated ? "Updated" : "Published"} {fmt(lastUpdate)}
</time>
<script type="application/ld+json" set:html={JSON.stringify({
"@context": "https://schema.org",
"@type": "Article",
datePublished: article.data.publishedAt.toISOString(),
dateModified: lastUpdate.toISOString(),
})} />
在 ISO 字符串里带上时间和时区能增加精度;只要保证渲染出来的署名和 schema 描述的是同一个时刻就行。
Step 3:让 sitemap lastmod 说真话
用同一个 lastUpdate 值驱动 lastmod,而不是用构建时间。如果你做不到准确,宁可不写 lastmod 也别每次构建都设成”现在”——一段不准确的历史会让 Google 全站丢弃这个标签。
// astro.config.mjs —— @astrojs/sitemap
sitemap({
serialize(item) {
// 把 item.url 映射回文章,设 item.lastmod = (updatedAt ?? publishedAt)
return item;
},
});
Step 4:定义刷新策略
写清楚 updatedAt 何时该动,然后在 review 里执行。
- 实质(撞):加新章节、模型/定价事实更新、
代码示例重写、换截图、给出实质性新建议
- 小修(不撞):错别字、措辞润色、加内链、
纯格式改动
- 只修对端翻译漂移:不撞(每个语言页各自管自己的日期)
reviewer 在 PR 上执行;小修 diff 撞了日期就给一句”恢复日期”评论。
Step 5:标 volatile 文章并审计
定价、模型清单、“X 的当前状态”类——加 volatile: true。季度脚本扫出任何日期超过 90 天的 volatile 文章,这份清单就是你的刷新队列。
// scripts/audit-volatile-staleness.mjs
import fs from "node:fs";
import matter from "gray-matter";
const THRESHOLD_DAYS = 90;
const now = Date.now();
for (const f of /* 遍历你的文章文件 */ []) {
const { data } = matter(fs.readFileSync(f, "utf8"));
if (!data.volatile) continue;
const last = new Date(data.updatedAt || data.publishedAt).getTime();
const ageDays = (now - last) / 86_400_000;
if (ageDays > THRESHOLD_DAYS) {
console.log(`STALE volatile: ${f} (${Math.round(ageDays)}d old)`);
}
}
Step 6:回填存量陈旧标签——挑着来
跑一次性回填,逐篇判断,而不是对整个语料库盖章放行。
1. 列出最后一次实质 git 提交比 frontmatter publishedAt
新 6 个月以上的文章。
2. 每篇判断:是不是真的做过实质刷新。
3. 是——把 updatedAt 设成那次真实编辑的 git 日期。
4. 否——别动。
不要把所有文章一把撞到今天。只设挑选过的、站得住脚的日期——这正是”新鲜度信号”和”date-spam”的全部分别。
如何确认已修好
- view-source 看一篇刷新过的文章,确认可见署名日期等于 JSON-LD 里的
dateModified。 - 用 Rich Results Test 跑这一页——
datePublished和dateModified都应通过校验、无警告。 - 查 sitemap 条目:
curl -s https://site.com/sitemap-0.xml | grep -A1 your-slug,确认lastmod是文章真实更新日期,而不是构建时间戳。 - 等 Google 重新抓取后(在 Search Console 里请求编入索引可加快),SERP 摘要应显示新日期。这可能要几天到几周;让新日期”立得住”的正是 schema 与可见日期的一致。
预防
- 两字段 schema:
publishedAt不可变,updatedAt可选、配刷新。 - 只显示一个可见日期;刷新内容绝不同时印”Published”和”Updated”。
- 可见署名、JSON-LD
dateModified、sitemaplastmod三者必须一致。 - 文档化刷新策略;reviewer 在 PR 上执行”实质 vs 小修”。
- 时间敏感话题加
volatile: true,配季度陈旧度审计。 - 用 git 历史当真相来源,做一次性、挑选式回填。
常见问题
Google 到底用不用 dateModified,还是它自己挑日期?
两者都有。Google 把 dateModified 当作一个新鲜度信号读取,但会拿它和页面上醒目的日期及其它线索交叉核对。一旦不一致,它可能忽略你的 schema、改选它更信任的那个日期——通常是较老的。可靠做法是让可见日期和 schema 日期完全相同。
该同时显示发布日期和更新日期吗?
对频繁刷新的内容,一般不该。截至 2026 年 6 月,测试显示两个日期都在时 CTR 会下降,因为 Google 倾向于展示较老的 datePublished。只显示”Updated”,把 datePublished 留在结构化数据里。
改日期会被 Google 惩罚吗?
没有直接惩罚,但有信任代价。如果你的 sitemap lastmod 或署名没有实质内容变化就跳到”今天”,Google 会不再信任你的日期信号——往往是全站性的——这反而让它更慢地认出你真正的更新。
新日期多久才会在搜索里出现? 只有 Google 重新抓取这页之后才会变。在 Search Console 里请求编入索引能加快,但仍可能要几天到几周。让新日期一出现就立得住的,正是 schema 与可见日期的一致。
只改个错别字也要撞日期吗?
不要。Google 自家指引说小修不构成更新 dateModified 的理由。只在页面实质内容变化时才撞。
应该直接改 publishedAt,而不是加 updatedAt 吗?
不应该。publishedAt 是页面的首发日期,应当不可变。覆盖它会丢掉真实历史、还像在操纵。加一个独立的 updatedAt,用它来驱动新鲜度。
相关
- Stale Articles Not Updated
- Content Site Sitemap Not Resubmitted After Big Changes
- Outdated Screenshots in Tutorials
- Content Site FAQ Schema Not Extracted
- Content Site Hreflang Tags Misconfigured
- Content Site Canonical Points to Self Wrong
标签: #内容运营 #站点质量 #站点审计 #排查 #publish-date