时间因子SEO 是一个专为 Halo 博客系统设计的 SEO 优化插件,通过动态注入结构化数据(meta/script 标签)来提升站点在各大搜索引擎的收录与排名表现。
- 演示站点:https://www.lik.cc/
- 文档:https://docs.lik.cc/
- QQ 交流群:
下图展示了插件在页面中为不同搜索引擎动态注入的结构化数据(OG、字节、百度、Google 等):
- 多平台支持:支持 Google、百度、字节、OG 等主流搜索引擎的结构化数据格式
- 动态内容:根据页面类型和内容自动填充标题、描述、作者、标签等字段
- 支持启用/禁用搜索引擎优化功能
- 可配置默认封面图片
- 自动获取站点信息(标题、Logo、关键词等)
- 支持按模板 ID 手动覆盖标题/描述,优先级最高
- 普通用户访问时零性能影响
- 结构化数据格式紧凑,无多余注释
- 异常处理完善,保证系统稳定性
标题:SEO 覆盖配置(插件设置 / SEO 覆盖) → 预注入的 <title> 标签文本 → 实体固定值 → 站点标题(设置 / 基本设置) → 不输出
描述:SEO 覆盖配置(插件设置 / SEO 覆盖) → 预注入的 <meta name="description"> 的 content → 实体固定值 →
站点描述(设置 / SEO
设置) → 不输出
局限性说明:插件读取的
<title>和<meta name="description">来自 Halo 在模板渲染前注入到内部模型(IModel)的值,由 Halo 核心框架写入,与主题模板无关。主题通过 Thymeleaf 模板动态渲染的标题/描述(如th:text表达式的计算结果)在此阶段尚未执行,因此无法被读取。如果主题依赖模板表达式定制标题格式,建议通过「SEO 覆盖」手动指定,以确保 SEO 标签内容与预期一致。
标题和描述字段均支持以下占位符,可自由组合:
| 占位符 | 展开为 |
|---|---|
%TITLE% |
预注入的 <title> 标签文本 → 实体固定值(见下表) |
%DESC% |
预注入的 <meta name="description"> content → 实体固定值(见下表) |
%SITENAME% |
站点标题 |
%SITEDESC% |
站点 SEO 描述 |
示例:描述填写 %TITLE% - %SITEDESC%,在文章页会展开为 文章标题 - 站点描述。
其中“实体固定值”因页面类型而异:
| 页面类型 | 标题实体值 | 描述实体值 |
|---|---|---|
| 文章详情页 | post.spec.title |
post.status.excerpt |
| 独立页面 | singlePage.spec.title |
singlePage.status.excerpt |
| 分类详情页 | category.spec.displayName |
category.spec.description |
| 标签详情页 | tag.spec.displayName |
tag.spec.description |
| 作者页 | user.spec.displayName |
user.spec.bio |
| 豆瓣(plugin-douban) | title |
无 |
| 其他页面 | 无 | 无 |
| 页面类型 | 模板 ID | 数据来源类型 | 文档 |
|---|---|---|---|
| 首页 | index |
无 | 模板变量 |
| 文章详情页 | post |
Post, User, Tag | 模板变量 |
| 独立页面 | page |
SinglePage, User | 模板变量 |
| 分类集合页 | categories |
无 | 模板变量 |
| 分类详情页 | category |
Category(封面、permalink) | 模板变量 |
| 标签集合页 | tags |
无 | 模板变量 |
| 标签详情页 | tag |
Tag(permalink) | 模板变量 |
| 文章归档页 | archives |
无 | 模板变量 |
| 作者页 | author |
User(头像、permalink) | 模板变量 |
路由前缀:分类集合、标签集合、归档页的 canonical URL 会读取 Halo CMS 的“主题路由设置”(设置 / 主题路由设置)配置,与站点实际路由保持同步,不使用硬编码路径。
| 页面类型 | 模板 ID | 插件 |
|---|---|---|
| 瞬间列表 | moments |
plugin-moments |
| 瞬间详情 | moment |
plugin-moments |
| 图库 | photos |
plugin-photos |
| 朋友圈 | friends |
plugin-friends-new |
| 豆瓣 | douban |
plugin-douban |
| 番剧 | bangumi |
halo-plugin-bangumi-data |
并非所有页面都拥有完整的 SEO 字段。当某个字段为空时,对应的 meta/script 标签会被自动省略(不输出空值标签),以保证结构化数据的有效性。
| 页面类型 | og:type |
Schema.org @type |
发布/更新时间 | 作者 | 关键词 | 说明 |
|---|---|---|---|---|---|---|
| 文章详情页 | article |
BlogPosting |
✅ | ✅ | ✅ 文章标签 | 字段最完整的页面类型 |
| 独立页面 | article |
BlogPosting |
✅ | ✅ | ✅ 站点关键词 | 独立页面无标签,关键词回退到站点级 |
| 分类详情页 | website |
WebPage |
❌ | ❌ | ✅ 分类名 | 分类无发布时间和作者 |
| 标签详情页 | website |
WebPage |
❌ | ❌ | ✅ 标签名 | 标签无发布时间和作者 |
| 作者页 | profile |
ProfilePage |
❌ | ✅ | ✅ 作者名 | 作者页无发布时间 |
| 列表/聚合页 | website |
WebPage |
❌ | ❌ | ✅ 站点关键词 | 首页、分类集合、标签集合、文章归档页、所有第三方插件页面 |
省略规则:当发布/更新时间为空时,
og:release_date、og:modified_time、bytedance:published_time、bytedance:updated_time不输出;百度时间因子<script>中的pubDate/upDate字段不输出,若两者均为空则整个百度 script 标签不输出;Schema.org JSON-LD 中的datePublished/dateModified字段不输出。当作者为空时,og:author不输出。
- canonical 链接
- alternate 链接
- 标题、描述、封面图
- 作者、标签、发布时间
- 站点信息
- 文章标题、摘要、封面
- 作者、分类、发布时间
- 站点名称、Logo
- 内容标题、描述、图片
- 作者信息、发布时间
- 站点标识
- 文章结构化数据
- 作者信息
- 发布时间(带时区)
- 标题、描述、图片
- 站点 Twitter/X 账号信息
- 作者 Twitter/X 账号信息
- Google (Googlebot)
- 百度 (Baiduspider)
- 字节跳动 (Bytespider)
- 必应 (Bingbot)
- 360搜索 (360spider)
- 搜狗 (Sogou)
- Yandex
- DuckDuckGo (DuckDuckBot)
- 雅虎 (Slurp)
- Ask (Teoma)
- Java 21+
- Node.js 18+
- pnpm
# 构建插件
./gradlew build
# 开发前端
cd ui
pnpm install
pnpm dev./gradlew build构建完成后,可以在 build/libs 目录找到插件 jar 文件。

