# Acai Modular System ## Modules Modules are the visual building blocks of Acai websites. Each module lives in `template/estandar/modulos//`. ### File Structure ``` / ├── index-base.tpl # Source template (EDIT THIS) ├── index.tpl # Compiled output (auto-generated, do NOT edit) ├── index-twig.tpl # Compiled Twig output (auto-generated, do NOT edit) ├── builder.json # Compiled builder vars (auto-generated, do NOT edit) ├── style.css # Module-scoped styles └── script.js # Module JavaScript ``` ### Template Syntax Templates use a hybrid of **Twig** and **Acai attributes**. The source file is always `index-base.tpl`. ```html

Title here

Description text

Call to action
``` ### Including Modules from Other Modules ```html ``` Parameters are received as variables inside the included module. ### Global Variables | Variable | Description | |----------|-------------| | `section_id` | Unique ID per module instance (use for anchors, JS scoping) | | `interno` | `true` when viewing in CMS editor, `false` on public site | | `server.HTTP_HOST` | Current domain | | `loop.index` | 1-based iteration index (inside `c-for`) | | `loop.index is odd` / `loop.index is even` | For alternating layouts | ## General Sections General sections are database-backed templates used for record views, headers, footers, and reusable layouts. They use the same template engine as modules. ### Key Differences from Modules - Access record data via the `thisrecord` variable - Upload fields return **arrays**: `thisrecord.image[0].urlPath` - Additional upload metadata: `info1` (alt text), `info2`, `info3`, `info4` - Foreign key fields use `_num` suffix: `thisrecord.category_num` - Saved via `save_general_section()` (not `save_module()`) - Parser type 2 = Twig (recommended), 0 = Acai legacy syntax ### Example: Record Template ```html
{{ thisrecord.imagen[0].info1 }}

{{ thisrecord.nombre }}

{{ thisrecord.descripcion | raw }}

{{ thisrecord.precio }}€
``` ### Variable Assignment Use `` tag to create variables from queries: ```html ``` ### Header, footer, and site-wide style/JS — NOT regular files `template/estandar/modulos/custom-header-twig/index-base.tpl` and the equivalent `custom-footer-twig` one are **not editable as files** — `acai-write`/`acai-line-replace` reject them with `"Forbidden path: ... es un artefacto generado del layout global"`. They're special general sections (the header/footer of the **entire site**). The `.tpl` on disk is only a generated copy for fast reading (`acai-view` works fine on it), but the real source lives in `layout.json` and is edited with the `get_layout_field`/`set_layout_field` MCP tools (see [docs/mcp-tools-reference.md](mcp-tools-reference.md)): - `field: 'header'` / `field: 'footer'` — the header/footer templates themselves. - `field: 'style'` — global CSS for the whole site. - `field: 'javascript'` — global JS for the whole site (delegated listeners shared by every page live here, not in any `.js` file in the repo — a `grep` of the repo for "how does X work in the header" can find nothing even though X works fine in production). Workflow for a header/footer/global-CSS/global-JS change: `get_layout_field({field: '...'})` → edit the **full** string (there's no line-replace for this — `set_layout_field` is a destructive full-content replace) → `set_layout_field({field: '...', content: ...})`. The response includes `compile_ok` — verify it, same as any other write-op (see the reliability warning in [docs/mcp-tools-reference.md](mcp-tools-reference.md)). ## Repeatable Content (multiv2) The `multiv2` builder field type creates repeatable groups of fields: ```html

{{ item.title }}

{{ item.description }}

``` Access individual items: `record.items[0].title`, `record.items[1].image`, etc.