Plugins and hierarchy
Introduction to hierarchy
Outlast Framework is built to use a hierarchical plugin system where it is easy to build, extend, and override features with separate modules.
Everything – including views, controllers, models, libraries, tag and filter definitions, etc. can be overridden in plugins or the current local application.
This may be confusing at first as you may have a few copies of similar files within a project, but fear not – below is an explanation of how to determine which is relevant and which is not.
In practice this means that if we have for example a view file in the system folder
/system/app/view/admin/base.html you can completely replace the contents of this file for your application by placing the file in your app folder
The framework will now completely ignore the system base.html and use your local base.html instead.
As with view files, you can also override system models, controllers, field definitions – just about anything.
Typically the hierarchy is processed in this order:
- System folder (first system plugins, then system apps)
- Plugin folders
- Local app folder
This means that anything in your system folder will be overridden by anything in the plugins folder which in turn will be overridden by anything in your app folder – so anything in your
/app folder is king.
Changing the order
You can change the order in which plugins are loaded in the global config file
$zajconf['plugin_apps'] = ['user', 'email', 'content'];
Plugins are loaded from back to front, so in the example above the
wordpress plugin will be loaded first, followed by
user, etc. In otherwords, anything found in ‘user’ will override anything similar in ‘wordpress’.
You can also change the order in which system plugins are loaded:
$zajconf['system_apps'] = ['_jquery', '_global'];
As above, the system plugins are processed from back to front. So any models or controllers in
_jquery that have the same hierarchical position and file name will override the one found in
Plugins as Git submodules
You can add a plugin as submodule. This allows you to easily update to the latest version while also sending updates back upstream.
To add a plugin as a submodule on SourceTree open up the repo, right click on
Submodules and click
Add submodule.... Fill in the
Source Path with the submodule repo’s url and set the
Local relative path to
Once the submodule has been added, simply follow the usual steps to activate the plugin (update in
Creating your own plugins
Modular features should be placed in their own separate plugin folders. This will allow you to reuse the code in multiple projects.
Creating plugins is really simple – basically you just need to create the subfolder in the
/plugins/ folder and then register the plugin in
- Create the folder
- Register the plugin in
$zajconf['plugin_apps'] = [ 'my_new_plugin'];
- Create the same folder as found in any plugin folders or as in you
- Start adding your own views, controllers, models, libraries, tags, filters, etc.
Here you will find an example folder structure for the content plugin. Notice there is no separate apps folder but everything is in root here.
Plugin assets folder
Plugin assets (css, jpg, js, etc. files) need to be placed in the plugin folder’s
site subfolder. So in the example above the style.css associated with your plugin would go in the
/plugins/my_new_plugin/site/style.css folder. Plugin assets can be accessed externally using the following url scheme:
Important! Plugin asset folders require a
.htaccess file in their
site folders with the following content to work properly:
If needed, you can use this or the global .htaccess file to change the URL scheme.
Plugin magic methods
Plugins can have special magic methods which are triggered during events like loading and installation. Plugin magic methods must be placed in the plugin’s main controller, which is a ctl file located in either
/plugins/your_plugin/controller/your_plugin/default.ctl.php. These controller methods can be overridden locally but the plugin controller file must exist in one of the above folders.
You can have the following magic methods (all are optional):
__plugin()– this magic method is called when the plugin is loaded up during a request. keep in mind that when this is called the
__load()method has not yet run and any plugins loaded afterwards are not yet available – including your local app folder. This means you should not access anything here that might be overridden locally (such as loading conf files or rerouting to other controllers). The parameters passed are $request, $app, $mode.
__install()– this magic method is called when the install script is running. You can use it to validate the plugin’s installation and send error messages about the install if needed. If you return a string, it will be treated as an error and displayed during OFW installation. No parameters are passed.
Extending vs overriding vs decoration
Extending – You can always extend any of the classes and view files found in your plugins. Extending classes will work like any standard PHP extension, while extending view files will work according to the logic of template inheritance.
Overriding – You can also completely override files by simply copying a plugin or system version to your local
/app folder. Because the app folder is more important than plugin or system folders, it will take precedence.
Decorating – You can also decorate models, controllers, and views. Unlike extension, decoration allows you to add features to the original model, controller, or view as defined in the system or one of your plugins while preserving the same name. In other words, you are not creating a new, similar object, but instead modifying the original. This is useful because any future bugfixes and enhancements to the original file will apply to your decorated version as well.