(não recomendado) Sobrescrevendo modelos 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 plugin outlets. Se nenhum desses funcionar para o seu caso de uso, sinta-se à vontade para abrir um PR para o core do Discourse ou iniciar um tópico Dev aqui no Meta. Estamos sempre felizes em discutir a adição de novos outlets/APIs para facilitar a personalização.

Se você esgotou todas as outras opções, pode ser necessário recorrer a substituições de templates. Essa técnica permite que você substitua todo o template 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 core do Discourse irão entrar em conflito com sua substituição de template eventualmente, potencialmente causando erros catastróficos ao renderizar o fórum.

Se você decidir seguir essa abordagem, 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 template, 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á se movendo cada vez mais para o uso de componentes criados usando o formato de arquivo .gjs do Ember. Os templates para esses componentes são definidos inline e não podem ser substituídos por temas/plugins.

Daqui para frente, todas as personalizações de template devem ser feitas usando Plugin Outlets

[details=Eu entendo que isso quebrará em um futuro próximo, mostre a documentação de qualquer maneira]

Substituindo Templates de Componentes

Para substituir um template de Componente Ember (ou seja, qualquer coisa sob components/* no core do Discourse), você deve criar um arquivo .hbs com nome idêntico em seu tema/plugin. Por exemplo, para substituir o template do componente badge-button no core do Discourse, você criaria um arquivo de template em 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 sempre ser aninhada dentro do diretório /templates, mesmo que o componente core tenha um template ‘colocado’.

Substituindo Templates de Rotas

A substituição de templates de rotas (ou seja, todos os templates não componentes sob templates/*) funciona da mesma forma que os componentes. Crie um template com nome idêntico em seu tema/plugin. Por exemplo, para substituir discovery.hbs no core, você criaria um arquivo como

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

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

Substituindo Templates ‘Raw’ (.hbr)

O sistema de template “raw” do Discourse em breve será substituído por componentes Ember regulares. Mas, por enquanto, a substituição de templates raw funciona da mesma forma que os templates Ember. Por exemplo, para substituir topic-list-item.hbr no core, 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 template, o “vencedor” é aquele com a menor classificação numérica nesta lista:

  1. Substituições de temas (o maior ‘id’ do tema vence)
  2. Substituições de plugins (o nome alfabético mais recente do plugin vence)
  3. Core

Essa precedência também significa que você pode substituir templates de plugins a partir de temas. Tecnicamente, você também pode substituir templates de temas de outros temas, e templates de plugins 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 templates na classe DiscourseTemplateMap. Para templates de componentes colocados, essas informações são usadas durante a inicialização do aplicativo para substituir as associações de template do core. Para todos os outros templates, o mapa é usado pelo resolver em tempo de execução para buscar o template correto.


Este documento é controlado por 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