Skip to content

Architecture ​

Renick.Content has three layers:

  1. Content. A document is a list of typed blocks, stored as JSON in a host field: a Tailor entry, a model attribute, a RainLab.Pages page or a RainLab.Blog post. JSON Schema v1 defines the format; every write is validated.
  2. Editor. A TipTap 3 / React 19 island mounted by the contenteditor form widget. The bundle in assets/dist is committed, so installs never run a JS toolchain.
  3. Rendering. BlockRenderer turns the JSON into HTML per request (via renickContent, content_render() or |rc_blocks) and applies visibility rules server-side.

Component map ​

On save, DocumentSaveGuard normalizes the document, validates it strictly and checks BlockRules. Rule violations the stored document already had don't block the save. After the host is saved, a version is captured and the media usage index is refreshed.

The document lives in the host. The plugin's own tables are sidecars: renick_content_versions (snapshots, audit log), renick_content_templates, renick_content_media_usage, renick_content_shared (Shared Content), renick_content_scripts (Custom Scripts), renick_content_api_tokens (hashed) and renick_content_ai_usage (monthly AI budget).

Where things live ​

plugins/renick/content/
├── Plugin.php          # registrations only
├── routes.php          # REST API (off by default), tile/thumb proxies, form endpoints
├── blocks/             # <handle>/<handle>.yaml definition + <handle>.htm partial
├── classes/            # renderer, document model, Content/ContentApi facades, Integrations/, TailorList/, ai/
├── components/         # renickContent, Entry List, submission form
├── contentfields/      # Tailor content field
├── controllers/        # backend pages (tokens, audit log, scripts, shared content, templates)
├── formwidgets/        # ContentEditor, icon picker
├── console/            # renick:content:* commands
├── models/
├── schema/document-v1.json
├── assets/             # src/ editor source; dist/ and frontend/ committed bundles
└── tests/              # PHPUnit; Playwright e2e lives in /tests-e2e

Start with Hosting the field, Authoring blocks, the PHP API or the REST API.