Skip to content

Subpage builder

Auto-generate subpages when you create a new page

If you want to auto-create a given set of subpages every time you create a particular page, you can achieve this with a page.create:after hook. To make it more versatile, you can define a custom blueprint setting that leverages Kirby's new $page->blueprint() method. We will take you step by step through an example based on the Starterkit.

Let's say every time you create a new note page (in the Panel or progamatically), you want to create two subpages: gallery and info.

Blueprint settings

Add the custom option subpage_builder to the note.yml blueprint in the Starterkit:

/site/blueprints/pages/note.yml
title: Note
num: date
icon: 📖

subpage_builder:
  - title: Gallery
    uid: gallery
    template: gallery
    num: 1
  - title: Info
    uid: info
    num: 2
    template: info

columns:
  - width: 2/3
    fields:
      text:
        type: textarea
        size: large

  - width: 1/3
    sections:
      subpages:
        type: pages
        templates:
          - gallery
          - info
      meta:
        type: fields
        fields:
          date:
            type: date
            time: true
            default: now
          author:
            type: users
          tags: true
          gallery:
            type: pages
            query: site.find("photography").children
            multiple: false
            info: "{{ page.images.count }} image(s)"
            empty: "No gallery selected"
            image:
              cover: true
            help: Place the {{ gallery }} tag anywhere in your text to add the selected gallery

As you can see above, we also added a pages section for the subpages.

The hook

Now we need a hook that is called each time a page is created.

We can define it within the return array of our config.php:

/site/config/config.php
'hooks' => [
        'page.create:after' => function ($page) {
            buildPageTree($page);
        }
    ]

Within the hook's callback function, we call a function called buildPageTree() with the newly created $page as first parameter. We will define that function in a plugin.

The plugin

The buildPageTree() function is a recursive function that builds new subpages as long as the blueprint has a subpage builder setting with valid values.

/site/plugins/treebuilder/index.php
<?php

function buildPageTree($page) {

    // get the subpage_builder definition from the blueprint
    $builder = $page->blueprint()->subpage_builder();

    // if any is set…
    if (empty($builder) === false) {

        // …loop through each page to be built
        foreach($builder as $build) {

            // check if all necessary fields have been defined
            // in subpage_builder
            $missing = A::missing($build, ['title', 'template', 'uid']);

            // if any is missing, skip
            if (empty($missing) === false) {
                continue;
            }

            try {
                // the parent itself is created as a draft
                $subPage = $page->createChild([
                    'content'  => [
                        'title' => $build['title']
                    ],
                    'slug'     => $build['uid'],
                    'template' => $build['template'],
                ]);
            } catch (Exception $error) {
                throw new Exception($error);
            }

            // publish the subpages, so that they are published
            // when the parent is published
            if ($subPage) {

                // call the function recursively
                buildPageTree($subPage);

                // publish subpages and sort
                $subPage->publish();

                if (isset($build['num']) === true) {
                    $subPage->sort($build['num']);
                }
            }
        }
    }
}

In this example, all subpages in the tree are automatically published. That way, they will be published together with the parent without any further interaction.