- Correct hooks-and-api.md: file hooks vs module hooks param injection, FK naming not always _num, CmsApi.hook Promise pattern - Add 9 new rules to hooks-and-api.md: reserved `tipo` var, ghost modules, cms_uploads schema, name vs title by menuType, menuOrder, localCache gotcha, slug generation, uploads from hooks, CocoEmail - Add 5 rules to modular-system.md: minified/ dir, Docker workflow, debug tools (?compiletwig/?pruebas), general sections deploy, controlador - Add 2 rules to css-js-conventions.md: Vue inline conflict, Vue mount delay - Add testing section to quick-reference.md - Create docs/deploy-and-sync.md for production deploy and sync rules - Promote 3 critical rules to CLAUDE.md (rules 11-13) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
152 lines
5.2 KiB
Markdown
152 lines
5.2 KiB
Markdown
# Acai Modular System
|
|
|
|
## Modules
|
|
|
|
Modules are the visual building blocks of Acai websites. Each module lives in `template/estandar/modulos/<module-id>/`.
|
|
|
|
### File Structure
|
|
|
|
```
|
|
<module-id>/
|
|
├── 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
|
|
└── minified/
|
|
├── script-{hash}.js # JS minificado (servido al browser, do NOT edit)
|
|
└── style-{hash}.css # CSS minificado (servido al browser, do NOT edit)
|
|
```
|
|
|
|
### Template Syntax
|
|
|
|
Templates use a hybrid of **Twig** and **Acai attributes**. The source file is always `index-base.tpl`.
|
|
|
|
```html
|
|
<section class="hero-section" id="{{ section_id }}">
|
|
<div class="container mx-auto px-4">
|
|
<h2 data-field-type="headfield" class="text-3xl font-bold">
|
|
Title here
|
|
</h2>
|
|
<p data-field-type="textbox" class="text-lg text-gray-600">
|
|
Description text
|
|
</p>
|
|
<img data-field-type="upload" src="placeholder.jpg" class="w-full rounded-lg" />
|
|
<a data-field-type="link" href="#" class="btn">Call to action</a>
|
|
</div>
|
|
</section>
|
|
```
|
|
|
|
### Including Modules from Other Modules
|
|
|
|
```html
|
|
<module_id :param1="value1" :param2="'string value'"></module_id>
|
|
```
|
|
|
|
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 field names match the schema exactly (may or may not have `_num` suffix — always check the `.ini.php`)
|
|
- Saved via `save_general_section()` (not `save_module()`)
|
|
- Parser type 2 = Twig (recommended), 0 = Acai legacy syntax
|
|
|
|
### Example: Record Template
|
|
|
|
```html
|
|
<article class="product-card">
|
|
<img src="{{ thisrecord.imagen[0].urlPath }}"
|
|
alt="{{ thisrecord.imagen[0].info1 }}"
|
|
class="w-full h-64 object-cover" />
|
|
<h3 class="text-xl font-semibold">{{ thisrecord.nombre }}</h3>
|
|
<p class="text-gray-600">{{ thisrecord.descripcion | raw }}</p>
|
|
<span class="text-2xl font-bold">{{ thisrecord.precio }}€</span>
|
|
</article>
|
|
```
|
|
|
|
### Variable Assignment
|
|
|
|
Use `<set>` tag to create variables from queries:
|
|
|
|
```html
|
|
<set :categories="'categorias' | get()"></set>
|
|
<set :featured="'productos' | get({destacado: 1}, 'orden ASC', 3)"></set>
|
|
```
|
|
|
|
|
|
## Repeatable Content (multiv2)
|
|
|
|
The `multiv2` builder field type creates repeatable groups of fields:
|
|
|
|
```html
|
|
<div c-for="item in record.items">
|
|
<h3 data-field-type="textfield">{{ item.title }}</h3>
|
|
<p data-field-type="textbox">{{ item.description }}</p>
|
|
<img data-field-type="upload" src="{{ item.image }}" />
|
|
</div>
|
|
```
|
|
|
|
Access individual items: `record.items[0].title`, `record.items[1].image`, etc.
|
|
|
|
---
|
|
|
|
## Workflow Local (Docker)
|
|
|
|
Al editar módulos en desarrollo local con Docker, los archivos compilados no se regeneran automáticamente. Hay que copiar manualmente:
|
|
|
|
```bash
|
|
# 1. Editar HTML y JS por separado
|
|
vim modulos/MODULE_ID/index-base.tpl # Solo HTML
|
|
vim modulos/MODULE_ID/script.js # Todo el JS
|
|
|
|
# 2. Copiar para que Docker los sirva
|
|
cp modulos/MODULE_ID/index-base.tpl modulos/MODULE_ID/index.tpl
|
|
cp modulos/MODULE_ID/script.js modulos/MODULE_ID/minified/script.js
|
|
```
|
|
|
|
### Herramientas de debug
|
|
|
|
- **`?compiletwig`** — Añadir a cualquier URL. Regenera los `index-twig.tpl` pero con un pipeline diferente al auto-compile. Útil para forzar recompilación, pero puede romper en ciertos contextos. Usar con precaución.
|
|
- **`?pruebas`** — Bypass de modo mantenimiento. Añadir a cualquier URL establece `$_SESSION["pruebas"]=true`. Solo hay que hacerlo una vez por sesión.
|
|
|
|
---
|
|
|
|
## General Sections — Deploy
|
|
|
|
Las general sections se identifican como `custom-{nombre_tabla}` (ej: `custom-productos`). Se despliegan con `save_general_section`, NO con `save_module`:
|
|
- `table`: nombre de la tabla (ej: `"productos"`)
|
|
- `content`: HTML del template
|
|
- `javascript`: JS
|
|
- `css`: CSS
|
|
|
|
---
|
|
|
|
## Páginas CMS (Apartados)
|
|
|
|
### Campo `controlador` obligatorio para builder
|
|
Si una página debe renderizar módulos del builder (drag-and-drop), necesita estos campos configurados:
|
|
```
|
|
controlador = "cms/lib/plugins/builder_saas/controlador.php"
|
|
precontrolador = "cms/lib/plugins/builder_saas/controlador_tabla.php"
|
|
```
|
|
Sin estos campos, la página muestra solo la general section (`custom-apartados`) en vez de los módulos asignados.
|