# Plantillas HTML

Las plantillas HTML usan una sintaxis sin lógica de estilo Mustache con marcadores de posición `{{variable}}`. Se renderizan en el cliente dentro de la aplicación POS, lo que significa que **funcionan sin conexión**: no se necesita conexión con el servidor para mostrar o imprimir un recibo.

Este es el motor recomendado para la mayoría de los usuarios.

## Sintaxis[​](#syntax "Enlace directo a Sintaxis")

### Variables[​](#variables "Enlace directo a Variables")

Inserte datos usando llaves dobles:

```
<h1>{{store.name}}</h1>

<p>Order #{{order.number}}</p>

<p>Total: {{totals.total_display}}</p>
```

Use variantes `_display` para valores de moneda ya formateados (p. ej., `$12.50` en lugar de `12.5`). Consulte la [referencia de datos de recibos](/es/receipts/receipt-data.md) para ver todos los campos disponibles.

### Secciones (bucles y condicionales)[​](#sections-loops-and-conditionals "Enlace directo a Secciones (bucles y condicionales)")

Use `{{#section}}...{{/section}}` para recorrer matrices o mostrar contenido de forma condicional:

```
{{#lines}}

<div class="line-item">

  <span>{{name}} × {{qty}}</span>

  <span>{{line_total_display}}</span>

</div>

{{/lines}}
```

### Secciones invertidas[​](#inverted-sections "Enlace directo a Secciones invertidas")

Utilice `{{^section}}...{{/section}}` para mostrar contenido cuando un valor esté vacío o sea falso:

```
{{#customer.id}}

  <p>Customer: {{customer.name}}</p>

{{/customer.id}}

{{^customer.id}}

  <p>Guest checkout</p>

{{/customer.id}}
```

### Etiquetas localizadas[​](#localised-labels "Enlace directo a Etiquetas localizadas")

Utilice `{{i18n.key}}` para las etiquetas traducibles que se adaptan al idioma de la tienda:

```
<th>{{i18n.subtotal}}</th>

<td>{{totals.subtotal_display}}</td>
```

## Patrones comunes[​](#common-patterns "Enlace directo a Patrones comunes")

### Encabezado de la tienda[​](#store-header "Enlace directo a Encabezado de la tienda")

El array `store.address_lines` está preformateado para recibos; recórralo en lugar de unir campos de dirección individuales.

```
<div style="text-align: center;">

  {{#store.logo}}<img src="{{store.logo}}" alt="{{store.name}}" style="max-width: 200px;" />{{/store.logo}}

  <h1 style="margin: 8px 0;">{{store.name}}</h1>

  {{#store.address_lines}}<div>{{.}}</div>{{/store.address_lines}}

  {{#store.phone}}<div>{{store.phone}}</div>{{/store.phone}}

  {{#store.tax_ids}}<div>{{#label}}{{label}} {{/label}}{{value}}</div>{{/store.tax_ids}}

</div>
```

### Partidas con descuentos[​](#line-items-with-discounts "Enlace directo a Partidas con descuentos")

El campo `discounts` de una partida es el importe del descuento como número positivo, o `0` cuando no hay descuento. Mustache trata `0` como falso, por lo que `{{#discounts}}...{{/discounts}}` es la condición de protección adecuada.

```
{{#lines}}

<div class="line-item" style="display: flex; justify-content: space-between;">

  <div>

    <div>{{name}} × {{qty}}</div>

    {{#discounts}}

      <div style="font-size: 0.9em; color: #6b7280;">

        <s>{{unit_subtotal_display}}</s> {{unit_price_display}}

      </div>

    {{/discounts}}

  </div>

  <div>{{line_total_display}}</div>

</div>

{{/lines}}
```

### Resumen de impuestos[​](#tax-summary "Enlace directo a Resumen de impuestos")

```
{{#tax_summary}}

<div class="tax-line">

  <span>{{label}} ({{rate}}%)</span>

  <span>{{tax_amount_display}}</span>

</div>

{{/tax_summary}}
```

### Datos de pago[​](#payment-details "Enlace directo a Datos de pago")

```
{{#payments}}

<div class="payment" style="display: flex; justify-content: space-between;">

  <span>{{method_title}}</span>

  <span>{{amount_display}}</span>

</div>

{{#tendered}}

  <div style="display: flex; justify-content: space-between;">

    <span>{{i18n.tendered}}</span><span>{{tendered_display}}</span>

  </div>

  <div style="display: flex; justify-content: space-between;">

    <span>{{i18n.change}}</span><span>{{change_display}}</span>

  </div>

{{/tendered}}

{{/payments}}
```

### Códigos de barras y códigos QR[​](#barcodes-and-qr-codes "Enlace directo a Códigos de barras y códigos QR")

Utilice el `<barcode>` elemento — la misma sintaxis que [plantillas térmicas](/es/receipts/thermal-templates.md). El valor va dentro del elemento; la simbología se establece en el `type` atributo. El renderizador sustituye cada elemento por un SVG en línea.

```
<!-- Code 128 barcode of the order number -->

<barcode type="code128" height="40">{{order.number}}</barcode>



<!-- QR code -->

<barcode type="qrcode" scale="3">{{order.payment_url}}</barcode>



<!-- EAN-13 -->

<barcode type="ean13">{{order.number}}</barcode>
```

El atributo `type` debe establecerse **literalmente** en la plantilla; no puede provenir de un marcador de posición. Un `type` de `qr` o `qrcode` se renderiza como código QR tanto en plantillas HTML como térmicas.

Si el tipo de código de barras seleccionado no puede codificar el valor (por ejemplo, datos EAN-13 no numéricos o con una longitud incorrecta), la vista previa muestra un bloque `Barcode error` o `QR code error` con el valor original, para que pueda corregir el valor o cambiar a un tipo compatible.

Se admiten todas las [simbologías de bwip-js](https://github.com/metafloor/bwip-js/wiki/Supported-Barcode-Types): `code128`, `qrcode`, `ean13`, `ean8`, `upca`, `pdf417`, `datamatrix` y muchas más.

## Estilo[​](#styling "Enlace directo a Estilo")

Las plantillas sin lógica se sanean mediante la función de WordPress `wp_kses_post` antes del renderizado, lo que **elimina `<style>`, `<head>`, y etiquetas de nivel de documento**. Utilice **estilos en línea** en cada elemento:

```
<div style="font-family: monospace; font-size: 12px; max-width: 300px; margin: 0 auto;">

  <div style="text-align: center; margin-bottom: 16px;">

    <strong style="font-size: 16px;">{{store.name}}</strong>

  </div>

  <div style="display: flex; justify-content: space-between; font-weight: 700; border-top: 1px solid black; padding-top: 8px;">

    <span>{{i18n.total}}</span>

    <span>{{totals.total_display}}</span>

  </div>

</div>
```

La misma restricción se aplica a `<script>`, `<link>`, y otras etiquetas que no son de contenido: se eliminan, por lo que no se debe depender de CSS o JavaScript externos.

Diseñado para blanco y negro

Los recibos suelen imprimirse en impresoras térmicas o láser en blanco y negro. Diseñe con esto en mente: use **grosor de fuente, espacios en blanco, contraste tipográfico y líneas horizontales** para la jerarquía en lugar de rellenos de color. Los fondos de color y el texto gris desaparecen en la impresión en blanco y negro o se imprimen como medios tonos poco definidos.

¿Necesita un aspecto de papel térmico sin una impresora térmica?

Haga clic en **Usar plantilla** en la tarjeta **Recibo estrecho** de la galería: es un diseño monoespaciado de 72mm de ancho que se imprime correctamente mediante la impresión del navegador, en impresoras térmicas compatibles con HTML (dispositivos Sunmi/Imin WebView) y en papel estándar. No es para impresoras térmicas ESC/POS sin procesar; use las plantillas XML de **Recibo térmico simple** para esas impresoras.

## Buenas prácticas[​](#best-practices "Enlace directo a Buenas prácticas")

* **Use los campos `_display`** para todos los valores de moneda; gestionan automáticamente el formato según la configuración regional
* **Use etiquetas `{{i18n.*}}`** en lugar de codificar texto de forma fija, para que las plantillas funcionen en varios idiomas
* **Utilice secciones para condicionales** — envuelva los campos opcionales en `{{#field}}...{{/field}}` para que se oculten cuando estén vacíos
* **Comience con una plantilla de galería** en lugar de crearla desde cero
* **Pruebe con la vista previa** en el editor de plantillas antes de activarla
