(не рекомендуется) Переопределение шаблонов Discourse из темы или плагина

В идеале при кастомизации Discourse через темы или плагины следует использовать CSS, JavaScript Plugin API или plugin outlets. Если ни один из этих методов не подходит для вашего случая, не стесняйтесь создать PR в ядро Discourse или начать тему с тегом Development на Meta. Мы всегда рады обсудить добавление новых outlets/API для упрощения кастомизации.

Если вы исчерпали все другие варианты, возможно, вам придется прибегнуть к переопределению шаблонов (template overrides). Этот метод позволяет переопределить весь шаблон любого компонента Ember или маршрута из вашей темы или плагина.

:rotating_light: Это не рекомендуемый способ кастомизации Discourse. Ежедневные изменения в ядре Discourse в конечном итоге приведут к конфликтам с вашим переопределением шаблона, что может вызвать катастрофические ошибки при отображении форума.

Если вы решите использовать этот подход, убедитесь, что у вас есть достаточные процессы автоматизированного тестирования и QA для обнаружения регрессий. Если вы распространяете тему или плагин с переопределением шаблонов, пожалуйста, убедитесь, что администраторы форумов осведомлены о рисках нестабильности, которые несет ваша тема или плагин.

:rotaching_light: :rotating_light: :rotating_light: Обновление за октябрь 2023 года: Для новых функций Discourse всё чаще переходит к использованию компонентов, созданных с использованием формата файлов .gjs в Ember. Шаблоны для этих компонентов определяются внутри файла и не могут быть переопределены темами или плагинами.

В дальнейшем вся кастомизация шаблонов должна выполняться с использованием Plugin Outlets

Я понимаю, что это скоро перестанет работать, но покажите мне документацию всё равно

Переопределение шаблонов компонентов

Чтобы переопределить шаблон компонента Ember (то есть любой элемент в components/* в ядре Discourse), создайте файл с таким же именем .hbs в вашей теме или плагине. Например, чтобы переопределить шаблон компонента badge-button в ядре Discourse, создайте файл шаблона в вашей теме или плагине по следующему пути:

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

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

Переопределение всегда должно быть вложено в директорию /templates, даже если у основного компонента есть «колокализованный» шаблон.

Переопределение шаблонов маршрутов

Переопределение шаблонов маршрутов (то есть всех не-компонентных шаблонов в templates/*) работает так же, как и для компонентов. Создайте шаблон с таким же именем в вашей теме или плагине. Например, чтобы переопределить discovery.hbs в ядре, создайте файл:

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

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

Переопределение «сырых» шаблонов (.hbr)

Система «сырых» шаблонов Discourse скоро будет заменена обычными компонентами Ember. Но до тех пор переопределение сырых шаблонов работает так же, как и шаблонов Ember. Например, чтобы переопределить topic-list-item.hbr в ядре, можно создать файл:

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

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

Взаимодействие нескольких тем / плагинов

Если несколько установленных тем или плагинов переопределяют один и тот же шаблон, «победителем» становится тот, у которого наименьший номер ранга в этом списке:

  1. Переопределения тем (побеждает тема с наибольшим «id»)
  2. Переопределения плагинов (побеждает плагин с последним алфавитным именем)
  3. Ядро

Эта приоритетность также означает, что вы можете переопределять шаблоны плагинов из тем. Технически вы также можете переопределять шаблоны тем из других тем и шаблоны плагинов из других плагинов, но поведение может быть неожиданным из-за зависимости от имени плагина и id темы.

Как это работает?

Discourse собирает и определяет приоритеты шаблонов в классе DiscourseTemplateMap. Для колокализованных шаблонов компонентов эта информация используется во время инициализации приложения для замены ассоциаций шаблонов ядра. Для всех остальных шаблонов карта используется разрешителем во время выполнения для получения правильного шаблона.


Этот документ находится под контролем версий — предложите изменения на GitHub.

17 лайков

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 лайка

Is this still the case?

I’m a bit sad the ability to override a lot of code is being removed.

It makes sense to replace the bespoke Widget system, to some extent, but that gave us the ability to hook into existing code at multiple levels, reducing a lot of breaking change risk as we could target just small blocks in clever ways that would allow us to:

  • add features
  • not disturb anything else.

I’ve just had to remove TWO significant features from Discourse Journal, for example, that were based on fine grain overrides to widgets because the only way to have recreated them in Glimmer is via a pair of Template overrides (including an attempt to change a .gjs file) which is apparently no longer supported.

Even if this was supported, we would be left with overriding bigger stretches of code than under the widget framework, with an associated increase in risk of core changes conflicting with the overrides.

This isn’t healthy for the extensibility of the platform.

Can anything be done about it?

7 лайков

Yeah I hear you - there were some nice things about widget extensibility APIs.

But the flip side is that it’s been incredibly difficult for us to modify ANY of the widget-based UI in core, because we have no idea what random methods/decorations people might be introducing. That’s why widget customisations have seemed relatively stable - we’ve been too scared to touch the core implementations.

Our solution for this going forward is Wrapper Plugin Outlets. These allow themes and plugins to optionally override very small chunks of templates with their own implementation.

For example, see how Chat conditionally overrides the home-logo with a custom component. That works for the existing widget-based header, and the new glimmer-based header (coming soon! :tm:)

We’re generally happy to accept PRs to add new wrapper outlets in various places. If you’re unsure about a particular use-case, please feel free to open a Dev topic with details!

10 лайков

OK that’s sounds like a way forward, thank you.

I’ll need to digest the implications of that and adjust to a strategy along those lines.

Appreciate the response!

6 лайков