理想情况下,当通过主题/插件自定义 Discourse 时,您应该使用 CSS、JavaScript 插件 API 或 插件插槽(plugin outlets)。如果这些方法不适用于您的情况,请随时向 Discourse 核心提交一个 PR 或在 Meta 上发起一个 Dev 主题。我们非常乐意讨论添加新的插槽/API 以简化自定义过程。
如果您已用尽所有其他选项,则可能需要诉诸模板覆盖。此技术允许您从主题/插件中覆盖任何 Ember 组件或路由的整个模板。
这不是自定义 Discourse 的推荐方式。 Discourse 核心的日常更改最终会与您的模板覆盖发生冲突,从而可能在渲染论坛时导致灾难性错误。
如果您决定采用此方法,请确保您拥有足够的自动化测试和 QA 流程来检测回归。如果您分发带有模板覆盖的主题/插件,请确保论坛管理员了解您的主题/插件带来的稳定性风险。
![]()
![]()
2023 年 10 月更新:对于新功能,Discourse 越来越多地转向使用使用 Ember 的
.gjs文件格式编写的组件。这些组件的模板是内联定义的,无法被主题/插件覆盖。从今往后,所有模板自定义应使用 插件插槽(Plugin Outlets)完成。
我明白这在不久的将来会中断,仍然向我展示文档
覆盖组件模板
要覆盖 Ember 组件模板(即 Discourse 核心中 components/* 下的任何内容),您应该在主题/插件中创建一个同名的 .hbs 文件。例如,要覆盖 Discourse 核心中 badge-button 组件的模板,您需要在主题/插件中此位置创建一个模板文件:
{theme}/javascripts/discourse/templates/components/badge-button.hbs
{plugin}/assets/javascripts/discourse/templates/components/badge-button.hbs
覆盖必须始终嵌套在 /templates 目录下,即使核心组件具有“共置”模板也是如此。
覆盖路由模板
覆盖路由模板(即 Discourse 核心中 templates/* 下所有非组件模板)的方法与组件相同。在主题/插件中创建同名模板即可。例如,要覆盖核心中的 discovery.hbs,您可以创建如下文件:
{theme}/javascripts/discourse/templates/discovery.hbs
{plugin}/assets/javascripts/discourse/templates/discovery.hbs
覆盖“原始”模板 (.hbr)
Discourse 的“原始”模板系统很快将被标准的 Ember 组件取代。但在此之前,覆盖原始模板的方法与 Ember 模板相同。例如,要覆盖核心中的 topic-list-item.hbr,您可以创建一个文件,如下所示:
{theme}/javascripts/discourse/templates/list/topic-list-item.hbr
{plugin}/assets/javascripts/discourse/templates/list/topic-list-item.hbr
多个主题/插件之间的交互
如果多个已安装的主题/插件覆盖了相同的模板,则“获胜者”是在此列表中排名编号最低的那个:
- 主题覆盖(ID 最高的 ID 获胜)
- 插件覆盖(最新字母顺序的插件名称获胜)
- 核心
此优先级也意味着您可以从主题覆盖插件模板。技术上您也可以从其他主题覆盖主题模板,以及从其他插件覆盖插件模板,但这可能因为依赖于插件名称和主题 ID 而产生令人惊讶的行为。
这是如何工作的?
Discourse 在 DiscourseTemplateMap 类中组装和确定模板的优先级。对于共置的组件模板,该信息在 应用程序初始化期间用于替换核心模板关联。对于所有其他模板,运行时解析器使用该映射来获取正确的模板。
本文档受版本控制 - 在 github 上建议更改。