Das Feld einbinden
Der Editor ist ein October-Formular-Widget, registriert als contenteditor. Er funktioniert in jedem Formular: Tailor-Blueprints, Backend-Formulare von Plugins, eigene Models.
Backend-Formulare (fields.yaml)
fields:
content:
label: Content
type: contenteditor
# all optional:
allowBlocks: [heading, richtext, image] # whitelist of block handles (default: all)
maxDepth: 3 # nesting cap (default: 20)
previewCss: [/themes/demo/assets/css/theme.css] # default: the global "Preview stylesheets" setting
fillHeight: false # default: fill the remaining viewport height
showPreview: false # default: show the live-preview column
blockSettings: false # default: the global "Show block settings in the editor" setting
seoTab: false # default: the global "Show the SEO tab in the editor" setting
previewLayout: default # CMS layout of the fallback preview (default: the theme's 'default')
previewWrapClass: 'container' # class(es) around the document in the fallback preview
previewVar: article # extra page variable for the record in a Tailor real-page preview (default: post/entry)
draftContext: article # AI drafts fit an article column: no hero, no full-width sections (default: page)draftContext: article passt für Felder, deren Seite Titel, Titelbild und eine schmale Spalte selbst rendert, etwa Blogbeiträge: KI-Entwürfe verzichten dann auf Heros und Sektionen in voller Breite. allowBlocks und maxDepth gelten auch beim Speichern über DocumentSaveGuard. Verstöße, die schon im gespeicherten Dokument stehen, genießen Bestandsschutz.
Praxisnahe Live-Vorschau
Die Vorschau rendert die Blöcke in einem echten Theme-Layout (previewLayout) oder, wenn dieses scheitert, in einer Minimalseite. Links sind wirkungslos, und das iframe ist Script-sandboxed. Static Pages von RainLab.Pages nutzen das Layout der Seite.
Tailor-Blueprints
Derselbe Feldtyp contenteditor (mit allowBlocks / maxDepth) funktioniert in Blueprints. Er trägt sich in die Jsonables des Models ein und legt eine nullable longText-Spalte an.
Vorschau über die echte Seite
Ein Tailor-Eintrag wird über die Seite gerendert, die seinen Blueprint mit [section] isDefault = 1 bindet, samt deren Container. Das funktioniert für Entwürfe und neue Einträge und zeigt ungespeicherte Änderungen, ohne zu speichern. Der Datensatz wird als post und entry injiziert (weiterer Name über previewVar); previewWrapClass greift hier nicht.
Ohne eine solche Seite oder wenn sie nicht rendert, nutzt die Vorschau ein Layout: previewLayout, sonst das Layout der Section-Seite, sonst das der RainLab.Pages-Seite, sonst das default-Layout des Themes.
Was die Echte-Seite-Vorschau nicht reproduziert
Das PHP-onStart der Seite läuft nicht, daher fehlen SEO-Tags, Vorher/Nachher-Links und andere berechnete Variablen. Überschrift und Titelbild stammen aus den zuletzt gespeicherten skalaren Feldern.
Eigene Models
Lege eine nullable longText-Spalte an und trage das Feld in $jsonable ein. Das Widget speichert normalisiertes JSON; beim Lesen erhältst du das dekodierte Array.
public $jsonable = ['content'];
// migration
$table->longText('content')->nullable();Das Dokument rendern
{# CMS component: also injects the frontend CSS/JS (includeAssets, includeBootstrap) #}
[renickContent]
==
{% component 'renickContent' document=post.content %}
{# Layout without its own container: root blocks with no stored width get one #}
{% component 'renickContent' document=entry.content rootWidth='container' %}
{# Twig function and filter: HTML only #}
{{ content_render(post.content)|raw }}
{{ post.content|rc_blocks }}Alle drei rufen BlockRenderer::renderDocument() auf und akzeptieren einen JSON-String oder ein dekodiertes Array. Das Rendern wirft nie: Ein defekter Block wird zu einem HTML-Kommentar (im Debug-Modus zu einer sichtbaren Karte).
Der Editor zeigt Container als Standardbreite jedes Blocks, speichert aber nichts; ein Block bleibt also volle Breite, solange das Layout ihn nicht einrahmt. Ein Layout ohne äußeren Container (wie Dawns Seiten) übergibt rootWidth (container oder narrow): Blöcke auf oberster Ebene ohne gespeicherte Breite erhalten sie, ebenso die Kinder einer obersten Sektion ohne Breite. Blöcke mit fullBleed: true (Hero- und CTA-Bänder) bleiben volle Breite.
Update auf 1.0.7: Aus |content wird |rc_blocks
Der alte Filter verdeckte Octobers eigenen |content-Filter. Benenne {{ record.content|content }} (mit oder ohne |raw) überall, wo es ein Block-Dokument rendert, in {{ record.content|rc_blocks }} um und führe dann php artisan cache:clear aus. Bei Rich-Editor-HTML bleibt |content. Ein Dokument, das auf |content bleibt, gibt rohes JSON aus oder wirft bei einem dekodierten Array (einem Tailor-Feld) einen Fehler.
Site-beschränkte Blöcke verhalten sich fail-closed
Ein Block mit visibility.sites rendert nur, wenn die aktive Site bekannt und gelistet ist. In CLI oder Tests übergib sie: BlockRenderer::renderDocument($doc, ['siteId' => 1]).
Plugin-Integrationen
Alle Integrationen sind standardmäßig aus und ohne ihr Plugin wirkungslos. Ein Block, dessen Integration fehlt oder aus ist, rendert nichts; die Editor-Vorschau nennt den Grund.
Die Schalter für RainLab.Pages und RainLab.Blog liegen unter Einstellungen → Content → Content-Editor → Editor → Integrationen. Sie fassen bestehende Inhalte nie an: Nur leere Felder und Block-Dokumente bekommen den Block-Editor, und Block-Dokumente behalten ihn, wenn der Schalter wieder aus ist.
Static Pages (RainLab.Pages)
Layout-Variable (RainLab.Pages 2.x und 3.x)
[staticPage]
useContent = 0
==
{variable type="contenteditor" name="content" label="Content" tab="Content"}{/variable}
{% page %}- Die einzige Option unter Pages 3.x, dessen Editor den Einstellungs-Schalter ignoriert. Dawns
static-Layout bringt sie mit. - Eine
contenteditor-Variable pro Layout. Das Dokument steht im Markup der Seite, also rendert{% page %}es, und die Assets werden eingebunden. - Seiten, deren Inhalt noch HTML ist, öffnen schreibgeschützt und behalten ihr HTML.
- Unter 3.x speichern Übersetzungen in
content/static-pages-<locale>/; eine, die der Basisseite gleicht, bleibt leer. Die Historie gilt pro Site. - Pages 3.x warnt nicht vor ungespeicherten Änderungen in Layout-Variablen.
Einstellungs-Schalter (RainLab.Pages 2.x)
„Block-Editor für statische Seiten verwenden“ ersetzt das Inhaltsfeld bei Layouts ohne die Variable.
Blogbeiträge (RainLab.Blog)
„Block-Editor für Blogbeiträge verwenden“ bearbeitet content als Blöcke und rendert daraus beim Speichern und Laden content_html, sodass blogPost und blogPosts weiter funktionieren. Markdown-Beiträge behalten den Markdown-Editor. KI-Entwürfe nutzen dort den Artikel-Kontext (draftContext: article).
Shop (OFFLINE.Mall)
Einstellungen → Content → Mall-Integration (nur solange OFFLINE.Mall installiert ist) ergänzt die Blöcke Mall-Produkte und Mall-Kategorie, Darstellungs-Voreinstellungen und eine Statusliste der Seiten, die Mall braucht.
- Shop-Scaffold (Button oder
renick:content:mall-scaffold): kopiert einshop-Layout, die Produkt-, Kategorie-, Warenkorb-, Checkout-, Konto-, Adress- und Login-Seiten sowie Partial-Overrides austemplates/mall/der Theme-Lineage (sonst neutrale Bootstrap-5-Vorlagen) und verknüpft sie in Malls Einstellungen. Vorhandene Dateien bleiben erhalten. - Produktdaten werden in
renick.content.beforeRenderBlockaufgelöst, pro Währung und Kundengruppe gecacht und beim Speichern von Produkten, Varianten, Preisen und Kategorien geleert. - Mall liefert kein Frontend-CSS. Dawns Shop-Layout lädt
offline-mall-integration.cssund.js; andere Themes bleiben ungestylt.
Einsendungen von Besuchern (Tailor)
Ab October CMS 4.4 ergänzt Einstellungen → Content → Einsendeformulare den Block Einsendeformular und die Komponente tailorSubmission, die Tailor\Components\SubmissionComponent erweitert. Beim Blueprint bleiben Validierung, Moderationsstatus, Spam-Bereinigung, Benachrichtigungen sowie Octobers Drossel und Honeypot. Das Plugin ergänzt:
- das lokale Captcha pro Block (Immer an funktioniert auch bei ausgeschalteter globaler Einstellung),
- Pflichtfelder, die sich nicht ausblenden lassen, und einen Block, der nicht rendert, wenn ein Pflichtfeld nicht darstellbar ist,
- private Uploads (
uploads/protected, nur im Backend), deren Typ, Anzahl und Größe vor dem Absenden geprüft werden, - ein HMAC-signiertes Feld
_rc_tsf, geprüft beicms.page.init, damit gecachtes Block-HTML den Handler erreicht.
Zum Theming partials/renick-content/tailor-submission-form.htm überschreiben; {% framework %} ist nicht nötig. php artisan theme:seed dawn installiert eine Demo unter /en/appointment und schaltet die Integration ein (nur ab 4.4).
Eigene Integration schreiben
Erweitere Integration und gib sie aus renick.content.registerIntegrations zurück; eine eingebaute mit gleichem code() gewinnt. Pflicht sind nur code() und isAvailable(), und nur verfügbare Integrationen booten oder registrieren Komponenten. Optional: boot(), settingsPage(), blockDefinitions() (solange aktiv), blockHandles(), unavailableNotice(), components(), extendSettingsController(), cacheKeySuffix(), flushCaches(). isEnabled() liest <code>_enabled (Bindestriche als Unterstriche) aus den Content-Editor-Einstellungen, außer du überschreibst settingsModel() / settingKey().
use Renick\Content\Classes\Integrations\Integration;
final class AcmeShopIntegration extends Integration
{
public function code(): string { return 'acme-shop'; }
public function isAvailable(): bool
{
return \System\Classes\PluginManager::instance()->hasPlugin('Acme.Shop');
}
public function blockDefinitions(): array
{
return [/* renick.content.registerBlocks payload */];
}
}
// Plugin.php: register(), not boot(), because Renick.Content collects integrations in its own boot()
public function register()
{
Event::listen('renick.content.registerIntegrations', fn () => [new AcmeShopIntegration()]);
}