Virtual Pages
Render pages backed by external JSON or API data through the normal routing and template pipeline.
On this page
What is a virtual page?
A Page backed by data that was never read from disk, for exposing an external API (events, products, any JSON) as a renderable page.
A virtual page is never injected globally. It exists only because a real page, with a real folder and _index.json, routes to it explicitly, the same constraint that governs addons.
Creating one
App::page(string $uri, array $data) already supports this. A non-empty $data skips every disk read, and a view in $data still resolves the right view-bound Page subclass:
$app->page('events/summer-fest', $syntheticData);
The result is a normal Page, with standard class and template resolution behavior.
In a router
A real page's router builds the data and returns the page. Handlers may return a different Page:
// site/views/events/router.php, for the real page at site/pages/events/
use Phlat\App;
use Phlat\Page;
use Phlat\Exceptions\NotFoundException;
use Phlat\Toolkit\Hash;
return function (App $app, Page $page): void {
$page->router->get('{slug}', function ($slug) use ($app, $page) {
$record = (new EventsSource())->find($slug);
if (!$record) throw new NotFoundException();
return $app->page("{$page->url()}/{$slug}", [
'uuid' => Hash::sha256("events:{$slug}"),
'view' => 'event',
'data' => $record,
]);
});
};
Use a conventional URI like "{$page->url()}/{$slug}" and url(), template resolution and everything else derived from the path just work.
Listing
For an index, build each page the same way and collect them in a PageCollection, which accepts appended instances:
$events = new PageCollection($app);
foreach ($source->all() as $slug => $record) {
$events->append($app->page("{$page->url()}/{$slug}", [
'uuid' => Hash::sha256("events:{$slug}"),
'view' => 'event',
'data' => $record,
]));
}
Limits
- Not in the registry.
find(), search and sitemaps don't see virtual pages. List them from their source, as above. - No shared source interface. A data source is a plain class with whatever lookups suit it.
- Don't save them.
save()on a virtual page writes real files at its path. Return virtual pages only from GET handlers, so they never reach the admin's edit flow.