--- title: "Campos editables del builder" tags: [builder, twig, html, modules] load_priority: 80 load_when: [always] summary: "Atributos data-field-* (textfield, headfield, link, upload, list, multiv2, checkbox), agrupar campos en pestañas con data-field-group, c-if/c-for/c-class, c-form, componentes built-in del builder Acai." --- # Builder Fields — Campos editables del index-base.tpl Este documento define los campos editables que el usuario rellena desde el panel del builder de Acai. Cubre el atributo `data-field-type` con todos sus tipos (`textfield`, `headfield`, `textbox`, `wysiwyg`, `link`, `upload`, `uploadMulti`, `list`, `multiv2`, `checkbox`, `colorpicker`), la regla `data-field-label` → nombre de variable, los atributos Acai (`c-if`, `c-else`, `c-for`, `c-class`, `c-hidden`, `c-required`), el tag ``, la inclusión de módulos, los formularios `c-form` y los componentes built-in. Léelo antes de crear o modificar cualquier `index-base.tpl`. ## Reglas de nomenclatura de variables El atributo `data-field-label` se convierte automáticamente en el nombre de variable Twig: se ponen minúsculas y se eliminan espacios y caracteres especiales. | Label | Variable resultante | |-------|---------------------| | `Categoría Noticia` | `categoranoticia` | | `Color Principal` | `colorprincipal` | | `Título Producto` | `ttuloproducto` | Reglas obligatorias: - Todo elemento con `data-field-type` DEBE incluir también `data-field-label`. - Sin `data-field-label`, el builder genera variables temporales o incorrectas y el módulo queda mal configurado. - Usa labels descriptivos y estables; no dejes labels vacíos ni genéricos como "Campo" o "Texto". - En `index-base.tpl` evita clases Tailwind con valores arbitrarios (`text-[44px]`, `font-['Cinzel']`, `leading-[1.1]`) — pueden romper el parseo. Muévelas a `style.css`. ## Tipos de campo (`data-field-type`) | Tipo | Elemento HTML | Devuelve | |------|---------------|----------| | `textfield` | `

` | String | | `headfield` | `

`–`

` | String + variable extra `_tag` con la etiqueta elegida | | `textbox` | `
` | String multilínea | | `wysiwyg` | `
` | String HTML | | `link` | `` | URL string (ya incluye barras) | | `upload` | `` | **Array** de `{urlPath, info1, info2, info3, info4}` | | `uploadMulti` | `
  • ` | Itera sobre archivos subidos | | `list` (fijo) | `
    ` | Valor seleccionado | | `list` (tabla) | `
    ` | `num` del registro | | `multiv2` | `
  • ` wrapper | Array de objetos repetibles | | `checkbox` | `
    ` o `` | `1` o `0` (número) | | `colorpicker` | `
    ` | Hex color string | ### textfield ```html

    Elemento editable

    ``` ### headfield Genera 2 variables: la estándar y `_tag` con la etiqueta elegida (h1…h6). ```html

    Título de la sección

    ``` ### textbox ```html
    Texto largo editable
    ``` ### wysiwyg Editor de texto enriquecido. Acceder con `| raw` para no escapar el HTML. ```html

    Texto con estilos editables

    ``` ### link El campo `enlace` de Acai ya incluye las barras necesarias — nunca añadas barras extra. Genera 2 variables: la estándar y `_anchor` con el anchor del enlace. ```html
    Haz clic aquí ``` ### upload Devuelve un array. Acceso en Twig: `{{ imagen[0].urlPath }}`. ```html
    ``` Atributos disponibles: - `data-lazy="true"` — carga perezosa - `data-field-width="1400"` — ancho máximo sugerido - `data-field-info1` … `data-field-info5` — labels de los campos de información por imagen Los `data-field-infoN` (hasta 5) definen los labels que el builder muestra como campos editables **en cada imagen subida** (van a `infoLabels` en el `builder.json`). Sus valores se leen luego como `info1`…`info4` dentro del array del var. ```html ``` ```twig {{ imagenprincipal[0].info1 }}
    {{ imagenprincipal[0].info2 }}
    ``` Los `data-field-infoN` funcionan igual en `uploadMulti`. ### uploadMulti Itera sobre todas las imágenes subidas. Variable iteradora: `uploadMulti`. ```html
  • {{ uploadMulti.info1 }}
  • ``` ### list (opciones fijas) ```html
    ``` Formato `data-list-options`: - `opcion1,opcion2` → la opción es etiqueta y valor a la vez - `|valor3,etiqueta3` → separa valor de etiqueta con `|` ### list (tabla) Selecciona un registro de otra tabla. Devuelve el `num`. ```html
    {{ record.titulo }}
    ``` - `data-list-table` — nombre de tabla **sin prefijo `cms_`** - `data-list-value` — campo a usar como valor (normalmente `num`) - `data-list-label` — campo a mostrar como label ### multiv2 — Campos repetibles Crea grupos de campos repetibles. La variable resultante es un array de objetos. ```html
    • Nombre del producto
      Descripción del producto
    ``` Uso en Twig: ```twig {% for record in productos %}

    {{ record.nombre }}

    {{ record.descripcion }}

    {% endfor %} ``` ### checkbox Devuelve `1` o `0` (número), nunca `true`/`false`. ### colorpicker Devuelve un string hexadecimal (`#ff0000`). Almacenado en config-vars (no en `builder_custom`). ## Agrupar campos en pestañas (`data-field-group`) Los campos de un módulo se reparten en pestañas dentro del panel de configuración añadiendo `data-field-group="Nombre del grupo"` al mismo elemento que ya lleva `data-field-type`. Mecanismo: cualquier atributo `data-field-*` extra —aparte de `data-field-type`, `data-field-label` y `data-field-value`— se recoge en el objeto `customDataField` del var, recortando el prefijo `data-field-`. Es decir, `data-field-group="Estilos"` acaba como `customDataField: { group: "Estilos" }` en el `builder.json`. Comportamiento del panel: - Los vars se agrupan por `customDataField.group` y se muestran en pestañas laterales. - Los vars sin `data-field-group` caen en la pestaña **Principal**. - El orden de las pestañas es el de primera aparición de cada grupo en el template. - Con un solo grupo no se muestran pestañas. - Funciona igual en vars de primer nivel y dentro de `multiv2`. ```html
    Título de la sección
    Texto de apoyo
    ``` Recomendación de uso: - Agrupa cuando el módulo pase de ~6-8 vars; por debajo, una sola lista se lee mejor. - Reparto habitual: **Contenido** (textos e imágenes), **Estilos** (colores, alineación, bordes), **Ajustes** (opciones de comportamiento, límites, enlaces). - Mantén los nombres de grupo consistentes entre módulos y en español. Son literales: `Estilos` y `estilos` generan dos pestañas distintas. ## Atributos Acai ### `c-if` — Renderizado condicional Usa `=` (un solo igual) para comparaciones, no `==`. ```html
    {{ subtitle }}
    Grid layout
    ``` ### `c-else` Va inmediatamente después del elemento `c-if`. ```html

    No image available

    ``` ### `c-for` — Iteración sobre array ```html

    {{ item.title }}

    ``` ### `c-for` — Iteración sobre tabla de BD ```html
    • {{ producto.title }}
    ``` Parámetros opcionales: `c-where` (string SQL), `c-order` (string de orden), `c-limit` (entero). Equivalente Twig: ```twig {% for producto in 'productos' | get('visible=1','num desc',10) %}
  • {{ producto.title }}
  • {% endfor %} ``` Variables del loop: `loop.index` (1-based), `loop.index is odd`, `loop.index is even`. ### `c-class` — Clases CSS condicionales ```html
    ``` ### `c-hidden` — Variables ocultas Elemento que NO se renderiza pero SÍ declara variables builder. Patrón típico para colores y opciones de configuración. ```html
    ``` ### `c-required` — Validación condicional ```html ``` ## Tag `` — Definir variables ```html {% set gracias = 'apartados' | get('num = 20').0 %} ``` ## Incluir módulos Para incluir un módulo dentro de otro módulo o dentro de una sección general, usa el `moduleId` como etiqueta HTML: ```html ``` Ejemplos: ```html ``` El módulo hijo recibe los parámetros como variables en su contexto. ## Formularios — `c-form` Maneja automáticamente validación, almacenamiento en BD y envío de emails. ```html ``` ### Atributos `c-form` | Atributo | Descripción | |----------|-------------| | `tableName="'tabla'"` | Tabla destino (sin `cms_`) | | `mailRecord="['correos', 'ID']"` | Template de email en tabla `correos` | | `sendTo="'email@dominio.com'"` | Destinatarios (separados por coma) | | `sendToClient="'campo_email'"` | Campo del formulario con email del cliente para auto-reply | | `captcha="true"` | Activa Google reCAPTCHA | | `honeypot="true"` | Campo oculto anti-spam | | `messageOK="'texto'"` | Mensaje al enviar correctamente | | `messageKO="'texto'"` | Mensaje al fallar validación | | `redirect="'/ruta/'"` | Redirección tras envío correcto | | `attachFiles="true"` | Adjuntar archivos al email | | `showImages="true"` | Mostrar thumbnails en email | | `emailMode="'twig'"` | Email en formato Twig | | `header="'
    ...'"` | HTML cabecera del email | | `footer="'
    ...'"` | HTML footer del email | | `styles="'body { ... }'"` | CSS del email | Para formularios estándar (contacto, postulación), prefiere `c-form` antes que crear lógica custom de POST/hook. Solo crea una tabla propia si necesitas gestionar esos registros desde el admin. ## Componentes built-in ### Carousel — `c-tns-wrapper` ```html
    ``` ### Lightbox ```html ``` ### Breadcrumb ```html ``` ### Animate On Scroll (AOS) ```html
    Contenido animado
    ``` Valores comunes: `fade-up`, `fade-down`, `fade-left`, `fade-right`, `zoom-in`, `zoom-in-up`, `fade-up-right`, `fade-up-left`. Tras cambios dinámicos en JS: `AOS.refresh()`. ### Lazy loading ```html ``` ## Reglas críticas 1. Todo `data-field-type` exige `data-field-label`. 2. `data-field-label` se transforma a variable: minúsculas, sin espacios ni caracteres especiales. 3. Campos `upload` retornan **arrays** — usa `imagen[0].urlPath`, nunca `imagen`. 4. Variables dentro de `multiv2` son propiedades del objeto iterado (`record.nombre`). 5. `c-if` usa `=` (un igual). `{% if %}` usa `==` (doble igual). 6. `c-for` con tabla: nombre **sin prefijo `cms_`**. 7. `enlace` ya incluye las barras — no añadas slashes extra. 8. Checkbox guarda `1` o `0` (número), nunca `true`/`false`. 9. Evita Tailwind arbitrary-value en `index-base.tpl` — muévelos a `style.css`. 10. `script.js` y `style.css` son estáticos: NO uses sintaxis Twig dentro. Pasa valores dinámicos vía `data-*`. 11. Si el módulo lista registros de una tabla del CMS (`c-for` sobre ella, o su `hook.php` la consulta), declara esa tabla con `update_module_metadata({ cmsTables: [...] })`. No es un `data-field-*`: no se deduce del HTML, hay que declararla. Ver `03-modules-and-sections.md`.