🚀 A new era: Kirby 4 Get to know
Skip to content

Custom post types

A blog is not just a great way to post text, but also images, videos, links or quotes. Putting all those different types of content into a dumb old article template is quite boring and so custom post types have become very popular.

This is a quick introduction how to build custom post types for your Kirby-powered blog.


Normally you would have a folder for each blog article and inside you would have an article.txt with a corresponding article.php template.

But since we want to control the HTML for each post type, we are going to rename our text files:

  • content
    • blog
      • a-text-post
        • article.text.txt
      • a-nice-video
        • article.video.txt
      • a-beautiful-image
        • article.image.txt
      • a-great-link
        • article.link.txt
      • a-thoughtful-quote
        • article.quote.txt

So whenever you want to post a video, you are going to use the article.video.txt filename and whenever you are going to post a regular text article you are going to use article.text.txt, etc.

You are free to use different content fields in each of those text files. For example for a video post it would makes sense to have something like:

Title: My awesome Video
Video: http://www.youtube.com/watch?v=YQIMGV5vtd4
Text: A Swarm of Nano Quadrotors – I want one for Christmas

…whereas for a quote it would be better to have something like:

Title: My awesome Quote
Quote: Design is how it works
By: Steve Jobs

It's up to you which fields you use for each post. All you need to make sure is to use them in your templates accordingly.


For each of those article types we are also going to need a template.
Add them to /site/templates

  • site
    • templates
      • article.text.php
      • article.video.php
      • article.image.php
      • article.link.php
      • article.quote.php

Use snippets!

In each template you are probably going to use almost the same HTML with a few exceptions, like embedding the video or image or showing the quote. To make your life easier, make sure that you use snippets wherever you can to re-use common pieces of code instead of adding them to each of the templates. This will make your templates much easier to maintain later.

Blog template

We now have different article templates for each post type, but there's still the list of articles on our main blog page. We probably also want to create different HTML per post type for the article list. Easy!

Open the main blog template in your editor. I suppose it's called /site/templates/blog.php or something.

<?php foreach ($articles as $article): ?>

  <?php if ($article->template() == 'article.text'): ?>

  <!-- put the HTML for the text post here -->

  <?php elseif ($article->template() == 'article.video'): ?>

  <!-- put the HTML for the video post here -->

  <?php elseif ($article->template() == 'article.image'): ?>

  <!-- put the HTML for the image post here -->

  <?php elseif ($article->template() == 'article.link'): ?>

  <!-- put the HTML for the link post here -->

  <?php elseif ($article->template() == 'article.quote'): ?>

  <!-- put the HTML for the quote post here -->

  <?php endif ?>

<?php endforeach ?>

The if clause together with the output of $article->template() makes it simple to generate different HTML for each post type. You can even extend this to support more post types.

Not a fan of long if clauses?

If and elseif blocks are not particularly great to make your template readable. We can use snippets again to simplify this.

  • site
    • snippets
      • blog
        • article.preview.text.php
        • article.preview.video.php
        • article.preview.image.php
        • article.preview.link.php
        • article.preview.quote.php

Each snippet contains the template code that is needed to create the article preview for the blog page. Now we can massively reduce the logic in our blog template.

<?php foreach ($articles as $article): ?>
  <?php snippet('blog/article.preview.' . $article->template(), ['article' => $article]) ?>
<?php endforeach ?>

Within each snippet you can work with the $article variable, that we've passed to the snippet in the foreach loop. The best part about this is, that a missing post type is simply ignored as the snippet won't load.