Custom user plugins
Overview
The PluginManager
provides a framework for developers to create custom plugins to extend RaspAP's functionality. To facilitate this, the SamplePlugin
repository was created to make it easy for developers to get started creating their own plugins. Using the SamplePlugin
is described in the following sections.
The SamplePlugin
The SamplePlugin
implements a PluginInterface
and is automatically loaded by RaspAP's PluginManager
.
Several common plugin functions are demonstrated in SamplePlugin
, as well as a method for persisting session data in plugin instances. Each plugin has its own namespace, meaning that classes and functions are organized to avoid naming conflicts. Plugins are self-contained and render templates from inside their own /templates
directory.
Getting started
The SamplePlugin
requires an installation of RaspAP, either via the Quick install method or with a Docker container. The default application path /var/www/html
is used here. If you've chosen a different install location, substitute this in the steps below.
- Begin by creating a fork of the SamplePlugin repository.
- Change to your RaspAP install location and create a
/plugins
directory. - Change to the
/plugins
directory and clone yourSamplePlugin
fork: - The
PluginManager
will detect and autoload the plugin; a new Sample Plugin item will appear in the sidebar.
You may now proceed with customizing your plugin by using the tips in the next sections.
Scope of functionality
The SamplePlugin
implements the server-side methods needed to support basic plugin functionality. It initalizes a Sidebar
object and adds a custom navigation item. User input is processed with handlePageAction()
and several common operations are performed, including:
- Saving plugin settings.
- Starting a sample service.
- Stopping a sample service.
Template data is then collected in $__template_data
and rendered by the main.php
template file located in /templates
. Property get/set methods are demonstrated with apiKey
and serviceStatus
values. A method is then used in persistData()
to save the SamplePlugin
object data.
Caution
Importantly, SamplePlugin
does not use the PHP $_SESSION
object. Known as a "superglobal", or automatic global variable, this is available in all scopes throughout a script. Using the $_SESSION
object in a plugin context can lead to conflicts with other plugin instances.
On the front-end, Bootstrap's form validation is used to validate user input. A custom JavaScript function responds to a click event to generate a random apiKey
value. The sample.service
LED indicator is functional, as are the service stop/start form buttons.
Customizing
The SamplePlugin
demonstrates basic plugin functions without being overly complex. It's designed with best practices in mind and made to be easily modified by developers.
Unique plugin names
Most plugin authors will probably begin by renaming SamplePlugin
to something unique. The PluginManager
expects the plugin folder, file, namespace and class to follow the same naming convention. When renaming the SamplePlugin
ensure that each of the following entities uses the same plugin name:
Entity | Type |
---|---|
plugins/SamplePlugin |
folder |
plugins/SamplePlugin/SamplePlugin.php |
file |
namespace RaspAP\Plugins\SamplePlugin |
namespace |
class SamplePlugin implements PluginInterface |
class |
That is, replace each occurrence of SamplePlugin
with your plugin name in these entities.
Plugin logic and templates
Plugin classes and functions are contained in SamplePlugin.php
. The parent template main.php
and child tab templates are used to render template data.
├── SamplePlugin/
│ ├── SamplePlugin.php
│ └── templates/
│ ├── main.php
│ └── tabs/
│ ├── about.php
│ ├── basic.php
│ └── status.php
You may wish to omit, modify or create new tabs. This is done by editing main.php
and modifying the contents of the /tabs
directory.
Sidebar item
The PluginInterface
exposes an initalize()
method that is used to create a unique sidebar item. The properties below can be customized for your plugin:
$label = _('Sample Plugin');
$icon = 'fas fa-plug';
$action = 'plugin__'.$this->getName();
$priority = 65;
You may specify any icon in the Font Awesome 6.6 free library for the sidebar item. The priority value sets the position of the item in the sidebar (lower values = a higher priority).
Permissions
For security reasons, the www-data
user which the lighttpd
web service runs under is not allowed to start or stop daemons or execute commands. RaspAP's installer adds the www-data
user to sudoers, but with restrictions on what commands the user can run. If your plugin requires execute permissions on a Linux binary not present in RaspAP's sudoers file, you will need to add this yourself. To edit this file, the visudo
command should be used. This tool safely edits sudoers
and performs basic validity checks before installing the edited file.
Execute visudo
and edit RaspAP's sudoers file like so:
An example of adding entries to support a plugin's service is shown below:
www-data ALL=(ALL) NOPASSWD:/bin/systemctl start sample.service
www-data ALL=(ALL) NOPASSWD:/bin/systemctl stop sample.service
www-data ALL=(ALL) NOPASSWD:/bin/systemctl status sample.service
Wildcards ('*
') and regular expressions are supported by sudoers
but care should be taken when using them.
Multiple instances
The PluginManager
is a managerial class responsible for locating, instantiating and coordinating plugins. Through the use of namespaces and object data persistence in SamplePlugin
, any number of user plugins may be installed to /plugins
and run concurrently.
As previously noted, developers should avoid using PHP's $_SESSION
object in their plugins to prevent conflicts with other plugin instances. An alternative method for session data storage is provided in the SamplePlugin
persistData()
function.
Note
The persistData()
function writes serialized data to the volatile /tmp
directory which is cleared on each system boot. For this reason, it should not be used as a method of permanent data storage. However, this functionality roughly approximates PHP's $_SESSION
object; the difference being that each plugin's data is isolated from other plugin instances.
Publishing your plugin
The SamplePlugin
contains an "About" tab where you may provide author information, a description and link to your project. If you've authored a plugin you feel would be useful to the RaspAP community, you're encouraged to share it in the SamplePlugin
repository's discussions.
Discussions
Questions or comments about creating user plugins? Join the discussion here.