How to store and display blog entries in /blog/YYYY/MM folders?

,

Writing a new thread because I’m somewhat stuck here. This topic is more complicated, it seems, and the previous discussion was for Kirby v3, so I think that having a new thread for the current and the next version makes sense - it’ll take me a few more months to have my Kirby installation ready, and I’m positive that v6 will be released by then. :slight_smile:

What I try to achieve is a WordPress-like /blog/yyyy/mm/slug structure. Example /content/ structure from my testing environment:

% find content
content
content/home
content/home/home.txt
content/blog
content/blog/2026
content/blog/2026/07
content/blog/2026/07/testpost
content/blog/2026/07/testpost/article.txt
content/site.txt
content/error
content/error/error.txt

I try to create the folder structure automatically, via site/models/article.php:

<?php

class ArticlePage extends Page {

    public static function create(array $props): Kirby\Cms\Page
    {
        $date = $props['content']['date'] ?? date('Y-m-d');

        $year  = date('Y', strtotime($date));
        $month = date('m', strtotime($date));

        $blog = page('blog');

        $yearPage = $blog->find($year);
        if ($yearPage === null) {
            $yearPage = Page::create([
                'parent'   => $blog,
                'slug'     => $year,
                'template' => 'archive.year',
                'content'  => ['title' => $year],
                'draft'    => false,  
            ]);
        }

        $monthPage = $yearPage->find($month);
        if ($monthPage === null) {
            $monthPage = Page::create([
                'parent'   => $yearPage,
                'slug'     => $month,
                'template' => 'archive.month',
                'content'  => ['title' => $month],
                'draft'    => false,
            ]);
        }

        $props['parent'] = $monthPage;
        return parent::create($props);
    }
}
?>

Now I wonder what I did wrong, because that does not create subfolders - the resulting posts are in yyyymmdd_slug instead. And I can’t seem to fetch them. I expanded site/templates/default.php to try and read them, but it doesn’t work:

<!doctype html>
<html>
    <head>
        <?php snippet('scss') ?>
        <?php snippet('webmention-endpoint'); ?>
    </head>
    <body>
        <h1><?= $page->title()->html() ?></h1>

        <?php foreach($page->index()->filterBy('article')->listed()->flip() as $article): ?>

            <article>
                <h1><?= $article->title()->html() ?></h1>
                <p><?= $article->text()->excerpt(300) ?></p>
            </article>

        <?php endforeach ?>
    </body>
</html>

All I get is <h1>Home</h1>. Maybe I misunderstand how Kirby works (21 years of WordPress, 27 years of occasional PHP, still trying to grok Kirby’s basics), so I’ll probably need a hint here. :face_with_peeking_eye:

I am afraid that your ArticlePage::create() method won’t get called for creating the blog page - as the ::create() method is called to create the object/page, it isn’t yet the specific page model (ArticlePage in you case) yet. So the parent page (e.g. blog) will call in its ::createChild() method the general base Page::create(). The page ends up directly in blog/. The 20260722_ prefix is likely just the sorting number from num: date in your blueprint. You could instead look into overwriting the ::createChild() method of your parent page (e.g. BlogPage - or similar if you have that).

In your template example, $page->index() is probably not right. You likely render the home page with it (as you say showing <h1>Home</h1>, but your home page doesn’t;'t have the blog articles as children or grandchildren. So it’s either $site->index() but use that with caution as that can be quite performance heavy on larger sites. Ideally, you know your blog parent page and then do something like page('blog')->children()->listed()->flip().

Ah, I might have got confused between articles (“blog pages”) and the blog itself. From what I had read up to this point, creating an Article and telling the Model what its parent is would be enough.

So what I need is something like site/models/blog.php:

<?php

class BlogPage extends Page {
    public static function createChild(array $props): Kirby\Cms\Page
    {
      // ...
    }
}
?>

and fill it with what was ArticlePage::create? The blog page itself exists - but I did not declare a model for that yet.