Feito com Chinaski

Referência de Templates

Um tema Chinaski é um diretório plano de templates Template Toolkit 2 (.tt). O processo de build renderiza seus templates em HTML estático para cada página e post, uma vez por idioma configurado. Esta página cobre os arquivos do tema, as variáveis que recebem, e os helpers e as regras que os acompanham.

Onde os temas vivem

  • O tema padrão embutido vem com a aplicação e serve como fallback.
  • Temas personalizados vivem em builder/themes/<slug-do-seu-tema>/. Quando um tema com o slug do tema ativo existe lá, o builder o usa; caso contrário, faz fallback para os templates embutidos.
  • Qual tema está ativo é escolhido em Settings.

Arquivos de template obrigatórios e opcionais

Arquivo Propósito Obrigatório?
page.tt Template padrão para cada página publicada Sim
post.tt Template para cada post de blog publicado Sim
blog_index.tt Listagem paginada do blog e páginas de categoria Sim
404.tt Página 404 por idioma Sim
_head.tt Partial de <head>: CSS, meta tags, importações de fonte Convenção
_header.tt Header do site: logo, navegação, tagline Convenção
_footer.tt Rodapé do site: copyright, navegação secundária Convenção
_cookie_notice.tt Banner GDPR opcional Não
_sidebar.tt Partial de barra lateral opcional Não
search.tt Página de resultados de busca opcional Não
_password_gate.tt UI de portão de senha no lado do cliente para páginas protegidas Obrigatório se page.tt/post.tt suportam password_hash
<custom>.tt Qualquer página que o selecione via a configuração template Não

Arquivos que começam com _ são partials e nunca são renderizados como páginas independentes.

Variáveis de template

Os templates recebem um conjunto plano de variáveis: não há objetos page. ou site.. Use site_name, title, lang e assim por diante diretamente.

page.tt e 404.tt

Variável Tipo Notas
title string Título da página
body string HTML Pré-renderizado: não escape com | html
slug string Slug da URL
lang / language string Código de 2 letras, por exemplo en
meta_title string? Sobrescreve o <title>
meta_description string? Descrição SEO
og_title string? Título OpenGraph
og_description string? Descrição OG
og_image_url string? Imagem OG
canonical_url string Gerada automaticamente
featured_image_url string? Imagem hero
featured_image_alt string? Texto alt
updated_at string datetime do SQLite
site_name string Das configurações
site_tagline string Das configurações
footer_copyright string Das configurações
year inteiro Ano do build
url_base string Prefixo de URL: pode ser vazio; acrescente-o como prefixo a TODOS os links internos
cookie_notice_active 0/1 Se deve renderizar _cookie_notice.tt
noindex 0/1 Emite <meta name="robots" content="noindex">
nav_items array {label, url, slot, sort_order}: slot é header ou footer
hreflang_links array {hreflang, href} para traduções
breadcrumbs array {name, url, is_current}
json_ld string HTML JSON-LD pré-serializado: emita cru
ga4_id string? ID do Google Analytics
gtm_id string? ID de contêiner do GTM
twitter_site string? Handle do Twitter com @
password_hash string? Se definido, você DEVE envolver o conteúdo em _password_gate.tt (veja abaixo)

post.tt: tudo de page.tt, mais

Variável Tipo Notas
excerpt string Excerto fornecido pelo autor; pode estar vazio
category string? Nome de categoria única
tags string Separado por vírgulas; divida com tags.split(',')
author string Nome de exibição
is_sticky 0/1 Fixado no topo do índice do blog
published_at string? datetime do SQLite; momento da primeira publicação
date string Fatia YYYY-MM-DD de published_at
feed_url string URL absoluta do feed RSS
og_type string Sempre 'article'

blog_index.tt

Variável Tipo Notas
posts array Hashes de post ordenados com as chaves p.title, p.slug, p.date, p.body, p.category
pagination hash? {current_page, total_pages, prev_url, next_url, abs_prev_url, abs_next_url}: undef quando há apenas uma página
title string “Blog” localizado ou nome da categoria
category_name string? Definido ao filtrar por categoria

search.tt

Variável Tipo Notas
query string Termo de busca
results array {title, url, excerpt}
result_count inteiro Total de correspondências

Blocos

Autores colocam blocos escrevendo {{block:my-cta}} em um corpo de página ou post. Em tempo de build, o builder encontra o shortcode, busca o bloco publicado com aquele nome e idioma, o renderiza com seu template, e substitui o HTML renderizado no corpo.

Os templates de bloco são compartilhados entre temas e vivem fora do diretório do seu tema; seu tema é responsável pelo CSS que estiliza sua saída.

Classes CSS que seu tema deve estilizar

Cada tipo de bloco emite uma classe wrapper previsível e classes internas. Seu _head.tt deve estilizar estas:

Tipo Wrapper Classes internas
cta .cta-block .cta-inner .cta-heading .cta-subheading .cta-button
image .image-block .image-caption
quote .quote-block .quote-text .quote-attribution
hero .hero-block .hero-media .hero-inner .hero-heading .hero-subheading .hero-button
testimonial .testimonial-block .testimonial-label .testimonial-body .testimonial-avatar .testimonial-text .testimonial-attribution
stat .stat-block .stat-number .stat-label
promo .promo-block .promo-media .promo-content .promo-heading .promo-body .promo-button
embed .embed-block .embed-caption .embed-content
video .video-block .video-heading .video-wrapper .video-caption
form .form-block .form-heading .form-subheading .block-form .block-form__field
newsletter .newsletter-block .newsletter-inner .newsletter-heading .newsletter-subheading .newsletter-form .newsletter-form__row
accordion .accordion-block .accordion-heading .accordion .accordion__item .accordion__summary .accordion__body
table .table-block .table-heading .table-wrapper .block-table
columns .columns-block .columns-heading .columns .columns--2 .columns--3 .columns--4 .column .column__image .column__heading .column__body
gallery .gallery-block .gallery-heading .gallery .gallery__item

Estilo mínimo requerido para as classes utilitárias:

  • .video-wrapper: position: relative; padding-bottom: 56.25%; com o iframe position: absolute; inset: 0; width: 100%; height: 100%; (vídeo responsivo 16:9)
  • .columns--2 / .columns--3 / .columns--4: display: grid com grid-template-columns apropriadas
  • .table-wrapper: overflow-x: auto para que tabelas rolem no mobile
  • .gallery: grade responsiva com gap
  • .accordion__item / .accordion__summary: reset básico de details/summary

Páginas multilíngues

  • Cada página é renderizada uma vez por idioma configurado.
  • Links internos devem incluir o prefixo de idioma: use [% url_base %]/[% lang %]/contact/ ou similar. A única exceção é nav_items[].url, que já contém a URL completa correta: use-as como estão.
  • O elemento <html> deve carregar o idioma: <html lang="[% lang | html %]">.

Regras de segurança

As seguintes diretivas são proibidas em conteúdo de tema e bloco e são rejeitadas:

  • [% PERL %] / [% RAWPERL %]
  • [% INSERT '/caminho/absoluto' %]
  • [% USE: .. %] de módulos como File/IO/Socket/Net/LWP/WWW/HTTP/System/Cmd/Process/Pipe/Expect

Páginas protegidas por senha

A proteção por senha é um portão voltado ao leitor: o conteúdo da página ainda está presente no HTML publicado, e _password_gate.tt o esconde atrás de uma checagem em JavaScript até o visitante digitar a senha correta. page.tt e post.tt devem implementá-lo assim:

[% IF password_hash %]
[% WRAPPER '_password_gate.tt' %][% PROCESS page_content %][% END %]
[% ELSE %]
[% PROCESS page_content %]
[% END %]

(Envolva o bloco que contém seu conteúdo principal; o nome exato do bloco não importa, apenas que esteja definido e processado dentro do wrapper.) Se o seu template omite o ramo password_hash inteiramente, um administrador ainda pode definir uma senha em uma página usando seu tema, e a página será renderizada publicamente sem nenhum aviso de que o portão está ausente.

Resumo rápido

  • [% variable %]: saída crua
  • [% variable | html %]: escapada para HTML (use para TODO texto controlado por usuário)
  • [% variable | uri %]: codificação URI (para segmentos de caminho de URL)
  • [% IF / ELSE / END %], [% UNLESS: .. %]: condicionais
  • [% FOREACH item IN items %]: loops; loop.index / loop.count disponíveis
  • [% INCLUDE '_partial.tt' %]: inclui um partial, compartilhando as variáveis atuais; adicione x = 42 para passar ou sombrear valores
  • [% PROCESS '_macros.tt' %]: como INCLUDE mas sem introduzir um novo escopo
  • [%-: .. -%]: apara os espaços em branco ao redor

Principais pegadinhas

  1. Stash plano: sem objetos aninhados. site.title, page.title, post.title todos estão errados; use site_name e title.
  2. Campos de item de navegação são label, url, slot, e não name, href, active.
  3. Datas: nunca chame formatação de data em published_at; use a variável pré-computada date, ou tome os primeiros 10 caracteres de published_at.
  4. O body é HTML pré-renderizado: emita [% body %] sem escapar.
  5. Partials têm o prefixo _.
  6. Todos os links internos precisam de url_base e lang.
Leia este site em