Overriding Discourse templates from a Theme or Plugin

Ideally, when customizing Discourse via themes/plugins, you should use CSS, the JavaScript Plugin API, or plugin outlets. If none of these work for your use-case, feel free to open a PR to Discourse core or start a #dev topic here on Meta. We’re always happy to discuss adding new outlets/APIs to make customization easier.

If you’ve exhausted all other options, you may need to resort to template overrides. This technique allows you to override the entire template of any Ember Component or Route from your theme/plugin.

:rotating_light: This is not a recommended way of customizing Discourse. Day-to-day changes in Discourse core will conflict with your template override eventually, potentially causing catastrophic errors when rendering the forum.

If you decide to take this approach, make sure you have sufficient automated testing and QA processes to detect regressions. If you distribute a theme/plugin with template overrides, please ensure forum admins are aware of the stability risks your theme/plugin carries.

Overriding Component Templates

To override an Ember Component template (i.e. anything under components/* in Discourse core), you should create an identically-named .hbs in your theme/plugin. For example, to override the template for the badge-button component in Discourse core, you would create a template file in your theme/plugin at this location:

:art: {theme}/javascripts/discourse/templates/components/badge-button.hbs

:electric_plug: {plugin}/assets/javascripts/discourse/templates/components/badge-button.hbs

The override must always be nested inside the /templates directory, even if the core component has a ‘colocated’ template.

Overriding Route Templates

Overriding route templates (i.e. all the non-component templates under templates/*) works in the same way as components. Create an identically named template in your theme/plugin. For example, to override discovery.hbs in core, you would create a file like

:art: {theme}/javascripts/discourse/templates/discovery.hbs

:electric_plug: {plugin}/assets/javascripts/discourse/templates/discovery.hbs

Overriding ‘Raw’ Templates (.hbr)

Discourse’s “raw” template system will soon be replaced by regular Ember components. But in the meantime, overriding raw templates works in the same way as Ember templates. For example, to override topic-list-item.hbr in core, you could create a file like:

:art: {theme}/javascripts/discourse/templates/list/topic-list-item.hbr

:electric_plug: {plugin}/assets/javascripts/discourse/templates/list/topic-list-item.hbr

Interaction between multiple themes / plugins

If multiple installed themes/plugins override the same template, the ‘winner’ is the one with the lowest-numbered ranking in this list:

  1. Theme overrides (highest theme ‘id’ wins)
  2. Plugin overrides (latest alphabetical plugin name wins)
  3. Core

This precedence also means that you can override plugin templates from themes. Technically you can also override theme templates from other themes, and plugin templates from other plugins, but the behaviour can be surprising because of the dependence on plugin-name and theme-id.

How does this work?

Discourse assembles and prioritises templates in the DiscourseTemplateMap class. For colocated component templates, that information is used during app initialization to replace the core template associations. For all other templates, the map is used by the resolver at runtime to fetch the correct template.

9 Likes

And what about mobile templates? What is the directory structure to rewrite templates from core

It should work exactly the same - you match the name of the core template. So if it has /mobile, include that in your override.

I try to rewrite mobile login.hbs template and it doesn’t work https://i.imgur.com/zOyJ5ET.png, am I right with the path?

The full path isn’t visible in your screenshot as far as I can see. Please can you paste it here as text.

themeroot/javascripts/mobile/modal/login.hbs

You’re missing discourse/templates from your path

So in your case, it would be {theme}/javascripts/discourse/templates/mobile/modal/login.hbs

2 Likes