Kirby Ink - PHP Class-based Blueprints

I am creating posts for my plugins to make it easier to find them using the forum search and not just the docs search.


This plugin introduces two new ways to define blueprints for Kirby 4. (yes 4+ only)

Fluent & Named Helper Classes

Define blueprints in PHP files with the fluent definition or named parameter definition instead of just the array definition that Kirby provides. You can use the*::make()-helpers to create them and avoid typos.

site/plugins/example/blueprints/fields/description.php

return Field::make(FieldTypes::TEXTAREA)
    ->label('Description')
    ->toArray();

PHP Attributes for PageModels

Define blueprints for pages in PageModels and use public properties with PHP attributes to define fields. You will gain auto-completion and insights on hover for the fields in your templates.

site/plugins/example/models/ArticlePage.php

#[
    Label([
        'en' => 'Introduction',
        'de' => 'Einleitung',
    ]),
    Type(FieldTypes::TEXT),
]
public Field $introduction;

Benefits of using this plugin

You could alternatively use another plugin by @lukaskleinschmidt to create type-hints based on your regular Kirby setup but that would mean you need to update them on every code change. With my plugin you can define your fields in the PageModel and instantly have code-completion in your templates. Hovering the property name will, in most IDEs, show you the attributes you did set for easy reference.

You could reduce the risk of typos and get auto-completion if you use my Schema for Kirby’s YAML Blueprints. But using the *::make()-helpers and the PHP attributes will get you code-completion and type-safety within the blueprints themselves and in the rest of your PHP code (the PageModels, controllers, templates, …).

Looking forward to your feedback,

- Bruno

1 Like

Love the concept, have to try it soon to be able to give more feedback.

I’m wondering, if you have page model attributes for fields, could a basic blueprint be generated automatically from those?

using the HasBlueprintFromAttributes should be enough to generate a fields-only blueprint.
you still need to register that blueprint array either with the autoloader plugin or manually. see https://github.com/bnomei/kirby-blueprints/blob/main/classes/Blueprints/HasBlueprintFromAttributes.php

see this example

The most recent version adds the Ink helpers. They wrap around the many static *::make methods while keeping static analysis happy.

The biggest advantage of Ink is that your IDEs highlighting will make your blueprints more readable than ever.


Why should you care about PHP based blueprints? As the excellent cookbook by @texnixe points out you can react dynamically on the state of your kirby installation.

many popular plugins use the same technique to show fields or sections depending on context of your page. like @tobimori 's seo plugin

my favorite use case is showing/hiding fields depending on the role of the user which complements the bouncer plugin, default when-conditionals or when-query plugin nicely.

    #[
        Blueprint
    ]
    public static function showAdminToolsBlueprint(): array
    {
        $role = kirby()->user()?->role();
        $isAdmin = $role == 'admin'; // use == or cast to string
        $adminTools = Ink::fields()
            ->fields([
                Ink::field(Ink::HEADLINE)
                    ->label('Admin Tools ('.$role.')'),
                Ink::field(Ink::SELECT)
                    ->label('State')
                    ->property('options', [
                        'new' => 'New',
                        'approved' => 'Approved',
                        'rejected' => 'Rejected',
                    ])
            ]);

        return Ink::page(
            title: 'Project',
            columns: [
                Ink::column(2 / 3)->fields([
                    //..
                ]),
                Ink::column(1 / 3)->sections([
                    Ink::files(label: 'Files'),
                    $isAdmin ? $adminTools : null,
                ]),
            ],
        )->toArray();
}

If you do not like typing out the many functions or want to be closer to yaml visually you can use the named properties syntax as well.

Ink::column(
    width: 2 / 3,
    fields: [
        'leftEar',
        Ink::field(
            type: Ink::BLOCKS,
            label: 'Trunk',
            properties: [
                Ink::EMPTY => '🐘'
            ]
        ),
        'rightEar',
    ]
),