Referencia de Facet

Referencia de Facet

Use esta página cuando la guía de sintaxis principal ya no es suficiente y necesites material de referencia más profundo sobre el comportamiento de Facet, objetos de contexto, contratos de helpers y reglas de renderizado.

Esta página es intencionalmente densa. Es la referencia técnica complementaria a:

What This Page Covers

Usa esta referencia cuando necesites detalles sobre:

  • objetos de contexto y sus propiedades comunes
  • patrones de acceso a page, media y collection
  • contratos de helpers de imagen y mapa
  • filtros por categoría
  • comportamiento del sistema de Variables
  • slots a nivel de layout
  • atributos de datos gestionados
  • referencias de media
  • reglas de renderizado y seguridad

Context Objects

Las plantillas Facet tienen acceso a un conjunto controlado de objetos a nivel raíz. Qué propiedades son útiles depende de la superficie de renderizado actual, pero el mismo modelo mental se aplica en todas partes.

page

page es el objeto de página actual en el contexto de renderizado vigente.

Core Page Properties

Las propiedades escalares comunes incluyen:

  • 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>

Status-style Properties

Las propiedades comunes de tipo booleano incluyen:

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

Ejemplo:

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

page.isEditable es especialmente útil para interfaces que solo deberían aparecer para los editores de la página actual:

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

Relational Properties

Facet suele exponer acceso relacional como:

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

Ejemplos:

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

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

Media Properties

Las propiedades orientadas a media comunes incluyen:

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

Ejemplos:

{{#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}}

Image Object Properties

Las propiedades típicas de un objeto de imagen incluyen:

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

File Object Properties

Las propiedades típicas de un objeto de archivo incluyen:

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

Image Transforms

Los objetos de imagen de page y query soportan transforms encadenados:

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

En bucles:

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

Collection Methods

Los helpers comunes de colección incluyen:

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

Ejemplos:

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

Dynamic Field Access

Los campos personalizados de página pueden ser accedidos por nombre:

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

Usa esto cuando la superficie de renderizado actual realmente dependa de datos a nivel de page. No lo uses para ocultar un contrato débil de campo de Component.

Localized URL

Facet puede exponer helpers de URL localizados para renderizado multilingüe dependiente de la página:

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

user

user representa el contexto del usuario actual.

Las propiedades comunes incluyen:

  • 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 expone helpers orientados a consultas para salidas escalares o agregadas.

Los patrones comunes incluyen:

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

Ejemplos:

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

Usa {{#pages}} cuando necesites un bloque de bucle. Usa los helpers inline pages.* para salidas escalares.

languages / lang

languages y lang exponen el sistema de idiomas.

Las propiedades comunes incluyen:

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

Ejemplo:

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

Dentro de {{#languages}}, cada elemento de idioma comúnmente expone:

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

site

site proporciona valores a nivel de sitio.

Las propiedades comunes incluyen:

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

También puede estar disponible acceso tipo configuración:

{{ 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>

Usa las configuraciones a nivel de site para valores globales estables, no para contenido que debería pertenecer a una Variable o a un objeto gestionado a nivel de página.

now

now proporciona valores de tiempo actuales.

Las propiedades comunes incluyen:

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

Ejemplo:

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

attr

attr expone valores pasados a una Variable:

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

attr debe mantenerse pequeño y explícito. Si un fragmento necesita un modelo de datos editable grande, probablemente deba ser un Component en lugar de una Variable.

loop

loop está disponible dentro de bloques de bucle tales como:

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

Propiedades comunes:

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

Ejemplo:

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

this

Dentro de {{#each}}, this es el elemento actual del bucle:

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

this y un alias nombrado normalmente apuntan al mismo elemento actual.

@index

@index es una abreviatura de loop.index.

Ejemplo:

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

Component Root-Level Fields

En plantillas de Component, los campos de la instancia actual del Component suelen inyectarse como variables a nivel raíz:

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

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

Esta es una de las razones por las que las plantillas de Component parecen más simples que las plantillas genéricas a nivel de página.

No se deben reutilizar nombres reservados casualmente como nombres de campo personalizados si colisionarían con objetos de contexto principales tales como:

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

Component Field Helper Reference

Facet trabaja con varios contratos de helper específicos de Component que no son iguales a la salida general de {{ expr }}.

Single Image Field Helpers

Los campos de image simples comúnmente soportan:

  • {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}

Ejemplo:

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

Multi-image Field Helpers

Dentro de {{#each gallery}}, los ítems de images comúnmente soportan:

  • {{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}}

Ejemplo:

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

Map Field Helpers

Los campos map comúnmente soportan:

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

Ejemplos:

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

Usa map solo para datos de localización estructurados, no para texto plano de direcciones.

Managed Embed Contracts

Los embeds de flujo de trabajo gestionados típicamente usan:

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

Ejemplos:

<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>

Usa ids fijas para flujos de trabajo propiedad de la plantilla y valores basados en campos para flujos seleccionables por el autor.

Filters Reference

Los filtros transforman valores antes de la salida. La regla más importante es simple:

  • usa filtros para formateo
  • no uses filtros para ocultar un modelo de objeto débil

String Filters

Los filtros de cadena comunes incluyen:

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

Ejemplos:

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

Default Value Filter

default suministra un valor de reserva cuando la entrada falta o es similar a null en el contrato soportado:

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

Si el comportamiento exacto de cadena vacía importa, prefiere un ternario explícito.

Number Filters

Los filtros numéricos comunes incluyen:

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

Ejemplos:

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

Date Filters

Los filtros de fecha comunes incluyen:

  • date
  • datetime
  • relative

Ejemplos:

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

URL Filters

Los filtros orientados a URL comunes incluyen:

  • url_encode
  • url

Ejemplos:

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

JSON Filter

Usa json para salida JSON segura:

{{ data | json }}

Esto es útil cuando la plantilla necesita datos estructurados en HTML o salida orientada a script.

Array and Collection Filters

Los filtros de colección comunes incluyen:

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

Ejemplos:

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

Image Filter

Filtro de imagen común:

  • size

Ejemplo:

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

Hash Filter

Filtro de hash común:

  • md5

Ejemplo:

{{ user.email | md5 }}

Variable System

Las Variables son fragmentos de plantilla reutilizables que pueden ser embebidos en cualquier lugar soportado por el renderizado de FaceFlow.

Including Variables

Include básico:

[[my-variable]]

Con atributos:

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

Variable Structure

Una Variable típicamente contiene:

  • plantilla HTML
  • CSS opcional
  • JS opcional
  • atributos opcionales
  • modo de caché

Cache Modes

Los modos comunes incluyen:

  • static
  • dynamic
  • auto

Usa:

  • static cuando la salida es ampliamente amigable para caché
  • dynamic cuando la salida depende del estado runtime sensible al usuario o a la petición
  • auto cuando el motor debe elegir basado en el comportamiento de la Variable

Nested Variables

Las Variables pueden incluir otras Variables:

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

Usa el anidamiento para mejorar la reutilización y la claridad, no para crear cadenas profundas de dependencias ocultas.

Layout-Level Syntax

Las plantillas orientadas a layout a menudo dependen de algunos marcadores estructurales:

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

Ejemplo:

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

Estos marcadores pertenecen a la composición de layout y shell, no al renderizado ordinario de secciones.

Data Attributes

Los atributos de datos orientados al runtime comunes incluyen:

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

Usa estos cuando el contrato de runtime los documente explícitamente. No inventes atributos paralelos casualmente.

Media References

Algunos contextos de renderizado de FaceFlow pueden exponer patrones de referencia de media gestionada como:

  • @image:filename
  • @file:filename

Estas son representaciones del lado de implementación de activos gestionados. En plantillas autoradas, prefiere el helper documentado o las formas de salida de objeto en lugar de depender de referencias crudas de almacenamiento.

Rendering Pipeline

Un orden práctico de renderizado de Facet usualmente se ve así:

  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

La lección de diseño importante es que el shorthand de campos de Component, las expresiones Facet, los embeds de Variable y los marcadores de runtime gestionados están relacionados pero no son etapas idénticas.

Security Model

Facet está diseñado como una capa de plantillas gobernada en lugar de un entorno de ejecución de código sin restricciones.

Reglas clave:

  • no ejecutar código arbitrario del lado del servidor
  • los objetos raíz están controlados
  • filtros y tipos de bloque están en una whitelist
  • el comportamiento de consultas está restringido
  • la salida raw debe usarse intencionalmente

Trata esto como un lenguaje de plantillas en sandbox, no como un motor de scripting de respaldo.

Practical Design Rules

  • prefiere límites de objetos claros sobre lógica de plantilla inteligente
  • mantén la lógica de la plantilla superficial
  • usa Variables para fragmentos y Components para contratos de sección
  • usa Lists cuando la consulta y la paginación formen parte del contrato
  • revisa cualquier sintaxis de helper de campo contra la referencia de campo antes de usarla
  • revisa contenido sensible a caché antes de introducir renderizado diferido

Cookbook Patterns

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

Blog Post List

{{#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}}

Multi-language Switcher

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

Cache-safe User Welcome

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

FAQ

When should I use {{#pages}} vs {{#each}}?

  • usa {{#each}} cuando los datos ya existen en el contexto actual
  • usa {{#pages}} cuando la plantilla debe consultar los datos

What is the difference between {{ }} and {{{ }}}?

  • {{ ... }} es salida escapada
  • {{{ ... }}} es salida raw

Usa salida escapada por defecto.

Can I nest loops?

Sí, pero solo cuando el modelo de objeto siga siendo legible. Si los bucles anidados están compensando un contrato de contenido débil, detente y revisa el diseño.

Why does a field return null or empty output?

Causas comunes:

  • contexto incorrecto
  • nombre de campo incorrecto
  • usar la familia de sintaxis equivocada para el objeto actual
  • esperar un helper en un campo que no lo soporta

How should I debug template problems?

Empieza en este orden:

  1. confirma el contrato del objeto propietario
  2. confirma la familia de sintaxis correcta
  3. confirma los objetos de contexto disponibles
  4. reduce la plantilla al fragmento reproducible más pequeño
  5. luego reconstruye desde ahí