I’m using virtual pages in a project and I wanted to set up a JSON content representation. It seems like this is not possible?
Normally, just adding a template.json.php
to the templates folder is enough to make the content representation work. Do I have to do something special for virtual pages to work?
How have you implemented that virtual page? Is it reachable via the site index?
Thanks for your reply, @distantnative! It’s a virtual page with virtual children, and I after looking into it some more, I think that’s the issue. I could not reproduce the issue when using a simple, single layer virtual page.
Here’s a simplified example…
The publications page has a virtual “topics” page, defined in its model:
<?php
use Kirby\Cms\Pages;
/**
* PublicationsPage class
*
* This class extends the Page class to create a virtual page for the topic tags container
* and manages the combination of real and virtual child pages.
*/
class PublicationsPage extends Page
{
/**
* Get the real children of the page
*
* @return Pages Collection of real child pages
*/
public function realChildren(): Pages
{
return Pages::factory($this->inventory()['children'], $this);
}
/**
* Get or create the topic tags container
*
* @return Pages Collection containing the topic tags container
*/
public function getTopicTagsContainer(): Pages
{
return Pages::factory([
[
'slug' => 'topics',
'template' => 'topics',
'model' => 'topics',
'content' => [
'title' => 'Topics',
'uuid' => $this->uuid() . '-topics',
],
]
], $this);
}
/**
* Get all children, merging real children with the virtual topic tags container
*
* @return Pages Combined collection of real and virtual children
*/
public function children(): Pages
{
return $this->realChildren()->merge($this->getTopicTagsContainer());
}
}
The (virtual) topics page has virtual children itself, similarly defined in the model:
<?php
use Kirby\Cms\Pages;
use Kirby\Toolkit\Str;
/**
* TopicsPage class
*
* Generates virtual child pages for topic tags defined in the parent page's structure field.
*/
class TopicsPage extends Page
{
/**
* Generate and return virtual child pages for topic tags
*
* @return Pages Collection of virtual topic tag pages
*/
public function children(): Pages
{
$topicTags = $this->parent()->topic_list()->toStructure();
$topicTagsPages = $this->generateTopicTagsPages($topicTags);
return Pages::factory($topicTagsPages, $this);
}
/**
* Generate an array of topic tag pages
*
* @param \Kirby\Cms\Structure $topicTags Sorted structure of topic tags
* @return array Array of topic tag page data
*/
private function generateTopicTagsPages(\Kirby\Cms\Structure $topicTags): array
{
$topicTagsPages = [];
$usedSlugs = [];
foreach ($topicTags as $num => $topicTag) {
$usedSlugs[] = $slug;
$topicTagsPages[] = [
'slug' => $topicTag->topic_title()->slug(),
'num' => $num + 1,
'template' => 'topic',
'model' => 'topic',
'content' => [
'title' => $topicTag->topic_title()->value(),
'uuid' => $slug
]
];
}
return $topicTagsPages;
}
}
These topic pages are the ones I want to create content representations of. Unfortunately that doesn’t work and I get a 404 instead.
Can those be accessed via $site->find($path)
?
Yes, I can access them via $site->find('publications/topics/topic')
.
I could get it running for me.
My guess is that you don’t have a regular topic.php
template. Without it the content representation doesn’t work either.
Thank you for testing, Nico. I do have a topic.php
template, so I guess I’ll have to find the other difference between your setup and mine.
Maybe try to peel back layer by layer. E.g. if the virtual topics page works with/without merging with real children.
Because I think other than that I added it 1:1 as you posted above.
Except that in generateTopicTagsPages
$slug
didn’t exist
I finally had time to dig into this some deeper. Thanks again for testing it yourself, Nico.
In the end, it was not what I assumed previously — nested virtual pages work just fine (it must be pure magic). The culprit was a route with an aggressive (:all)
pattern. I didn’t expect it to also catch the .json
content representation. Makes total sense, though.
1 Like