Magento 2 — Guia de sobrevivência no Front-end (Parte 2)
No primeiro artigo mostrei algumas questões básicas sobre os temas, se você perdeu essa parte, clique aqui para lê-lo.
O Magento 2 utiliza XML de diversas formas diferentes, disponibilizando várias configurações da loja e até mesmo configurações de classes PHP. No front-end o XML que mais utilizamos é o Layout XML, assunto esse que gera bastante dúvidas quando um desenvolvedor começa a customizar o front-end na plataforma.
Nessa segunda parte veremos as principais funcionalidades que um front-end utiliza quando se está trabalhando com Layout XML.
Qual o propósito do Layout XML?
O principal propósito desse recurso é customizar uma página específica, como a página de categoria, por exemplo. Porém, existem alguns casos em que podemos utilizá-lo para customizar diversas páginas ao mesmo tempo.
Quando estamos trabalhando com Layout XML, tratamos páginas como handles
, sendo que cada página pode ter 1 ou mais handles
. Abaixo vou listar os mais conhecidos:
default
— Todas as páginascms_index_index
— Homecatalog_category_view
— Categoriacatalog_product_view
— Produtocheckout_cart_index
— Carrinhocheckout_index_index
— Checkout
Cada handle
desse é encarregado em customizar alguma parte da loja. Vamos pegar como exemplo o cms_index_index
, este talvez seja o mais utilizado. Isso porque ele é o responsável pela página inicial (Home). Veja abaixo um simples exemplo de como adicionar um novo bloco na home utilizando esse handle
.
No exemplo acima estou adicionando um simples texto na página inicial, não se atenha ainda para as instruções, vamos falar delas mais pra frente. Repare o nome do arquivo na barra inferior, ele é exatamente igual ao handle
que comentamos, isso indica para o Magento que todo o conteúdo desse arquivo será utilizado apenas na página inicial.
Certo, mas onde podemos colocar esse arquivo?
Bom, existem alguns lugares dentro do tema em que podemos inserir novos XMLs. Repare na imagem abaixo como ficou a estrutura de pastas do tema após criar o XML acima:
Cada handle
que trabalhamos no nosso tema ficará dentro de uma pasta com o código de um módulo. No nosso exemplo foi adicionada a pasta Magento_Theme
(Apesar de ter o nome Theme
, este é o código de um módulo contido no core
do Magento e, nesse caso, não representa o tema).
Nós podemos adicionar nossos XMLs em qualquer pasta com o código de um módulo (Magento_Theme
ou Magento_Catalog
por exemplo), porém, por convenção, nós adicionamos os XMLs nos módulos que são responsáveis por eles. Em outras palavras, se você estiver trabalhando com o handle checkout_index_index
(Que cuida da página de Checkout) faz sentido colocá-lo na pasta Magento_Checkout
. Isso irá ajudar (E muito) quando você precisar encontrar qual arquivo está criando algum bloco na página, pois você pode associar qual é o módulo responsável por ela e descartar as outras pastas.
A outra pasta necessária é a pasta layout
dentro da pasta do módulo. Nessa pasta estarão todos os arquivos XMLs que esse módulo é responsável. Após isso é só criar o arquivo seguindo o padrão nome_do_handle.xml
e adicionar as instruções necessárias.
Handles especiais
No exemplo acima utilizamos o cms_index_index.xml
, que fica responsável apenas pela página inicial, mas e quando precisamos adicionar instruções para diversas páginas?
Para isso existem alguns handles que agem em diversas páginas ao mesmo tempo. O principal é o default
(default.xml
), que é o responsável por todas as páginas. Utilizamos muito esse handle para customizar o header
e o footer
, já que eles estão presentes na maioria das páginas.
Blocks e Containers
Certo, agora que entendemos para que servem os handles
, iremos abordar as instruções que podemos utilizar dentro dos XMLs.
Até o final do artigo iremos ver as principais instruções disponíveis nos XMLs, mas a maioria delas giram em torno dos blocks
e dos containers
. Essas são as principais instruções que utilizaremos, as outras são utilizadas para modificar algo deles. Vamos começar pelo mais complexo que é o block.
Block
Uma página é formada por diversos blocos, então podemos dizer que um block
é um pedaço de um todo. É com ele que iremos falar para o Magento renderizar um phtml
(Arquivo que contém instruções php
e html
), sendo que esse phtml
poderá chamar métodos disponíveis em uma classe PHP especificada na propriedade class
(Note no código acima, estamos usando a classe Magento\...\Template
).
Repare no arquivo abaixo. Este é o nosso custom.phtml
que especificamos no XML acima. Falamos que o caminho do phtml
é o Magento_Theme::html/custom.phtml
, isso indica para o Magento que o nosso phtml estará localizado no seguinte caminho:
Nele iremos chamar um método disponível na classe Template
, que é o getBaseUrl()
. Esse método está disponível no phtml pois o Magento associa o arquivo de template ( phtml
) com a classe PHP
.
Como foi citado anteriormente, nesse arquivo nós podemos utilizar tanto HTML
quanto instruções PHP
. No nosso exemplo o método getBaseUrl
está sendo atribuído à uma variável no começo do arquivo, que está sendo utilizada logo após, dentro de uma tag p
.
Uma coisa interessante que entrou no Magento na versão 2.2 é que agora, se precisarmos criar um bloco com a classe que usamos no XML acima (A classe Template.php
), não precisamos mais passar o atributo class
, o Magento irá automaticamente associar essa classe ao bloco, já que essa é a classe padrão dos blocos.
Mas e se for preciso alterar um bloco que já existe?
Há também os casos em que precisamos alterar o comportamento de um bloco que já foi criado, seja um bloco criado pelo core do Magento, ou por um módulo de terceiro. Nesse caso não podemos utilizar a tag block
, pois isso irá sobrescrever o bloco previamente criado.
Isso se dá porque quando o Magento encontra dois blocos com o mesmo nome, apenas o último será carregado e o anterior será descartado, técnica conhecida como override de bloco.
Para que isso não aconteça, nós usamos a tag referenceBlock
. Com ela podemos informar o nome do bloco que queremos alterar, e em seguida podemos fazer nossas alterações.
Podemos fazer uma série de alterações com o referenceBlock
, listei abaixo abaixo as alterações mais utilizadas.
Alterar o template
do bloco:
Existem alguns casos que será necessário alterar o template de um bloco, podemos fazer isso de duas formas.
A primeira, e mais comum, é utilizando a própria tag template no referenceBlock
, assim como é utilizado ao criar um bloco novo:
Repare que precisamos apenas passar o nome do bloco original, em seguida passamos a propriedade template, indicando o novo template que será utilizado.
Um erro comum é quando o desenvolvedor copia todas as propriedades que existem na declaração do bloco (como a propriedade class
, por exemplo) e deixa no referenceBlock
. Isso não é necessário, já que o referenceBlock
só precisa do name
para funcionar.
A segunda forma de alterar o template é usando os arguments
, tag bastante utilizada para passar parâmetros aos blocos:
A ideia é a mesma da forma anterior, através da tag argument
podemos alterar o template no bloco.
Porém, existe uma desvantagem em usar esse método. O Magento considera que a primeira forma (Utilizando a propriedade direto no referenceBlock
) tem uma prioridade maior do que o argument
. Com isso, se você estiver usando essa forma para alterar um template que foi definido através do primeiro método, a sua alteração não vai funcionar, te forçando usar via propriedade.
Adicionar novos blocos
Também é possível adicionar novos blocos usando o referenceBlock
.
Repare que estamos criando um novo bloco dentro do que criamos anteriormente, criando um novo nó na hierarquia do layout.
Para fazer esse novo bloco aparecer, temos que fazer uma alteração no template do bloco simple.block.example
e informar onde o bloco filho deve ser renderizado. O template irá ficar assim:
Para isso nós chamamos o método getChildHtml
(Ver linha 9 acima), e passamos como parâmetro o nome do bloco que queremos que seja renderizado naquela parte do HTML, isso irá retornar o HTML processado do bloco child.block
.
Há também a possibilidade de renderizar todos os blocos filhos de uma vez, caso você crie mais de um bloco, ao invés de chamar cada bloco individualmente:
Repare que agora não passamos nada como parâmetro, dessa forma o Magento irá pegar todos os blocos filhos e renderizar onde antes estava renderizando apenas o bloco que passamos o nome.
Podemos fazer bastante customizações usando o referenceBlock
, porém esses dois exemplos acima são os mais utilizados quando usamos essa tag.
Container
Esta é uma nova funcionalidade no Magento 2 que chegou para ajudar no agrupamento de elementos, sejam eles outros containers ou blocos.
Com o container nós podemos criar elementos HTML simples direto pelo XML, isso irá ajudar bastante quando estivermos customizando as páginas.
Repare no exemplo acima, na linha 11, temos um container sendo criado. Nele podemos passar várias informações, como o name por exemplo, que tem a mesma lógica do name dos blocos (Deve ser único e é utilizado quando queremos fazer uma alteração nele).
Há também outros atributos que são específicos dos containers, como o htmlTag
, htmlClass
e o htmlId
. A ideia de cada um é bem clara:
htmlTag
: Atributo responsável por falar qual será a tag que o container irá utilizar para ser renderizado no HTML final.htmlClass
: Nesse atributo nós podemos passar a classe CSS que será inserida na tag do container (Se quiser passar mais de uma, deve-se usar espaço entre as classes).htmlId
: Aqui nós podemos definir um id para essa tag, este irá ser renderizado como um atributo no HTML.
referenceContainer
Talvez seja mais comum o uso do referenceContainer
se comparado ao container
em si. Isso porque os layouts base do Magento são criados basicamente via containers
, com isso os elementos que utilizamos para inserir nossos blocos já foram criados previamente e precisamos utilizar o referenceContainer
, veja abaixo um exemplo:
Esse é um dos layouts base que estão disponíveis no Magento 2, repare que só temos containers sendo criados. Com isso, nós temos que utilizar o referenceContainer
para que possamos adicionar um novo bloco (Ou um outro container) em um desses pontos.
Se quisermos adicionar um novo bloco no header.container
ficaria assim:
Repare que não precisamos colocar na mesma estrutura em que o header.container
foi criado (Dentro do container page.wrapper
). Quando estamos utilizando tanto o referenceContainer
, quanto o referenceBlock
, só precisamos colocar dentro do body
que o Magento conseguirá encontrar o elemento que informamos.
Certo, o que mais podemos fazer?
Como foi dito no começo, os blocos e os containers são os principais itens no Layout XML, porém temos outras ações que podemos fazer em nossas customizações:
before/after
O before
e o after
são atributos muito úteis no XML. Com eles podemos informar onde exatamente ficará o nosso bloco/container, se será antes ou depois de determinado elemento, ou até mesmo antes ou depois de todos os elementos.
Vamos rever o nosso primeiro exemplo desse artigo:
Repare que no final da linha 6, estamos utilizando o before="-"
, isso irá indicar que o nosso bloco simple.text.example
será inserido dentro do container content
antes de todos os outros elementos. Sempre que passamos um hífen no before
ou no after
, estamos falando que queremos esse elemento antes ou depois de todos os outros elementos que estão no elemento pai (Nesse caso o content
).
Também podemos informar o nome de um elemento no before/after
. No exemplo acima, estamos criando um novo bloco (Dentro do mesmo elemento que criamos o bloco antes — content
) e informamos que este será inserido depois do bloco simple.text.example
.
move
E se quisermos mudar a posição de um bloco que já existe?
No exemplo acima estamos mudando o posicionamento do bloco de copyright, que originalmente fica dentro do container com nome footer
, para o elemento footer-container
.
Para o move
funcionar precisamos passar, no mínimo, 2 informações. A primeira é o element
, que recebe o nome do elemento que será alterado (Pode ser tanto um bloco como um container) e em seguida precisamos informar o destination
, que é o elemento que receberá o bloco/container.
remove
Podemos também remover blocos/containers de uma página de uma forma bem simples.
Nesse caso estamos removendo o container header.container
numa página, para isso basta usar o referenceContainer
(Ou o referenceBlock
caso seja um bloco), passar o nome do container e usar o remove="true"
.
Conclusão
Essa parte do Magento pode ser bem complexa para quem está começando (E até mesmo para quem já tem experiência com Magento) e é bem extensa também. Esse é o básico sobre Layout XML, ainda conseguimos fazer outras coisas nessa parte do Magento, mas com esse conhecimento já conseguimos fazer a maioria das customizações necessárias.
Vou deixar na parte de referências abaixo alguns links do devdocs (Documentação oficial do Magento 2) para um conhecimento mais aprofundado.
A minha ideia aqui é fazer uma série de artigos, cada um com um tema específico, para que no final se torne um guia de sobrevivência completo. Veja abaixo os artigos já lançados:
- Parte 1 — Temas
- Parte 2 — Layout XML
E aí, ficou alguma dúvida? Espero que tenha ficado claro, caso contrário, sinta-se a vontade em comentar abaixo a sua dúvida. Vou deixar também minhas redes sociais abaixo caso queira me acompanhar ou mandar uma mensagem.