Purpose
The hook for substituting the rendered content of a page. When
Site::renderContent() is about to produce HTML from the
resolved page, it first dispatches this event. A listener can
fill the html slot with its own rendered output; Site uses
that and skips the default Parsedown sanitizer pipeline.
The bundled scriptor-markdown-pages plugin uses it: during
PageResolving it parses the markdown file into HTML; here it
returns the cached HTML so the page does not get re-processed by
Parsedown. Same shape applies to any plugin that owns its own
rendering pipeline (a CommonMark variant with extensions, a
Twig-rendered virtual page, etc.).
FQCN + file path
- FQCN:
Scriptor\Boot\Events\Frontend\ContentRendering - Source:
boot/Events/Frontend/ContentRendering.php
When to use
Subscribe inside Plugin::register() when you want to:
- Replace the rendered HTML of a specific page (your virtual page, your custom-rendering page-type).
- Skip the default Markdown rendering for pages whose
contentis already HTML (or some other format your plugin handles).
You do not use this event to mutate already-rendered HTML
from other plugins; the event exposes the source Page, not the
in-flight content. If you need post-processing of the default
output, leave the slot alone (default pipeline runs) and do your
post-processing somewhere closer to the template.
Surface
Public properties
| Property | Type | Purpose |
|---|---|---|
page |
readonly Page |
The page about to be rendered |
html |
?string (mutable) |
The slot listeners fill. Starts null. First non-null wins |
No methods.
Constructor
public function __construct(public readonly Page $page)
Site::renderContent() constructs the event with the current
page. You do not construct it yourself.
Lifecycle
Fires once per renderContent() call (usually once per request,
unless a theme calls $site->render('content') more than once).
After every listener has run, Site::renderContent() reads
$event->html:
- Non-null string: that becomes the rendered content. The default Parsedown pipeline is skipped entirely.
- Null: the default
$site->sanitizer->markdown($page->content)pipeline runs.
Listeners run in registration order. The "first writer wins"
convention is enforced by the listener: subsequent listeners
should self-check $event->html !== null and leave the slot
alone unless they intentionally want to wrap the prior output.
Common patterns
Substituting HTML for a virtual page (markdown-pages-style)
$context->subscribe(
\Scriptor\Boot\Events\Frontend\ContentRendering::class,
function (\Scriptor\Boot\Events\Frontend\ContentRendering $event): void {
if ($event->html !== null) {
return; // someone already rendered
}
$cached = $this->htmlCache->get($event->page->id());
if ($cached !== null) {
$event->html = $cached;
}
},
);
Detecting your own page-type and rendering with a custom pipeline
$context->subscribe(
ContentRendering::class,
function (ContentRendering $event): void {
if ($event->html !== null) {
return;
}
if ($event->page->pagetype !== 'rich-cms') {
return;
}
$event->html = $this->richRenderer->render($event->page->content);
},
);
Wrapping the default output (the rare case)
If you actually want to wrap whatever the default pipeline
produces, you have to render the default yourself and use
html to substitute the wrapped result. The event does not
expose the in-flight default output:
$context->subscribe(
ContentRendering::class,
function (ContentRendering $event) use ($sanitizer): void {
if ($event->html !== null) {
return; // do not stomp another plugin's substitution
}
$inner = $sanitizer->markdown($event->page->content);
$event->html = '<article class="enhanced">' . $inner . '</article>';
},
);
In practice, theme-level wrapping is cleaner than wrapping at this layer. Reach for this only when the wrapping has to apply across themes.
See also
PageResolving: where markdown-pages computes the HTML it later returns from this eventPageResolved: fires before this event; for hooks that should run regardless of who rendersPage: the source page the event carriesSite: therenderContent()method that dispatches this eventSanitizer: the defaultmarkdown()method that runs when no listener fills the slot- Concept: Frontend Events: pipeline overview