Modules

Pagekit uses Modules to set up the application code. The module definition is used to provide bootstrapping, routing and other configuration options. Here you can listen for events, add custom classes and your own controllers.

Definition: index.php

In order to load and configure a module, Pagekit has a ModuleManager. It will look for an index.php file in the root of the module's directory and expect it to return a PHP array. Think of this array as the bootstrap for the modules code.

By setting the right properties in this array, you tell Pagekit everything it needs to know about your module.

  1. <?php
  2.  
  3. /*
  4. * Return a php array which is the module definition.
  5. */
  6. return [
  7.  
  8. // Required: Unique module name
  9. 'name' => 'hello',
  10.  
  11. ];

This minimal example is a valid module definition, although it doesn't do anything except being loaded by Pagekit. A module is only loaded if the package it comes in has been enabled in the admin panel.

Note: If you start exploring Pagekit's internal structure, you will see the same module structure in many places, it's a central concept of the Pagekit architecture.

Available properties

The following table gives an overview of all keys that you can use in the module definition array. The sections below then explain the properties in detail and include code examples. You can directly jump to each section by clicking one of the Details links.

KeyDescriptionMore
mainBootstrap code, executed when module is loadedDetails
autoloadRegister namespaces to be autoloadedDetails
routesMount controllersDetails
permissionsDefine and register permission namesDetails
resourcesRegister resource shorthandsDetails
eventsListen to events from Pagekit or other modulesDetails
configDefault module configurationDetails
nodesRegister Nodes for the Site TreeDetails
nodeDefault options for node configurationDetails
settingsLink to a settings screenDetails
menuAdd menu items to the admin panelDetails
widgetsRegister WidgetsDetails
widgetDefault options for widget configurationDetails

Bootstrap code

To execute any kind of PHP code you can assign a callback function to the main property. The function receives the Pagekit Application container instance as a parameter.

  1. use Pagekit\Application;
  2.  
  3. // ...
  4.  
  5. 'main' => function (Application $app) {
  6. // bootstrap code
  7. }

This function is called when this module is loaded, so on every regular page request. However, the module's index.php needs to be located in a valid package and the package needs to be enabled in the admin panel. This means that an extension needs to be installed and also enabled in order for the bootstrap code to be loaded. If you use this inside a theme, only the bootstrap code from the currently activated theme is executed.

Instead of assigning a callback function and having all of your code directly in the index.php, you can also create a dedicated module class in a separate file. You then specify the full name of your module class (including the namespace) as the value of the main property.

  1. 'main' => 'MyNamespace\\MyModule',

Note The referenced namespace has to be autoloaded in order for this to work. Make sure the MyModule class implements the interface Pagekit\Module\ModuleInterface.

Register custom namespaces

Pass a list of namespaces and paths to be autoloaded by Pagekit. The path is relative to the module's path, so that src in the following example is located at packages/VENDOR/PACKAGE/src, assuming the module definition is located at packages/VENDOR/PACKAGE/index.php.

  1. 'autoload' => [
  2.  
  3. 'Pagekit\\Hello\\' => 'src'
  4.  
  5. ]

The classes from the linked directory are then available to referenced in use statements across the Pagekit codebase.

  1. <?php
  2. use Pagekit\Hello\HelloExtension;

Mount controllers

Use the routes property to mount controllers to a route. Learn more about Routing and Controllers.

  1. 'routes' => [
  2.  
  3. '/hello' => [
  4. 'name' => '@hello/admin',
  5. 'controller' => [
  6. 'Pagekit\\Hello\\Controller\\HelloController'
  7. ]
  8. ]
  9.  
  10. ]

Define permissions

Your module can define permissions. These can then be assigned to roles in the Pagekit User & Permissions area.

The unique permission names you define (here hello: manage settings) are used as an identifier across the codebase. You can use this identifier to protect your routes from users who do not have this permission and prevent users from performing unauthorized actions.

  1. 'permissions' => [
  2.  
  3. 'hello: manage settings' => [
  4. 'title' => 'Manage settings'
  5. ]
  6.  
  7. ]

A simple way to then protect a controller action is by using an annotation as follows. Read about annotations to find out more.

  1. <?php
  2. class MyController {
  3. /**
  4. * @Access("hello: manage settings")
  5. */
  6. public function settingsAction() {
  7. }
  8. }

Register resource shorthands

You can register prefixes to be used as shorter versions when working with paths. For example use views:admin/settings.php to reference packages/VENDOR/PACKAGE/views/admin/settings.php. Pagekit registers a few paths for extensions and themes by default already.

This works whenever the Pagekit filesystem is used (i.e. when generating the url for a file path or rendering a view from a controller).

  1. 'resources' => [
  2.  
  3. 'views:' => 'views'
  4.  
  5. ],

Listen to events

Events are triggered at several points in the Pagekit core and potentially by other modules. An event always has a unique name that identifies it. You can register callback functions to any event.

For more information on the Event system, check out the Events section

  1. 'events' => [
  2.  
  3. 'view.scripts' => function ($event, $scripts) {
  4. $scripts->register('hello-settings', 'hello:app/bundle/settings.js', '~extensions');
  5. }
  6.  
  7. ]

Default module configuration

In many cases you want to allow the user to change settings for your module, for example by providing a settings screen. To make sure your module always has some configuration values right from the start, you can provide a default module configuration.

  1. 'config' => [
  2. 'default' => 'World'
  3. ],

Any changes to this configuration array will later be stored by the database. The default values are then always merged with the values from the database and the merge result will be available as the config property of the module object as you can see in the examples in the next two sections.

Read config

To read the config of a module, you can access the config property of the module instance. This object is the result of both the default config stored inside the index.php and changes that are stored in the database.

  1. $config = $app->module('hello')->config;

Write config

To store changes for a module config, use the config() service. These changes will automatically propagate to the database.

  1. // Complete config
  2. $app->config()->set('hello', $config);
  3.  
  4. // Single Value
  5. $app->config('hello')->set('message', 'Custom message');

Note. If you directly read the config from the module, it will still have the old value. After the next request, Pagekit will have merged the changes and made them available as the config property of the $module instance.

Register Nodes for Site Tree

Nodes are similar to routes with the main difference that they can be dragged around in the Site Tree View and therefore dynamically result in a calculated route.

When you have added a Node, it will be available in the Site Tree. Click the Add Page button to see the Dropdown of all available Node types.

For more information on nodes, check out the Routing section.

  1. 'nodes' => [
  2.  
  3. 'hello' => [
  4.  
  5. // The name of the node route
  6. 'name' => '@hello',
  7.  
  8. // Label to display in the admin panel
  9. 'label' => 'Hello',
  10.  
  11. // The controller for this node. Each controller action will be mounted
  12. 'controller' => 'Pagekit\\Hello\\Controller\\SiteController'
  13. ]
  14.  
  15. ]

Node options

If your module wants to add a configuration screen to the content editor in the Site Tree, you can use the node property to add default options to the node object (complete explanation for configuration screen in the Theme tutorial).

In the following example, a theme defines a top_style property which is automatically added to every node object that is rendered. By default, the property will have the value uk-block-muted, which is a CSS class that we want to render for the top position, in this example.

  1. 'node' => [
  2.  
  3. 'top_style' => 'uk-block-muted'
  4.  
  5. ],

When rendering a page in the template.php of the theme, you can then access that property from the $params array.

  1. <?php echo $params['top_style'] ?>

With the node property, you set the default value for every node. To allow the user to change these values, you will want to add an interface to the admin area (typically in the form of an addition Theme tab when editing a page's content).

To allow the user to change the values of the default widget options that you have defined here, you can add an interface to the admin area. To achieve that, you define a JavaScript component to display the editing screen (Example), register that JavaScript file on the content editor page (Example) and optionally update your Webpack configuration, if you are using Webpack (Example). A complete explanation for this can be found in the Theme tutorial.

Add menu items to the admin panel

You can add menu items to the admin panel's main navigation. These can link to any registered route and be limited to certain access permissions. The access property determines if the menu item is visible or not.

  1. 'menu' => [
  2.  
  3. // name, can be used for menu hierarchy
  4. 'hello' => [
  5.  
  6. // Label to display
  7. 'label' => 'Hello',
  8.  
  9. // Icon to display
  10. 'icon' => 'hello:icon.svg',
  11.  
  12. // URL this menu item links to
  13. 'url' => '@hello/admin',
  14.  
  15. // Optional: Expression to check if menu item is active on current url
  16. // 'active' => '@hello*'
  17.  
  18. // Optional: Limit access to roles which have specific permission assigned
  19. // 'access' => 'hello: manage hellos'
  20. ],
  21.  
  22. 'hello: panel' => [
  23.  
  24. // Parent menu item, makes this appear on 2nd level
  25. 'parent' => 'hello',
  26.  
  27. // See above
  28. 'label' => 'Hello',
  29. 'icon' => 'hello:icon.svg',
  30. 'url' => '@hello/admin'
  31. // 'access' => 'hello: manage hellos'
  32. ]
  33.  
  34. ],

Link to a route that renders your settings screen. Setting this property makes Pagekit render a Settings button next to your theme or extension in the admin panel listing.

  1. 'settings' => '@hello/admin/settings',

Register widgets

A widget is also a module. With the widgets property you can register all widget module definition files. Each of those files is expected to return a PHP array in the form of a valid module definition. Learn more about widgets.

  1. 'widgets' => [
  2.  
  3. 'widgets/form.php'
  4.  
  5. ],

Widget options

If your module wants to add a configuration screen to the widget editor (which is often the case when developing a theme), you can use the widget property to add default options to the widget object (a complete example for a widget configuration screen is in the Theme tutorial).

In the following example, a theme defines a panel property which is automatically added to every widget object that is rendered. By default, the property will have the empty string as its value.

  1. 'widget' => [
  2.  
  3. 'panel' => ''
  4.  
  5. ],

When rendering the widget, you can then access that property from the $widget->theme array.

  1. <?php echo $widget->theme['panel'] ?>

To allow the user, to change the values of the default widget options that you have defined here, you can add an interface to the admin area. To achieve that, you define a JavaScript component to display the editing screen (Example), register that JavaScript file on the widget editor page (Example) and optionally update your Webpack configuration, if you are using Webpack (Example). A complete explanation for this can be found in the Theme tutorial.