Referência do Facet

Referência do Facet

Use esta página quando o guia de sintaxe primário não for mais suficiente e você precisar de material de referência mais aprofundado sobre o comportamento do Facet, objetos de contexto, contratos de helpers e regras de renderização.

Esta página é propositalmente densa. É o companheiro de referência técnica para:

O que esta página cobre

Use esta referência quando precisar de detalhes sobre:

  • objetos de contexto e suas propriedades comuns
  • padrões de acesso a página, mídia e coleções
  • contratos de helpers de imagem e mapa
  • filtros por categoria
  • comportamento do sistema de Variáveis
  • slots em nível de layout
  • atributos de dados gerenciados
  • referências de mídia
  • regras de renderização e segurança

Objetos de contexto

Templates do Facet têm acesso a um conjunto controlado de objetos de nível raiz. Quais propriedades são úteis depende da superfície de render atual, mas o mesmo modelo mental se aplica em todo lugar.

page

page é o objeto de página atual no contexto de renderização atual.

Propriedades principais da página

Propriedades escalares comuns incluem:

  • page.id
  • page.name
  • page.title
  • page.url
  • page.httpUrl
  • page.path
  • page.template
  • page.created
  • page.modified
  • page.createdStr
  • page.modifiedStr
  • page.status
  • page.sort
  • page.numChildren

Uso típico:

<h1>{{ page.title }}</h1>
<p>Updated {{ page.modified | date("F j, Y") }}</p>

Propriedades do tipo status

Propriedades booleanas comuns incluem:

  • page.isPublished
  • page.isHidden
  • page.isUnpublished
  • page.isTrash
  • page.isNew
  • page.hasChildren
  • page.isEditable

Exemplo:

{{#if page.hasChildren}}
  <p>This page has child pages.</p>
{{/if}}

page.isEditable é especialmente útil para interfaces que devem aparecer apenas para os editores da página atual:

{{#if page.isEditable}}
  <a href="{{ page.url }}?edit=1">Edit this page</a>
{{/if}}

Propriedades relacionais

Facet normalmente expõe acesso relacional como:

  • page.parent
  • page.parents
  • page.rootParent
  • page.children
  • page.siblings
  • page.next
  • page.prev
  • page.find

Exemplos:

{{ page.parent.title }}
{{ page.rootParent.title }}

{{#each page.children as="child"}}
  <a href="{{ child.url }}">{{ child.title }}</a>
{{/each}}

Propriedades de mídia

Propriedades orientadas a mídia comuns incluem:

  • page.images
  • page.image
  • page.files

Exemplos:

{{#each page.images as="img"}}
  <img src="{{ img.width(800).webp.url }}" alt="{{ img.description }}">
{{/each}}

{{#each page.files as="file"}}
  <a href="{{ file.url }}">{{ file.filename }}</a>
{{/each}}

Propriedades de objeto de imagem

Propriedades típicas de um objeto de imagem incluem:

  • img.url
  • img.httpUrl
  • img.filename
  • img.description
  • img.width
  • img.height
  • img.ext
  • img.filesize
  • img.webp.url
  • img.raw.url

Propriedades de objeto de arquivo

Propriedades típicas de um objeto de arquivo incluem:

  • file.url
  • file.httpUrl
  • file.filename
  • file.description
  • file.ext
  • file.filesize

Transformações de imagem

Objetos de imagem de página e de consulta suportam transforms encadeados:

{{ page.image.width(800) }}
{{ page.image.size(600, 400) }}
{{ page.image.size(600, 400).webp.url }}
{{ page.image.raw.url }}

Em loops:

{{#each page.images as="img"}}
  <img src="{{ img.size(400, 300).webp.url }}" alt="{{ img.description }}">
{{/each}}

Métodos de coleção

Helpers comuns de coleção incluem:

  • first
  • last
  • count
  • eq(n)
  • slice(start, length)

Exemplos:

{{ page.images.first.url }}
{{ page.images.count }}
{{ page.images.eq(2).url }}

Acesso dinâmico a campos

Campos personalizados da página podem ser acessados por nome:

{{ page.summary }}
{{ page.body }}
{{ page.headline }}
{{ page.field name="my_custom_field" }}

Use isto quando a superfície de render atual realmente depende de dados em nível de página. Não use isso para ocultar um contrato fraco de campo de Component.

URL localizado

Facet pode expor helpers de URL localizados para renderização multilíngue sensível à página:

{{ page.localUrl lang="fr" }}
{{ page.localUrl lang="default" }}

user

user representa o contexto do usuário atual.

Propriedades comuns incluem:

  • user.id
  • user.name
  • user.title
  • user.email
  • user.displayName
  • user.isLoggedin
  • user.isGuest
  • user.isSuperuser
  • user.language

Uso típico:

{{#if user.isLoggedin}}
  <span>Hello, {{ user.displayName }}!</span>
{{else}}
  <a href="/login/">Log In</a>
{{/if}}

pages

pages expõe helpers orientados a consulta para saídas escalares ou agregadas.

Padrões comuns incluem:

  • pages.count selector="..."
  • pages.first selector="..."
  • pages.last selector="..."
  • pages.titles selector="..." sep=", "
  • pages.json selector="..."

Exemplos:

<p>Total posts: {{ pages.count selector="template=blog-post" }}</p>
<p>Categories: {{ pages.titles selector="template=category" sep=", " }}</p>

Use {{#pages}} quando precisar de um bloco de loop. Use helpers inline pages.* para saídas escalares.

languages / lang

languages e lang expõem o sistema de idiomas.

Propriedades comuns incluem:

  • languages.count
  • languages.current
  • languages.default
  • languages.isMultiLanguage
  • languages.all
  • languages.{name}

Exemplo:

{{#if languages.isMultiLanguage}}
  Current language: {{ languages.current.title }}
{{/if}}

Dentro de {{#languages}}, cada item de idioma normalmente expõe:

  • lang.id
  • lang.name
  • lang.title
  • lang.isDefault
  • lang.isCurrent
  • lang.url
  • lang.httpUrl
  • lang.locale

site

site fornece valores em nível de site.

Propriedades comuns incluem:

  • site.name
  • site.url
  • site.httpUrl
  • site.httpHost
  • site.locale
  • site.year
  • site.assets
  • site.templates
  • site.adminUrl
  • site.adminProfileUrl
  • site.adminLogoutUrl

Acesso no estilo de configurações também pode estar disponível:

{{ site.setting key="company_name" }}
{{ site.setting key="phone" }}
<a href="{{ site.adminUrl }}">Dashboard</a>
<a href="{{ site.adminProfileUrl }}">Profile</a>
<a href="{{ site.adminLogoutUrl }}">Log out</a>

Use configurações em nível de site para valores globais estáveis, não para conteúdo que deveria pertencer a uma Variable ou a um objeto gerenciado em nível de página.

now

now fornece valores de tempo atuais.

Propriedades comuns incluem:

  • now.timestamp
  • now.date
  • now.datetime
  • now.year
  • now.month
  • now.day

Exemplo:

<footer>&copy; {{ now.year }} {{ site.name }}</footer>

attr

attr expõe valores passados para uma Variable:

{{! Usage: [[my-widget title="Hello" color="blue"]] }}
<div style="color: {{ attr.color | default("black") }}">
  <h3>{{ attr.title | default("Default Title") }}</h3>
</div>

attr deve permanecer pequeno e explícito. Se um fragmento precisa de um grande modelo de dados editável, provavelmente ele quer um Component em vez de uma Variable.

loop

loop está disponível dentro de blocos de loop como:

  • {{#each}}
  • {{#pages}}
  • {{#languages}}

Propriedades comuns:

  • loop.index
  • loop.index1
  • loop.first
  • loop.last
  • loop.length
  • loop.even
  • loop.odd

Exemplo:

{{#each page.children as="child"}}
  <div class="{{#if loop.odd}}row-alt{{/if}}">
    {{ loop.index1 }}. {{ child.title }}
  </div>
{{/each}}

this

Dentro de {{#each}}, this é o item atual do loop:

{{#each page.children}}
  <a href="{{ this.url }}">{{ this.title }}</a>
{{/each}}

this e um alias nomeado normalmente apontam para o mesmo item atual.

@index

@index é atalho para loop.index.

Exemplo:

{{#each page.children as="child"}}
  {{#if @index == 0}}
    <h2>{{ child.title }}</h2>
  {{else}}
    <p>{{ child.title }}</p>
  {{/if}}
{{/each}}

Campos do componente no nível raiz

Em templates de Component, os campos da instância do Component atual frequentemente são injetados como variáveis de nível raiz:

<h1>{{ title }}</h1>

{{#if showGallery}}
  <div class="gallery">
    {{#each images as="img"}}
      <img src="{{ img.url }}">
    {{/each}}
  </div>
{{/if}}

Esta é uma das razões pelas quais templates de Component parecem mais simples que templates genéricos em nível de página.

Nomes reservados não devem ser reutilizados casualmente como nomes de campo personalizados se eles colidirem com objetos de contexto principais tais como:

  • page
  • pages
  • user
  • languages
  • lang
  • site
  • now
  • attr
  • loop
  • this
  • @index

Referência de helpers de campo de Component

Facet funciona com vários contratos de helper específicos de Component que não são os mesmos que a saída geral {{ expr }}.

Helpers de campo de imagem única

Campos image únicos comumente suportam:

  • {field}
  • {field.raw}
  • {field.webp}
  • {field.name}
  • {field.description}
  • {field.width(N)}
  • {field.width(N).webp}
  • {field.height(N)}
  • {field.height(N).webp}
  • {field.size(W,H)}
  • {field.size(W,H).webp}

Exemplo:

<img src="{hero.width(1200).webp}" alt="{hero.description}">
<a href="{photo.raw}" download>Download original</a>

Helpers de campo de múltiplas imagens

Dentro de {{#each gallery}}, itens images comumente suportam:

  • {{this}}
  • {{this.raw}}
  • {{this.webp}}
  • {{this.name}}
  • {{this.description}}
  • {{this.width(N)}}
  • {{this.width(N).webp}}
  • {{this.height(N)}}
  • {{this.height(N).webp}}
  • {{this.size(W,H)}}
  • {{this.size(W,H).webp}}

Exemplo:

{{#each gallery}}
  <figure>
    <img src="{{this.width(600).webp}}" alt="{{this.description}}">
    <figcaption>{{this.name}}</figcaption>
  </figure>
{{/each}}

Helpers de campo de mapa

Campos map comumente suportam:

  • {field}
  • {field.width(N)}
  • {field.height(N)}
  • {field.size(W,H)}

Exemplos:

{officeLocation}
{officeLocation.width(600)}
{officeLocation.size(800,500)}

Use map apenas para dados estruturados de localização, não para cópia de endereço simples.

Contratos de embed gerenciados

Embeds em fluxo de trabalho gerenciado tipicamente usam:

  • data-form-embed
  • data-review-embed

Exemplos:

<div data-form-embed="enterprise-demo-request"></div>
<div data-review-embed="customer-success-reviews"></div>

<div data-form-embed="{contactForm}"></div>
<div data-review-embed="{serviceReview}"></div>

Use ids fixos para fluxos de trabalho possuídos por template e valores baseados em campo para fluxos de trabalho selecionáveis pelo autor.

Referência de filtros

Filtros transformam valores antes da saída. A regra mais importante é simples:

  • use filtros para formatação
  • não use filtros para ocultar um modelo de objeto fraco

Filtros de string

Filtros de string comuns incluem:

  • escape / e
  • raw
  • upper
  • lower
  • capitalize
  • trim
  • truncate
  • nl2br
  • striptags
  • replace
  • split
  • slice
  • pad
  • wrap
  • slug

Exemplos:

{{ page.title | upper }}
{{ page.body | striptags | truncate(200, "...") }}
{{ text | nl2br }}
{{ title | slug }}

Filtro de valor padrão

default fornece um fallback quando a entrada está ausente ou é nula na contract suportada:

{{ page.subtitle | default("Untitled") }}

Se o comportamento exato de string vazia for importante, prefira um ternário explícito.

Filtros numéricos

Filtros numéricos comuns incluem:

  • number
  • currency
  • abs
  • round
  • ceil
  • floor

Exemplos:

{{ 1234567 | number(0, ".", ",") }}
{{ price | currency("$", 2) }}
{{ ratio | round(2) }}

Filtros de data

Filtros de data comuns incluem:

  • date
  • datetime
  • relative

Exemplos:

{{ page.created | date("F j, Y") }}
{{ page.modified | datetime("Y-m-d H:i") }}
{{ page.modified | relative }}

Filtros de URL

Filtros orientados a URL comuns incluem:

  • url_encode
  • url

Exemplos:

{{ page.title | url_encode }}
{{ website | url }}

Filtro JSON

Use json para saída JSON segura:

{{ data | json }}

Isto é útil quando o template precisa de dados estruturados em HTML ou saída orientada a script.

Filtros de array e coleção

Filtros de coleção comuns incluem:

  • join
  • first
  • last
  • count
  • length
  • reverse
  • sort
  • pluck
  • unique
  • batch
  • keys
  • values
  • merge

Exemplos:

{{ tags | pluck("title") | join(", ") }}
{{ page.children | count }}
{{ items | batch(4) }}

Filtro de imagem

Filtro de imagem comum:

  • size

Exemplo:

{{ page.image | size(600, 400) }}

Filtro de hash

Filtro de hash comum:

  • md5

Exemplo:

{{ user.email | md5 }}

Sistema de Variáveis

Variables são fragmentos de template reutilizáveis que podem ser incorporados em qualquer lugar suportado pela renderização FaceFlow.

Inclusão de Variables

Inclusão básica:

[[my-variable]]

Com atributos:

[[my-widget title="Hello World" color="blue" count="5"]]

Estrutura de uma Variable

Uma Variable tipicamente contém:

  • template HTML
  • CSS opcional
  • JS opcional
  • atributos opcionais
  • modo de cache

Modos de cache

Modos comuns incluem:

  • static
  • dynamic
  • auto

Use:

  • static quando a saída for amplamente compatível com cache
  • dynamic quando a saída depender de estado em tempo de execução sensível ao usuário ou à requisição
  • auto quando o mecanismo deve escolher com base no comportamento da Variable

Variables aninhadas

Variables podem incluir outras Variables:

<footer>
  [[copyright-notice year="2026"]]
  [[social-links]]
</footer>

Use aninhamento para melhorar a reutilização e clareza, não para criar cadeias profundas de dependências ocultas.

Sintaxe de nível de layout

Templates orientados a layout frequentemente dependem de alguns placeholders estruturais:

  • {content}
  • {header}
  • {footer}
  • {siteComponents}

Exemplo:

<body>
  {header}
  {siteComponents}
  <main>
    {content}
  </main>
  {footer}
</body>

Esses placeholders pertencem à composição de layout e shell, não à renderização de seções ordinárias.

Atributos de dados

Atributos de dados orientados a runtime comuns incluem:

  • data-form-embed
  • data-review-embed
  • data-fb-map
  • data-fb-map-field
  • data-component-*
  • data-form-ajax
  • data-variable
  • data-loading

Use estes quando o contrato de runtime os documentar explicitamente. Não invente atributos paralelos casualmente.

Referências de mídia

Alguns contextos de renderização FaceFlow podem expor padrões de referência de mídia gerenciada tais como:

  • @image:filename
  • @file:filename

Estas são representações do lado de implementação de ativos gerenciados. Em templates autorais, prefira o helper documentado ou as formas de saída de objeto em vez de confiar em referências brutas de armazenamento.

Pipeline de renderização

Uma ordem prática de renderização do Facet geralmente se parece com isto:

  1. load the owning FaceFlow object
  2. resolve the current render context
  3. inject root-level fields and context objects
  4. evaluate field helper contracts
  5. evaluate Facet expressions and block helpers
  6. resolve Variable embeds
  7. resolve managed runtime markers such as Forms, Reviews, or maps
  8. return final output

A lição de design importante é que o atalho de campo de Component, expressões Facet, embeds de Variable e marcadores de runtime gerenciados são estágios relacionados, mas não idênticos.

Modelo de segurança

Facet é projetado como uma camada de templates governada em vez de um ambiente de execução de código bruto no servidor.

Regras chave:

  • sem execução arbitrária de código do lado servidor
  • objetos raiz são controlados
  • filtros e tipos de bloco são permitidos por whitelist
  • comportamento de consulta é restrito
  • saída raw deve ser usada intencionalmente

Trate isto como uma linguagem de template sandboxed, não como um mecanismo de script de fallback.

Regras práticas de design

  • prefira limites claros de objeto em vez de lógica esperta no template
  • mantenha a lógica do template rasa
  • use Variables para fragmentos e Components para contratos de seção
  • use Lists quando consulta e paginação fizerem parte do contrato
  • revise qualquer sintaxe de helper de campo contra a referência de campo antes de usá-la
  • revise conteúdo sensível ao cache antes de introduzir renderização adiada

Padrões (Cookbook)

<nav>
  <ul>
    {{#pages selector="parent=1, sort=sort" as="item"}}
      <li><a href="{{ item.url }}">{{ item.title }}</a></li>
    {{/pages}}
  </ul>
</nav>

Lista de posts do blog

{{#pages selector="template=blog-post, sort=-created, limit=6" as="post"}}
  <article>
    <h2><a href="{{ post.url }}">{{ post.title }}</a></h2>
    <p>{{ post.body | striptags | truncate(250) }}</p>
  </article>
{{else}}
  <p>No blog posts yet.</p>
{{/pages}}

Alternador multilíngue

{{#if languages.isMultiLanguage}}
  {{#languages as="lang"}}
    <a href="{{ lang.url }}">{{ lang.title }}</a>
  {{/languages}}
{{/if}}

Trilha de navegação (Breadcrumbs)

{{#each page.parents as="p"}}
  <a href="{{ p.url }}">{{ p.title }}</a> /
{{/each}}
<span>{{ page.title }}</span>

Saudação ao usuário segura para cache

{{#deferred skeleton-width="10rem" skeleton-height="2rem"}}
  {{#if user.isLoggedin}}
    <span>{{ user.displayName }}</span>
  {{else}}
    <a href="/login/">Sign In</a>
  {{/if}}
{{/deferred}}

Perguntas frequentes

Quando devo usar {{#pages}} vs {{#each}}?

  • use {{#each}} quando os dados já existirem no contexto atual
  • use {{#pages}} quando o template deve consultar os dados

Qual a diferença entre {{ }} e {{{ }}}?

  • {{ ... }} é saída escapada
  • {{{ ... }}} é saída raw

Use saída escapada por padrão.

Posso aninhar loops?

Sim, mas apenas quando o modelo de objeto permanecer legível. Se loops aninhados estiverem compensando um contrato de conteúdo fraco, pare e revise o design.

Por que um campo retorna null ou saída vazia?

Causas comuns:

  • contexto errado
  • nome de campo incorreto
  • usando a família de sintaxe errada para o objeto atual
  • esperando um helper em um campo que não o suporta

Como devo depurar problemas de template?

Comece nesta ordem:

  1. confirm the owning object contract
  2. confirm the right syntax family
  3. confirm the available context objects
  4. reduce the template to the smallest reproducible fragment
  5. then rebuild from there

Relacionado