Page Service
Load, save, list, and manage content pages.
PageService is the central API for working with content. It handles caching, events, and coordinates with the underlying content driver.
Getting the Service #
$pages = app('pages');
// or
$pages = app(PageService::class);
Loading Pages #
Single Page #
use VelvetCMS\Exceptions\NotFoundException;
try {
$page = $pages->load('about');
echo $page->title;
echo $page->html(); // Rendered HTML
} catch (NotFoundException $e) {
// Page does not exist
}
Returns a Page object. Throws NotFoundException if the page doesn't exist.
With Caching #
Pages are cached automatically. The cache is invalidated when content is saved.
// First call: loads from driver, caches result
$page = $pages->load('about');
// Subsequent calls: served from cache
$page = $pages->load('about');
Listing Pages #
Basic List #
$allPages = $pages->list();
Returns a Collection of Page objects.
With Filters #
$published = $pages->list([
'status' => 'published',
]);
$drafts = $pages->list([
'status' => 'draft',
]);
Sorting #
$pages->list([
'order_by' => 'created_at',
'order_dir' => 'desc',
]);
$pages->list([
'order_by' => 'title',
'order_dir' => 'asc',
]);
Note: The
FileDriverignoresorder_byandorder_dirfilters โ it always sorts bycreatedAtdescending. These filters are only respected by theDBDriverandHybridDriver.
Pagination #
// Get first 10 pages
$firstPage = $pages->list([
'limit' => 10,
'offset' => 0,
]);
// Get next 10 pages
$secondPage = $pages->list([
'limit' => 10,
'offset' => 10,
]);
Combined Filters #
$recentPublished = $pages->list([
'status' => 'published',
'order_by' => 'created_at',
'order_dir' => 'desc',
'limit' => 5,
]);
Saving Pages #
use VelvetCMS\Models\Page;
$page = new Page(
slug: 'new-post',
title: 'My New Post',
content: '# Hello\n\nThis is my new post.',
status: 'draft',
layout: 'blog',
);
$pages->save($page);
Required Fields #
slug- unique identifier/URLtitle- page titlecontent- page content
Updating Existing Pages #
Save with the same slug to update:
$page = $pages->load('existing-page');
$page->title = 'Updated Title';
$page->status = 'published';
$pages->save($page);
Deleting Pages #
use VelvetCMS\Exceptions\NotFoundException;
try {
$pages->delete('old-page');
} catch (NotFoundException $e) {
// Page did not exist
}
Returns true on success. Throws NotFoundException if the page doesn't exist.
Events #
PageService fires events for each operation:
| Event | Payload | When |
|---|---|---|
page.loading |
string $slug |
Before loading |
page.loaded |
Page $page |
After loading |
page.saving |
Page $page |
Before saving |
page.saved |
Page $page |
After saving |
page.deleting |
string $slug |
Before deleting |
page.deleted |
string $slug |
After deleting |
Example: Auto-Generate Slug #
$events->listen('page.saving', function (Page $page) {
if (empty($page->slug)) {
$page->slug = slugify($page->title);
}
});
Example: Clear Cache on Save #
$events->listen('page.saved', function (Page $page) {
app('cache.tags')->flush('pages');
});
Page Data Structure #
A Page object has the following properties:
use VelvetCMS\Models\Page;
$page = new Page(
slug: 'about',
title: 'About Us',
content: '# About Us\n\nOriginal markdown...',
status: 'published',
layout: 'default',
excerpt: 'Learn more about our company.',
meta: [], // Custom frontmatter fields
createdAt: new DateTime(),
updatedAt: new DateTime(),
publishedAt: new DateTime(),
);
$page->html(); // Rendered HTML
$page->isPublished(); // true
$page->getExcerpt(160); // Auto-generated excerpt if not set
$page->getMeta('key'); // Access custom meta fields
$page->toArray(); // Convert to array representation
Controller Example #
class PageController
{
public function __construct(
private readonly PageService $pages,
private readonly ViewEngine $view
) {}
public function show(Request $request, string $slug): Response
{
try {
$page = $this->pages->load($slug);
} catch (NotFoundException $e) {
return Response::notFound();
}
if (!$page->isPublished()) {
return Response::notFound();
}
return Response::html(
$this->view->render($page->layout ?? 'default', ['page' => $page])
);
}
public function index(Request $request): Response
{
$pages = $this->pages->list([
'status' => 'published',
'order_by' => 'created_at',
'order_dir' => 'desc',
'limit' => 20,
]);
return Response::html(
$this->view->render('pages/index', ['pages' => $pages])
);
}
}
Related #
- Content Drivers - storage backends
- Markdown - content format
- Standard Events - all page events