medienbaecker / kirby-modules
Easily add modules to your pages
Package info
github.com/medienbaecker/kirby-modules
Type:kirby-plugin
pkg:composer/medienbaecker/kirby-modules
Requires
- dev-main
- 5.0.0-rc.8
- 5.0.0-rc.7
- 5.0.0-rc.6
- 5.0.0-rc.5
- 5.0.0-rc.4
- 5.0.0-rc.3
- 5.0.0-rc.2
- 3.0.0
- 2.9.3
- 2.8.4
- 2.8.3
- 2.8.2
- 2.8.1
- 2.8.0
- 2.7.0
- 2.6.0
- 2.5.0
- 2.4.1
- 2.4.0
- 2.3.1
- 2.3.0
- 2.2.3
- 2.2.2
- 2.2.1
- 2.2.0
- 2.1.1
- 2.1.0
- 2.0.1
- 2.0.0
- 0.7.0
- 0.6.3
- 0.6.2
- 0.6.1
- 0.6
- 0.5.1
- 0.5
- 0.4
- 0.3
- 0.2
- 0.1
- dev-dependabot/npm_and_yarn/defu-6.1.6
- dev-dependabot/npm_and_yarn/multi-bf05dc1ecf
This package is auto-updated.
Last update: 2026-05-14 14:52:26 UTC
README
Modular page building for Kirby using regular Kirby pages with their own blueprint and snippet, edited inline on the parent page.
Licensing
Kirby Modules is a commercial plugin. You can use it for free on local environments but using it in production requires a valid licence. You can pay what you want, the suggested price being 99€ per project. Feel free to choose "0" when working on a purposeful project ❤️
Features
- Edit module fields inline on the parent page with a blocks-like UI
- Signed previews for hidden modules
- Great performance with large numbers of modules
- Robust multilanguage behaviour
- Automatic container page creation, separating modules from regular subpages
- Multiple modules sections per page
- Sensible defaults in module blueprints
Installation
composer require medienbaecker/kirby-modules
Or download this repository and put it into site/plugins/kirby-modules.
What's a Module?
A module is a regular page, differentiated from other pages by being inside a modules container. This makes it possible to use pages as modules without sacrificing regular subpages.
Page
├── Subpage A
├── Subpage B
└── Modules
├── Module A
└── Module B
Quick Start
Add a (or multiple) modules section to your page blueprint:
# site/blueprints/pages/default.yml title: Default Page sections: modules: type: modules
Create a module blueprint and snippet:
# site/blueprints/modules/text.yml title: Text fields: textarea: label: Text
// site/snippets/modules/text.php <div id="<?= $module->slug() ?>"> <?= $module->textarea()->kt() ?> </div>
Or create both files using the CLI command:
kirby make:module gallery
In your snippet, $module is the module page and $page is the parent page. Variables from controllers are also available.
Module blueprints support the full Kirby blueprint layout, including columns and sections:
# site/blueprints/modules/images.yml title: Images icon: images columns: - width: 1/2 fields: title: label: Title type: text images: label: Images type: files - width: 1/2 sections: files: true
Render in your template:
// site/templates/default.php <?= $page->modules() ?>
Anchor Links
Use $module->slug() as the element ID in your module snippet:
<div id="<?= $module->slug() ?>">
The slug is editable in the Panel via the #anchor button on each module card or the "Change anchor" button in the toolbar's dropdown.
Visibility
Each module's visibility can be toggled with a single click on its card. Hidden modules stay in place — they keep their sort position and any inline edits — but the frontend skips over them when iterating $page->modules(). The card shows a striped background while a module is hidden.
Hidden modules get a signed preview URL (token + _module query param) so authors can verify them on the live URL without Panel login. The preview button appears in the card's toolbar only while the module is hidden — visible modules render via their parent's URL.
Section Options
| Option | Type | Description |
|---|---|---|
default |
string |
First/pre-selected module type in create dialog |
templates |
array |
Manually define available types instead of all |
templatesIgnore |
array |
Hide specific module types |
min |
int |
Minimum number of modules |
max |
int |
Maximum number of modules |
empty |
string |
Empty state text |
Multiple Sections
Each section's name (YAML key) becomes the container slug:
sections: modules: type: modules default: text sidebar: type: modules templates: - module.cta - module.newsletter
// Default container for modules section called `modules` <?= $page->modules() ?> // Secondary container for modules section called `sidebar` <?= $page->modules('sidebar') ?>
File Pools
By default, a files field in a module sees only that module's own files. That's okay if you want to add a section to the module, too. Most of the times, you want to use the (grand)parent page's file pool however.
The filePool method resolves to the right files collection regardless of where it's called:
- On a module, returns the host page's files (the module's grandparent — the page that owns the modules container).
- On any other page, the page's own files.
- On the site, file, or user, that model's own files.
Use it as the query of any files field that should follow this rule:
type: files query: model.filePool uploads: parent: model.filePool.parent
To access the page of the file pool, you can use model.filePool.parent, as shown in the uploads option.
Config Options
// site/config/config.php return [ // Auto-publish new modules (default: false → created hidden). Set true to create visible. 'medienbaecker.modules.autopublish' => true, ];
Template Methods
| Method | Description |
|---|---|
$page->modules() |
All modules (default container) |
$page->modules('sidebar') |
Modules from named container |
$page->hasModules() |
Page has modules |
$page->isModule() |
Page is a module |
$page->filePool() |
Files for blueprint queries (host page if module, else self) |
$module->moduleId() |
CSS class (e.g. module--text) |
$module->moduleName() |
Blueprint title |
Custom Models
Override the model for all module types via config:
// site/config/config.php 'medienbaecker.modules.model' => CustomModulePage::class,
Or override a single module type via site/models/ (as you would with any regular page):
// site/models/module.text.php class ModuletextPage extends Medienbaecker\Modules\ModulePage { // your methods }
