Double template


For a site, the client needs two different visualization for each instance of her “project” page.

One which is the public, navigable, page, and another one which is for her private use and that works as a portfolio-like page of each “project” instance.

The difference between these two types of visualizations of “project” are so dissimilar they can’t really share a template, they would use two different templates.

And since the ammount of “project” pages is dynamic, I can’t hardcode this manually, it has to be dynamic.

My question is how to best approach this.

My first thought was to perhaps to use a page model to overwrite the children() method so each “project” has a virtual page child, which is a copy of itself except for the template. The url for this virtual child would be the original url with “portfolio” added to the end of it, or something similar.

Something like:

class PortfolioProjectPage extends Kirby\Cms\Page
    public function children()
        $portfolioPage = [
            'slug' => $this . 'portfolio',
            'num' => $this->num(),
            'template' => 'portfolio-page',
            'model' => 'portfolio-page',
            // ...
            'content'  => [
                'title'  => $this->title() . ' ( Portfolio )',
                // ...
        return Pages::factory($portfolioPage, $this);


But this seems like, perhaps, an overcomplicated solution. I tend to forget about simple solutions.

Is there any simple solution I am missing here.

Thank you!

An alternative could be a content representation, e.g. portfolioproject.portfolio.php which you would call in the browser as eg. notes/exploring-the-universe.portfolio

Thanks, that is a good idea.

But it says that Kirby tries to guess the content type header, I assume from the extension added to the representation, such as .json

But if use .portfolio wanting to echo mere php will I need to explicitly state it is php somehow on the file itself?


I’m not sure if a content type header is needed, in my local test the content type was text/html which is correct and it worked without issues. But you could send a header should the need arise.

1 Like