# Master Page Content

> Skill: Sistema blocchi di contenuto (`Contents`)

- Skill: `danilo-enesi/master-page-content` (Agent Skill, multi-file: 5 files)
- Install (CLI): `npx skillmds@latest add danilo-enesi/master-page-content`
- Raw SKILL.md: https://api.skillmd.com/api/skills/danilo-enesi/master-page-content/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: Danilo-enesi (https://skillmd.com/u/danilo-enesi)
- Updated: 2026-09-22
- Page: https://skillmd.com/skills/danilo-enesi/master-page-content

---


# Skill: Sistema blocchi di contenuto (`Contents`)

## Regola mentale — i blocchi sono DB-driven, NON statici

Un model con blocchi (Page, Blog, Project, ...) non ha un corpo fisso. Il suo contenuto è una **lista ordinata di righe DB** (`<entity>_contents`), ognuna con un `type` e un payload JSON libero (`data`). L'admin costruisce, ordina e riempie questi blocchi dal pannello Contenuti; il frontend legge le righe e mappa ogni `type` a un componente che è un **puro renderer**.

> Se stai per hardcodare testo, ordine, o assumere che un tipo di blocco esista solo su un modulo, ti stai sbagliando: tutto arriva da `getBlockData()` / `getContentMedia()`, ed esiste su qualsiasi modulo che abbia installato il sistema (vedi sotto).

## Quale file satellite ti serve

Il sistema ha **4 capa** (Field/toolbar → editor widget admin → dispatch AJAX → persistenza → lettura frontend) e questa skill le separa in 4 file, letti **solo** quando servono:

| Hai bisogno di... | Leggi |
|---|---|
| Capire l'architettura interna, chi chiama cosa, `moduleName` vs `viewsModuleName`, il gotcha `page_contents()`/`getBlocksAttribute()` | **`references/package-internals.md`** — leggilo SEMPRE prima degli altri tre, sono il contesto condiviso |
| Aggiungere i blocchi a un modulo che non li ha (es. Products, Services, un CRUD di progetto) | **`references/install-non-conventional.md`** |
| Capire il catalogo dei tipi esistenti, estendere un tipo (es. aggiungere un campo a `text`), aggiungere un tipo di blocco nuovo | **`references/conventional-blocks.md`** |
| Scrivere/adattare il rendering pubblico (componente + Blade) di un blocco | **`references/frontend-convention.md`** — è una convenzione minima di riferimento, non l'unico modo valido: se il progetto ha già un frontend con blocchi (sidebar, grouping, design system proprio), rispetta quello e usa questo file solo per i tipi non ancora implementati |

## `type` DB — i soli 6 valori standard + 1 custom

`title`, `text`, `article`, `gallery`, `attachments`, `video_embed` sono fissi nel package (catalogo completo in `conventional-blocks.md`). `image_full` è l'unico tipo custom già presente in tutti i moduli esistenti (Pages/Blog/Projects) — aggiunto via il meccanismo `getCustomContents()` descritto in `conventional-blocks.md`, non nel package.

## Prima domanda da farti quando ti attivano su questo tema

**Il modulo di cui si parla ha già il sistema Contents installato?** (verifica: il suo model principale ha `$contentClass`/`$content_foreign_key` dichiarati — via eredità da `Page` o via il trait `HasContentBlocks`, vedi `install-non-conventional.md` — e c'è una tabella `<entity>_contents`?)
- **Sì** → probabilmente stai lavorando su un tipo di blocco (estenderlo/aggiungerne uno) o sul frontend → `conventional-blocks.md` / `frontend-convention.md`.
- **No** → stai installando il sistema da zero su un modulo → `install-non-conventional.md`. Non improvvisare copiando solo pezzi: la procedura ha un passo (il dispatch `newContent()`) che fallisce in silenzio se saltato.

## Errori trasversali da evitare

- ❌ Trattare un blocco come componente statico con testo/ordine fissi. ✅ Tutto da `getBlockData()`/`getContentMedia()`.
- ❌ Modificare i file sotto `vendor/enesisrl/...`. ✅ Ogni fix di package va nel repo `laravel-master-dev` e tirato via Composer; a livello progetto usa gli override in `Master\Foundation\Form\...`.
- ❌ Cercare i media dentro `<entity>_contents.data`. ✅ Vivono nelle righe Spatie `media`, collezione `content<Tipo>__<media_id>` (`media_id` è l'unica cosa salvata in `data`).
- ❌ Salvare blocchi con `draft=1` come "live". ✅ Il frontend mostra solo `draft=0`; `draft=1` è la bozza pre-salvataggio creata dal dispatch AJAX prima del submit del form.
- ❌ Assumere che il nome del metodo relazione (`page_contents()`) o dell'accessor (`getBlocksAttribute` → `->blocks`) sia configurabile o rinominabile per modulo. Non lo è — vedi `package-internals.md`.

