Skip to content

Nested blocks

This is an example of how to build a nested block including a live panel preview and output snippets for the website. In our example we are creating a FAQ block, which allows us to add nested question/answer blocks within it. The block is built as a standalone plugin and can be extended and modified to your own needs. The example is based on a blank Kirby installation (v.3.5+) and everything is explained step by step.

Preparation

First we prepare our Kirby config file to enable custom blocks. We keep the Kirby default blocks grouped, and separate our new custom blocks for a better overview.

/site/config/config.php
return [
  'blocks' => [
    'fieldsets' => [
      'custom' => [
        'label' => 'Custom blocks',
        'type' => 'group',
        'fieldsets' => [
          'faq'
        ]
      ],
      'kirby' => [
        'label' => 'Kirby blocks',
        'type' => 'group',
        'fieldsets' => [
          'heading',
          'text',
          'list',
          'quote',
          'image',
          'video',
          'code',
          'markdown'
        ]
      ]
    ]
  ]
];

The blocks field can now be used without adding the new FAQ block type manually:

/site/blueprints/pages/default.yaml
title: Page
fields:
  blocks:
    type: blocks

Blueprints

Now let's create the blueprint for the FAQ block itself, and the blueprint for the nested block with a question and answer field.

The name of the block (faq in our example) must be unique and must not already be used by Kirby (e.g. heading, text, etc.). If the name is already in use, you can simply add a prefix or suffix to it (e.g. my_custom_faq).

FAQ blueprint

The first blueprint defines our FAQ block. Besides our new nested block we use an additional text field and a writer field in our example.

/site/plugins/faq-block/blueprints/blocks/faq.yml
name: FAQ
icon: star
fields:
  headline:
    type: text
  text:
    type: writer
  blocks:
    type: blocks
    fieldsets:
      - faqItem

Question/answer blueprint (nested)

The second blueprint defines the nested block with the question and the answer fields. Hereafter we call this block faqItem.

/site/plugins/faq-block/blueprints/blocks/faqItem.yml
name: Question / Answer
icon: box
fields:
  question:
    type: text
    placeholder: Your question …
  answer:
    type: writer
    placeholder: Your answer …

Output

Now we build the output snippets for the website. We need a snippet for the faq block and a snippet for the faqItem block.

Default template

For completeness, we also show the default template here, which can be used to render our newly created faq block.

/site/templates/default.php
<!DOCTYPE html>
<html lang="en">
<head></head>
<body>
    <h1><?= $page->title() ?></h1>
    <?= $page->blocks()->toBlocks(); ?>
</body>
</html>

FAQ snippet

The first output snippet is for the FAQ block. We show headline and text of this block as usual and we call the nested block(s) as follows.

/site/plugins/faq-block/snippets/blocks/faq.php
<div class="faq">
  <h2><?= $block->headline() ?></h2>
  <p><?= $block->text() ?></p>
  <dl>
    <?= $block->blocks()->toBlocks() ?>
  </dl>
</div>

Question/answer snippet

The second snippet defines the output of the nested question/answer block.

/site/plugins/faq-block/snippets/blocks/faqItem.php
<dt><?= $block->question() ?></dt>
<dd><?= $block->answer() ?></dd>

The plugin

Now let's create the plugin itself. The plugin needs only two files to work: index.php and index.js. An optional file index.css allows individual stylesheets for the preview.

index.php

In the index.php file we register our blueprints and output snippets, respectively for the FAQ block (faq) and the question/answer block (faqItem).

/site/plugins/faq-block/index.php
<?php

Kirby::plugin('your-project/faq-block', [
    'blueprints' => [
        'blocks/faq'      => __DIR__ . '/blueprints/blocks/faq.yml',
        'blocks/faqItem'  => __DIR__ . '/blueprints/blocks/faqItem.yml'
    ],
    'snippets'   => [
        'blocks/faq'      => __DIR__ . '/snippets/blocks/faq.php',
        'blocks/faqItem'  => __DIR__ . '/snippets/blocks/faqItem.php'
    ]
]);

index.js

The index.js file handles the previews inside the Panel. We define a template for faq and faqItem.

/site/plugins/faq-block/index.js
panel.plugin('your-project/faq-block', {
  blocks: {
    faq: {
      template: `
        <div @dblclick="open" class="faq">
          <h2>{{ content.headline }}</h2>
          <div v-html="content.text"></div>
          <dl v-for="item in content.blocks">
            <dt v-html="item.content.question"></dt>
            <dd v-html="item.content.answer"></dt>
          </dl>
        </div>
      `
    },
    faqItem: {
      template: `
        <div>
          <strong>
            <k-input
              v-bind="field('question')"
              :value="content.question"
              @input="update({ question: $event })">
            </k-input>
          </strong>
          <p>
            <k-writer
              v-bind="field('answer')"
              :value="content.answer"
              @input="update({ answer: $event })">
            </k-writer>
          </p>
        </div>
      `
    }
  }
});

index.css

The .css file is optional and can be used to style the preview for the block (and the nested blocks if needed).

/site/plugins/faq-block/index.css
/**
 * This is just an example
 * Add your individual css code here
 */

.faq {
  padding: 1.5rem;
  background: #fef3c7;
}
.faq h2 {
  font-size: 1.8em;
  font-weight: bold;
}
.faq h2 + div {
  color: #da7c0d;
}
.faq dl {
  padding: 20px 0 0;
}
.faq dl dt {
  font-weight: bold;
}
.faq dl dd {
  font-style: italic;
}

Summary

That's it! Now you have a fully functional example of how nested blocks are working. Add your own fields and styles to your block as you like.

The following files are used in our example:

  • blueprints
    • blocks
      • faq.yml
      • faqItem.yml
  • snippets
    • blocks
      • faq.php
      • faqItem.php
  • index.css
  • index.js
  • index.php

Feel free to download all needed files here: Nested blocks example.

Author