(não recomendado) Sobrescrevendo templates do Discourse a partir de um Tema ou Plugin

Idealmente, ao personalizar o Discourse por meio de temas/plugins, você deve usar CSS, a API de Plugin JavaScript ou saídas de plugin (plugin outlets). Se nenhuma dessas opções funcionar para o seu caso de uso, sinta-se à vontade para abrir um PR no núcleo do Discourse ou iniciar um tópico Dev aqui no Meta. Estamos sempre felizes em discutir a adição de novas saídas/APIs para facilitar a personalização.

Se você esgotou todas as outras opções, pode ser necessário recorrer a substituições de modelo (template overrides). Esta técnica permite substituir o modelo inteiro de qualquer Componente Ember ou Rota do seu tema/plugin.

:rotating_light: Esta não é uma maneira recomendada de personalizar o Discourse. Mudanças do dia a dia no núcleo do Discourse irão entrar em conflito com sua substituição de modelo eventualmente, potencialmente causando erros catastróficos ao renderizar o fórum.

Se você decidir seguir este caminho, certifique-se de ter testes automatizados e processos de QA suficientes para detectar regressões. Se você distribuir um tema/plugin com substituições de modelo, certifique-se de que os administradores do fórum estejam cientes dos riscos de estabilidade que seu tema/plugin acarreta.

:rotating_light: :rotating_light: :rotating_light: Atualização de Outubro de 2023: Para novos recursos, o Discourse está migrando cada vez mais para o uso de componentes criados usando o formato de arquivo .gjs do Ember. Os modelos para esses componentes são definidos inline e não podem ser substituídos por temas/plugins.

Doravante, todas as personalizações de modelo devem ser feitas usando Plugin Outlets

Eu entendo que isso quebrará em um futuro próximo, mostre-me a documentação de qualquer maneira

Substituindo Modelos de Componentes

Para substituir um modelo de Componente Ember (ou seja, qualquer coisa sob components/* no núcleo do Discourse), você deve criar um arquivo .hbs com o mesmo nome no seu tema/plugin. Por exemplo, para substituir o modelo do componente badge-button no núcleo do Discourse, você criaria um arquivo de modelo no seu tema/plugin neste local:

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

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

A substituição deve estar sempre aninhada dentro do diretório /templates, mesmo que o componente principal tenha um modelo ‘co-localizado’.

Substituindo Modelos de Rota

Substituir modelos de rota (ou seja, todos os modelos que não são de componentes sob templates/*) funciona da mesma forma que os componentes. Crie um modelo com o mesmo nome no seu tema/plugin. Por exemplo, para substituir discovery.hbs no núcleo, você criaria um arquivo como

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

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

Substituindo Modelos ‘Brutos’ (.hbr)

O sistema de modelo “bruto” do Discourse será em breve substituído por componentes Ember regulares. Mas, por enquanto, substituir modelos brutos funciona da mesma forma que modelos Ember. Por exemplo, para substituir topic-list-item.hbr no núcleo, você poderia criar um arquivo como:

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

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

Interação entre Múltiplos Temas / Plugins

Se múltiplos temas/plugins instalados substituírem o mesmo modelo, o ‘vencedor’ é aquele com a classificação numérica mais baixa nesta lista:

  1. Substituições de tema (o maior ‘id’ de tema vence)
  2. Substituições de plugin (o nome de plugin alfabeticamente mais recente vence)
  3. Núcleo

Esta precedência também significa que você pode substituir modelos de plugin a partir de temas. Tecnicamente, você também pode substituir modelos de tema a partir de outros temas, e modelos de plugin a partir de outros plugins, mas o comportamento pode ser surpreendente devido à dependência do nome do plugin e do id do tema.

Como isso funciona?

O Discourse monta e prioriza os modelos na classe DiscourseTemplateMap. Para modelos de componentes co-localizados, essa informação é usada durante a inicialização do aplicativo para substituir as associações de modelo do núcleo. Para todos os outros modelos, o mapa é usado por o resolvedor em tempo de execução para buscar o modelo correto.


Este documento tem controle de versão - sugira alterações no github.

17 curtidas

E quanto aos modelos para dispositivos móveis? Qual é a estrutura de diretórios para reescrever modelos do core

Deve funcionar exatamente da mesma forma - você corresponde ao nome do modelo principal. Portanto, se ele tiver /mobile, inclua isso em sua substituição.

Estou tentando reescrever o template de login do mobile.hbs e não está funcionando Imgur: The magic of the Internet, estou certo com o caminho?

O caminho completo não está visível na sua captura de tela, pelo que pude ver. Por favor, pode colá-lo aqui como texto.

themeroot/javascripts/mobile/modal/login.hbs

Você está perdendo discourse/templates no seu caminho

Portanto, no seu caso, seria {theme}/javascripts/discourse/templates/mobile/modal/login.hbs

2 curtidas

Isso ainda é verdade?

Fico um pouco triste que a capacidade de substituir muito código esteja sendo removida.

Faz sentido substituir o sistema de Widgets personalizado, em certa medida, mas isso nos deu a capacidade de nos conectar ao código existente em vários níveis, reduzindo muito o risco de alterações drásticas, pois poderíamos direcionar apenas pequenos blocos de maneiras inteligentes que nos permitiriam:

  • adicionar recursos
  • não perturbar mais nada.

Tive que remover DOIS recursos significativos do Discourse Journal, por exemplo, que eram baseados em substituições de granularidade fina de widgets porque a única maneira de recriá-los em Glimmer é por meio de um par de substituições de Template (incluindo uma tentativa de alterar um arquivo .gjs), o que aparentemente não é mais suportado.

Mesmo que isso fosse suportado, ficaríamos com a substituição de trechos maiores de código do que sob o framework de widgets, com um aumento associado no risco de alterações principais entrarem em conflito com as substituições.

Isso não é saudável para a extensibilidade da plataforma.

Algo pode ser feito a respeito?

7 curtidas

Sim, entendo você - havia algumas coisas boas nas APIs de extensibilidade de widgets.

Mas o outro lado é que tem sido incrivelmente difícil para nós modificar QUALQUER interface de usuário baseada em widget no núcleo, porque não temos ideia de quais métodos/decorações aleatórios as pessoas podem estar introduzindo. É por isso que as personalizações de widgets pareceram relativamente estáveis - ficamos com muito medo de tocar nas implementações principais.

Nossa solução para isso daqui para frente são os Plugin Outlets Wrapper. Eles permitem que temas e plugins substituam opcionalmente pedaços muito pequenos de templates com sua própria implementação.

Por exemplo, veja como o Chat condicionalmente substitui o home-logo com um componente personalizado. Isso funciona para o cabeçalho existente baseado em widget e para o novo cabeçalho baseado em glimmer (em breve! :tm:).

Geralmente estamos felizes em aceitar PRs para adicionar novos wrapper outlets em vários lugares. Se você tiver dúvidas sobre um caso de uso específico, sinta-se à vontade para abrir um tópico Dev com detalhes!

10 curtidas

OK, isso parece um caminho a seguir, obrigado.

Precisarei digerir as implicações disso e ajustar uma estratégia nessa direção.

Agradeço a resposta!

6 curtidas