{"id":48673185,"url":"https://github.com/howiehz/halo-plugin-transformer","last_synced_at":"2026-04-10T13:01:28.969Z","repository":{"id":349289947,"uuid":"1201769334","full_name":"HowieHz/halo-plugin-transformer","owner":"HowieHz","description":"适用于 Halo 的页面转换器插件","archived":false,"fork":false,"pushed_at":"2026-04-08T17:40:34.000Z","size":3852,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-08T19:22:45.444Z","etag":null,"topics":["halo","halo-plugin","halo-plugin-transformer"],"latest_commit_sha":null,"homepage":"","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":"Erzbir/halo-plugin-injector","license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/HowieHz.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-05T06:04:49.000Z","updated_at":"2026-04-08T18:34:05.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/HowieHz/halo-plugin-transformer","commit_stats":null,"previous_names":["howiehz/halo-plugin-injector","howiehz/halo-plugin-modifier"],"tags_count":11,"template":false,"template_full_name":null,"purl":"pkg:github/HowieHz/halo-plugin-transformer","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/HowieHz%2Fhalo-plugin-transformer","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/HowieHz%2Fhalo-plugin-transformer/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/HowieHz%2Fhalo-plugin-transformer/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/HowieHz%2Fhalo-plugin-transformer/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/HowieHz","download_url":"https://codeload.github.com/HowieHz/halo-plugin-transformer/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/HowieHz%2Fhalo-plugin-transformer/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31643431,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-10T07:40:12.752Z","status":"ssl_error","status_checked_at":"2026-04-10T07:40:11.664Z","response_time":98,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["halo","halo-plugin","halo-plugin-transformer"],"created_at":"2026-04-10T13:01:26.741Z","updated_at":"2026-04-10T13:01:28.954Z","avatar_url":"https://github.com/HowieHz.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# Halo CMS 页面转换器\n\n![GitHub](https://img.shields.io/github/license/HowieHz/halo-plugin-transformer)\n![GitHub all releases](https://img.shields.io/github/downloads/HowieHz/halo-plugin-transformer/total)\n![GitHub release (latest by date)](https://img.shields.io/github/downloads/HowieHz/halo-plugin-transformer/latest/total)\n![GitHub repo size](https://img.shields.io/github/repo-size/HowieHz/halo-plugin-transformer)\n[![Halo Version](https://img.shields.io/badge/Halo-2.23.2+-brightgreen.svg)](https://halo.run)\n\n## 简介\n\n这是一个用于**按规则改写指定页面内容**的 Halo CMS 插件。\n\nHalo CMS 自带的全局页面注入，更适合“整站统一加一段内容”这类场景。  \n如果你的需求更细一些，这个插件会更合适，比如：\n\n- 仅在特定页面路径下转换\n- 仅在特定模板 ID 下生效\n- 仅对 CSS 选择器命中的元素做插入、替换、移除\n\n这个插件不只追求“能改页面”，还想把下面这些事一起做好：\n\n- 规则表达足够灵活，尽量覆盖常见场景\n- 配置体验足够直接，尽量把问题拦在保存之前\n- 运行时开销尽量收紧，别把成本花在无效判断上\n- 控制台交互尽量顺手，少一点迷糊，少一点挫败感\n\n特别感谢 [Erzbir](https://github.com/Erzbir) 开源这个插件的雏形，给了一个很好的起点。  \n这个插件后续在规则能力、控制台体验和运行时处理上都继续推进到了新的高度，欢迎使用和反馈。\n\n## 功能介绍\n\n本插件目前提供这些能力：\n\n- 三种转换模式：\n    - `\u003chead\u003e`\n    - `\u003cfooter\u003e`\n    - `CSS 选择器`\n- 可组合的匹配规则：\n    - 页面路径匹配（以 `/` 开头，例如 `/archives/page/2`）\n    - 模板 ID 匹配（见下文[“模板 ID 匹配”](#模板-id-匹配)）\n    - `AND` / `OR`\n    - 本组 / 本项取反（`NOT`）\n    - 条件组嵌套\n- 两种规则编辑方式：\n    - 简单模式\n    - 高级模式（直接编辑规则树 JSON）\n- 单项与批量导入导出：\n    - 代码片段\n    - 转换规则\n- 规则级附加控制：\n    - 是否输出 `PluginTransformer start/end` 注释标记\n    - 运行顺序\n- 面向运行时的优化：\n    - 高频正则复用编译结果\n    - 实时规则 / 代码片段快照\n    - 页面范围预判与规则匹配优化\n    - 前后端双重校验，尽量避免坏规则落库\n- 体验优化：\n    - 移动端适配\n    - 无障碍适配\n\n## 快速开始\n\n如果你只是想先把插件跑起来，按下面三步做就够了：\n\n1. 在 Halo CMS 管理后台进入：工具 -\u003e `页面转换器`\n2. 新建一个代码片段（按需），再新建一条转换规则\n3. 转换规则可以先用页面路径做条件，确认生效后再逐步补模板 ID、CSS 选择器等更细的限制\n\n以下是页面预览：\n\n![config_snippet](assets/images/config_snippet.jpeg)\n![create_rule](assets/images/create_rule.jpeg)\n![mode_bulk](assets/images/mode_bulk.jpeg)\n![config_rule](assets/images/config_rule.jpeg)\n\n## 转换模式\n\n插件提供三种转换模式：\n\n| 模式         | 实现方式                  | 说明                                            |\n| ------------ | ------------------------- | ----------------------------------------------- |\n| `\u003chead\u003e`     | `TemplateHeadProcessor`   | 注入到 `\u003chead\u003e` 中                              |\n| `\u003cfooter\u003e`   | `TemplateFooterProcessor` | 注入到 `\u003chalo:footer /\u003e` 中，具体位置由主题控制 |\n| `CSS 选择器` | `TransformerWebFilter`    | 通过 CSS 选择器匹配并处理所有命中的元素         |\n\n\u003e 如果只是往 `\u003chead\u003e` 或 `\u003chalo:footer /\u003e` 插内容，优先用 `\u003chead\u003e` / `\u003cfooter\u003e` 模式理论上会有更好的性能。\n\n如果你在“全部满足（`AND`）”里加入“页面路径匹配”，插件就能先根据访问路径缩小范围，只处理少量需要改写 HTML 的页面。  \n如果规则没法先按页面路径缩小范围，比如完全没有页面路径条件，或者写成“页面路径 OR 模板 ID”这种组合，插件当然也还能工作；只是 `CSS 选择器` 模式会先处理所有页面，再继续判断别的条件，开销会明显更高，配置页也会给出性能提示。\n\n## 转换位置选项\n\n在 `CSS 选择器` 模式下，可以选择以下位置策略：\n\n- `append`：追加到目标元素内部末尾\n- `prepend`：插入到目标元素内部开头\n- `before`：插入到目标元素之前\n- `after`：插入到目标元素之后\n- `replace`：用代码片段替换目标元素\n- `remove`：直接移除目标元素\n\n\u003e `remove` 的意思是“把整个元素节点删掉”，不是清空内容，也不是隐藏元素。  \n\u003e 所以 `remove` 模式下不需要关联代码片段；保存时会自动清空“关联代码片段”，后端也会拒绝这类错误数据。管理后台里选择 `remove` 后，也不会再显示“关联代码片段”选择区。\n\n\u003e 注入到 `\u003chead\u003e` 时仍需注意 HTML 合法性。  \n\u003e 例如：\u003cdiv\u003e 这类块级元素并不会保留在 \u003chead\u003e 里，浏览器或 HTML 解析器通常会把它改放到 \u003cbody\u003e 中。\n\n## 规则级附加选项\n\n- 每条规则都可单独配置“注释标记”\n    - 开启后会输出 `\u003c!-- PluginTransformer start --\u003e` 与 `\u003c!-- PluginTransformer end --\u003e`\n    - `remove` 模式下不会显示“注释标记”选项，因为它会直接删除目标元素，不会留下适合输出注释标记的位置。\n- 每条规则也可单独配置运行顺序：\n    - 只影响**同一执行阶段**（同一转换模式）内的规则先后\n    - 数值越小越先执行\n    - 同值时先按规则名称字母序稳定执行；若名称相同或为空，再按规则 `id` 字母序兜底\n    - 控制台提供六档快捷值，也可选择输入整数精确值\n\n## 匹配规则\n\n每条转换规则都会带一套“匹配规则”，用来描述“这条规则到底在什么情况下生效”。  \n如果你在接口文档或报错信息里看到 `matchRule`，它说的就是这里这套东西。\n\n### 简单模式\n\n通过图形化界面编辑规则，支持：\n\n- 页面路径规则\n- 模板 ID 规则\n- 全部满足（`AND`）\n- 任一满足（`OR`）\n- 本组 / 本项取反（`NOT`）\n- 条件组嵌套\n\n如果某个条件组暂时没有子条件，编辑器会直接提示错误；空组不能保存。\n\n### 高级模式\n\n如果你已经很熟悉这套规则，也可以直接编辑规则树 JSON。\n\n- 根节点必须是 `GROUP`\n- 叶子节点支持：\n    - `PATH`\n        - `ANT`\n        - `REGEX`\n        - `EXACT`\n    - `TEMPLATE_ID`\n        - `REGEX`\n        - `EXACT`\n\n示例：\n\n```json\n{\n    \"type\": \"GROUP\",\n    \"operator\": \"AND\",\n    \"negate\": false,\n    \"children\": [\n        {\n            \"type\": \"PATH\",\n            \"matcher\": \"ANT\",\n            \"value\": \"/posts/**\",\n            \"negate\": false\n        },\n        {\n            \"type\": \"GROUP\",\n            \"operator\": \"OR\",\n            \"negate\": false,\n            \"children\": [\n                {\n                    \"type\": \"TEMPLATE_ID\",\n                    \"matcher\": \"EXACT\",\n                    \"value\": \"post\",\n                    \"negate\": false\n                },\n                {\n                    \"type\": \"TEMPLATE_ID\",\n                    \"matcher\": \"REGEX\",\n                    \"value\": \"^(post|page)$\",\n                    \"negate\": false\n                }\n            ]\n        }\n    ]\n}\n```\n\n## 导入与导出\n\n插件支持单项导出 / 导入，也支持代码片段、转换规则各自独立的批量导出 / 导入。\n\n导入导出遵循下面这些约束：\n\n- 面向“可移植、可继续编辑的内容”\n- 不携带 `id`、排序、系统元数据\n- 规则导出 / 导入不携带关联关系\n- 导出的 JSON 自动附带 `$schema`，方便在支持 JSON Schema 的编辑器里拿到提示和校验\n\n批量模式支持：\n\n- 批量导入\n- 批量导出\n- 批量启用\n- 批量禁用\n- 批量删除\n\n如果你要接外部工具链，或者打算自己生成导入文件，完整的协议细节、字段约束和错误恢复语义见 [CONTRIBUTING.md](./CONTRIBUTING.md)。\n\n## 编辑与校验\n\n### 配置页体验\n\n- 简单模式能即时定位多个错误；高级模式会尽量定位到具体 JSON 行\n- 正则表达式会在前后端都做校验，不必等到运行时才发现“怎么没生效”\n- 左侧“代码片段”和“转换规则”列表支持拖拽排序\n- 支持单项导出，也支持进入批量操作模式\n- 新建资源时可以先导入模板，也可以预先决定创建后默认启用还是禁用\n- 编辑中切换标签、切换资源、直接新建或关闭弹窗时，如存在未保存修改会先确认\n- 已修改但尚未保存的字段会显示“撤销修改”\n- 移动端下，左侧资源列表和右侧关联面板会收起成可展开侧边栏，避免三栏把编辑区挤没\n- 高级模式下：\n    - JSON 合法时可执行“格式化 JSON”\n    - JSON 非法时可执行“重建 JSON”，按当前简单模式配置重新生成\n- 代码片段内容与高级模式编辑器都带行号\n\n### 写入期校验\n\n为了减少“填了半天，结果一保存才发现不合法”的情况，这套校验分两层：\n\n- 编辑时：前端尽量即时提示错误，方便边改边修\n- 保存时：后端再次兜底校验，避免坏数据落库\n\n导入代码片段 / 转换规则 JSON 时，也会先做一轮前端校验。  \n如果只是少了几个可以自动补默认值的字段，会直接补上；如果问题还属于“能导进来、再慢慢改”的类型，就允许先导入、再修改。\n\n完整的控制台状态模型、排序语义、批量导入流程和未保存草稿处理约定见 [CONTRIBUTING.md](./CONTRIBUTING.md)。\n\n## 运行时与性能\n\n### 运行时表现\n\n能在请求外提前做掉的事，就尽量不要留到真正处理页面时再做。\n\n- 高频正则会复用编译结果，避免重复 `Pattern.compile`\n- `ANT` 风格的页面路径匹配会复用统一匹配器，减少重复判断\n- 规则会先做优化和页面范围预判，减少不必要的 HTML 改写\n- 规则变更会自动同步到实时规则快照，连接抖动后也会自动恢复\n- 删除代码片段时会先进入后台清理流程；控制台列表会立即隐藏这类“删除中”的资源，它们也不会再出现在可编辑 / 可关联集合里，避免出现“明明已经删了，怎么列表里还在”的滞后感\n- 若 `CSS 选择器` 规则还不能先按页面路径缩小范围，插件仍会工作，但开销会明显更高\n\n更完整的校验清单、规则优化细节、运行时处理链路和并发写入约束见 [CONTRIBUTING.md](./CONTRIBUTING.md)。\n\n## 模板 ID 匹配\n\n### 已知限制\n\n- 模板 ID 匹配依赖页面正确暴露 `_templateId`\n- 对 Halo 自带页面，或者正确接入模板 ID 的插件页面，这条链路通常都能稳定工作\n- 如果第三方页面没有暴露模板 ID，插件就拿不到可靠的模板身份\n- 遇到这种情况时，建议优先改用路径这类更稳定的条件\n\n### 常见模板 ID\n\n### Halo 内置页面\n\n| 模板 ID      | 说明         |\n| ------------ | ------------ |\n| `index`      | 首页         |\n| `categories` | 分类列表页   |\n| `category`   | 单个分类页   |\n| `archives`   | 归档页       |\n| `post`       | 文章详情页   |\n| `tag`        | 单个标签页   |\n| `tags`       | 标签列表页   |\n| `page`       | 单个独立页面 |\n| `author`     | 作者页       |\n\n### 常见插件页面\n\n| 模板 ID   | 来源                                                                      | 说明                                     |\n| --------- | ------------------------------------------------------------------------- | ---------------------------------------- |\n| `moments` | [瞬间插件](https://github.com/halo-sigs/plugin-moments)                   | 瞬间列表页，常见路径为 `/moments`        |\n| `moment`  | [瞬间插件](https://github.com/halo-sigs/plugin-moments)                   | 瞬间详情页，常见路径为 `/moments/{slug}` |\n| `photos`  | [图库管理插件](https://github.com/halo-sigs/plugin-photos)                | 图库页，常见路径为 `/photos`             |\n| `friends` | [朋友圈插件](https://github.com/chengzhongxue/plugin-friends-new)         | 朋友圈页，常见路径为 `/friends`          |\n| `douban`  | [豆瓣插件](https://github.com/chengzhongxue/plugin-douban)                | 豆瓣页，常见路径为 `/douban`             |\n| `bangumi` | [BangumiData 插件](https://github.com/ShiinaKin/halo-plugin-bangumi-data) | 番剧页，常见路径为 `/bangumi`            |\n\n\u003e 上面这些字符串本身就是要填写的模板 ID。  \n\u003e 第三方插件是否能用于“模板 ID 匹配”，取决于它有没有正确提供 `_templateId`。\n\n## 更新日志\n\n参见 [CHANGELOG.md](./CHANGELOG.md)。\n\n## 开发与贡献\n\n如果你准备改代码、提 PR、看实现细节，参见 [CONTRIBUTING.md](./CONTRIBUTING.md)。\n\n## 发布策略\n\n参见 [RELEASES.md](./RELEASES.md)。\n\n## 许可证\n\n[GPL-3.0](./LICENSE) © HowieHz\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhowiehz%2Fhalo-plugin-transformer","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhowiehz%2Fhalo-plugin-transformer","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhowiehz%2Fhalo-plugin-transformer/lists"}