PageModel
Das PageModel ist das Herzstück der Inhaltsverwaltung in CrispyCMS. Es repräsentiert eine einzelne Seite (Page) und bündelt sämtliche relevanten Daten – vom eigentlichen HTML-Inhalt über SEO-Metadaten bis hin zu komplexen Beziehungen wie verknüpften Templates oder Kategorien.
In der Backend-Logik (PHP) arbeiten Sie mit einer Instanz der Klasse. Im Frontend (Twig) wird dieses Modell automatisch in ein performantes JSON-Objekt umgewandelt, das direkten Zugriff auf alle Eigenschaften bietet.
Namespace
Crispy\Models\PageModel
Datenstruktur in Templates
In Ihren Twig-Templates steht das PageModel standardmäßig als globale Variable Page zur Verfügung. Anders als in PHP handelt es sich hierbei nicht um ein Objekt mit Methoden, sondern um ein strukturiertes JSON-Objekt.
Das folgende Beispiel zeigt die typische Struktur eines solchen Objekts:
{
"id": 105,
"name": "Willkommen",
"content": "<h1>CrispyCMS ist installiert!</h1><p>Starten Sie jetzt...</p>",
"author": 1,
"isPrivate": false,
"properties": 5,
"coverImage": "/assets/ugc/header.jpg",
"template": {
"id": 12,
"name": "Standard Layout",
"path": "default.twig",
"layout": {
"slug": "full-width"
}
},
"slug": "willkommen",
"computedUrl": "home/willkommen",
"fullUrl": "[https://example.com/home/willkommen](https://example.com/home/willkommen)",
"category": {
"id": 1,
"name": "Home",
"slug": "home"
},
"createdAt": 1738498942,
"updatedAt": 1755720570
}
Identifikation & Inhalt
Diese Methoden dienen dem Zugriff auf die primären Inhalte und Identifikationsmerkmale einer Seite.
getId Integer | null
Liefert die eindeutige Datenbank-ID der Seite. Bei neu instanziierten, noch nicht gespeicherten Objekten ist dieser Wert null.
{% if Page.id %}
<p>Seiten-ID: {{ Page.id }}</p>
{% else %}
<p>Neue Seite (noch nicht gespeichert)</p>
{% endif %}<?php
$pageId = $pageModel->getId();
if ($pageId !== null) {
echo "Seiten-ID: " . $pageId;
} else {
echo "Neue Seite";
}getName String
Gibt den Titel der Seite zurück. Dieser wird sowohl für die Darstellung in der Navigation als auch für den <title>-Tag verwendet.
<h1 class="text-3xl font-bold">{{ Page.name }}</h1>
<title>{{ Page.name }} - {{ config.CMSControl_SiteName }}</title>echo "Editieren: " . htmlspecialchars($pageModel->getName());getContent String | null
Liefert den eigentlichen HTML-Inhalt der Seite, der meist über den WYSIWYG-Editor gepflegt wird.
In Twig muss der Inhalt mit dem |raw Filter ausgegeben werden, da CrispyCMS HTML-Ausgaben standardmäßig escaped, um XSS-Attacken zu verhindern.
<article class="prose lg:prose-xl">
{{ Page.content|raw }}
</article>
{# Für Meta-Descriptions ohne HTML #}
<meta name="description" content="{{ Page.content|striptags|truncate(150) }}">$content = $pageModel->getContent(); // Inhalt weiterverarbeitengetCoverImage String
Gibt den relativen Pfad zum konfigurierten Titelbild der Seite zurück.
{% if Page.coverImage %}
<div class="hero-image" style="background-image: url('{{ Page.coverImage }}');"></div>
{% endif %}
Routing & URLs
CrispyCMS berechnet URLs automatisch basierend auf der Kategorie-Hierarchie.
getSlug String
Der URL-freundliche Bezeichner der Seite selbst (z.B. kontakt), ohne übergeordnete Pfade.
getComputedUrl String
Die vollständige relative URL, zusammengesetzt aus dem Kategorie-Pfad und dem Seiten-Slug. Ideal für interne Verlinkungen.
<a href="/{{ Page.computedUrl }}">Zur Seite</a>// Redirect zur Seite
header("Location: /" . $pageModel->getComputedUrl());getFullUrl String
Die absolute URL inklusive Protokoll (https) und Domain. Wichtig für SEO (Canonical Tags) und Social Sharing (OpenGraph).
<link rel="canonical" href="{{ Page.fullUrl }}">
<meta property="og:url" content="{{ Page.fullUrl }}">
Beziehungen
Seiten existieren selten isoliert. Diese Methoden geben Zugriff auf verknüpfte Objekte.
getCategory CategoryModel
Gibt das verknüpfte Kategorie-Objekt zurück. Dies ermöglicht den Zugriff auf die Hierarchie (Parent-Category).
{% if Page.category %}
<nav aria-label="breadcrumb">
<ol>
{% if Page.category.parent %}
<li>{{ Page.category.parent.name }}</li>
{% endif %}
<li><a href="/{{ Page.category.slug }}">{{ Page.category.name }}</a></li>
<li aria-current="page">{{ Page.name }}</li>
</ol>
</nav>
{% endif %}
getTemplate TemplateModel
Liefert das zugewiesene Template. Dies ist besonders nützlich, um Layout-Entscheidungen im Frontend basierend auf dem Template-Typ zu treffen.
{% if Page.template.slug == 'landing-page' %}
{% include 'partials/hero-header.twig' %}
{% else %}
{% include 'partials/standard-header.twig' %}
{% endif %}
Metadaten & Status
isPrivate Boolean
Prüft die Sichtbarkeit der Seite. Eine Seite gilt als “Privat”, wenn entweder sie selbst oder ihre zugewiesene Kategorie als privat markiert wurde.
In Twig dient dies primär der Anzeige (z.B. Schloss-Icon). Die tatsächliche Zugriffskontrolle findet im Router statt, bevor das Template geladen wird.
{% if Page.isPrivate %}
<Badge variant="destructive">
<Icon name="lock" class="size-3 mr-1" /> Intern
</Badge>
{% endif %}
getCreatedAt / getUpdatedAt Timestamp
In PHP geben diese Methoden Carbon-Objekte zurück. In der JSON-Repräsentation für Twig handelt es sich um Unix-Timestamps (Integer), die mit dem date-Filter formatiert werden müssen.
<footer>
Erstellt: {{ Page.createdAt|date('d.m.Y') }}
{% if Page.updatedAt > Page.createdAt %}
(Aktualisiert: {{ Page.updatedAt|date('d.m.Y') }})
{% endif %}
</footer>
getEmbedding Array
Gibt den Vektor (Embedding) der Seite zurück, falls die OpenAI-Integration aktiv ist.
$embedding = $pageModel->getEmbedding();
// Array mit Float-Werten, z.B. [0.0123, -0.234, ...]
Vollständiges Template-Beispiel
Hier sehen Sie, wie die verschiedenen Datenpunkte des PageModel in einem typischen HTML5-Gerüst zusammenkommen:
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<title>{{ Page.name }} | Meine Website</title>
{# SEO #}
<meta name="description" content="{{ Page.content|striptags|truncate(160) }}">
<link rel="canonical" href="{{ Page.fullUrl }}">
{# Open Graph #}
<meta property="og:title" content="{{ Page.name }}">
<meta property="og:url" content="{{ Page.fullUrl }}">
{% if Page.coverImage %}
<meta property="og:image" content="{{ Page.coverImage }}">
{% endif %}
</head>
<body class="page-{{ Page.id }} template-{{ Page.template.slug }}">
<header>
<h1>{{ Page.name }}</h1>
{% if Page.isPrivate %}
<span class="private-badge">Geschützter Bereich</span>
{% endif %}
</header>
<main>
{# Inhalt sicher ausgeben #}
<div class="content-wrapper">
{{ Page.content|raw }}
</div>
</main>
<aside>
<h3>Details</h3>
<ul>
<li>Kategorie: {{ Page.category.name }}</li>
<li>Autor-ID: {{ Page.author }}</li>
<li>Erstellt am: {{ Page.createdAt|date('d.m.Y H:i') }}</li>
</ul>
</aside>
</body>
</html>