Plugin Manager
Short description of the plugin manager functionality
Make your plugin compatible with the Plugin Manager (Admidio 5)
In order to make your plugin compatible with the Plugin Manager certain requirements must first be met. These include:
- A consistent folder structure
- The use of the new plugin namespace Plugins
- A Plugin class that extends the new abstract class PluginAbstract with at least the doRender method
- A JSON configuration file
More requirements
Naming conventions
In order to use the new plugin namespace Plugins some naming conventions must be observed:
- Neither any folder of the plugin nor any file used by the plugin may contain delimiters like “-” or “_” especially if it should be used via a class import. For consistency reasons only the optional folder db_scripts (see: folder structure) should be an exception from this rule.
- For better readability file and folder names containing multiple words should follow the CamelCase notation.
Folder structure
The basic folder structure of any plugin is shown below using the overview plugin “Birthday” as example:
classes folder
Presenter classes
Plugin-specific classes
Inside the Presenter folder all necessary PagePresenter classes of the plugin took place. These should be simmilar to the module-specific PagePresenter classes.
Plugin preferences class
If the plugin provides preferences there should be a class “[PluginName]PreferencesPresenter” present. This class contains a single static preference method following the naming conventions of the Preferences class of Admidio.
Below an example snippet of the createBirthdayForm preference method from the Birthday overview plugin:
public static function createBirthdayForm(Smarty $smarty): string { global $gL10n, $gCurrentSession; $pluginBirthday = Birthday::getInstance(); $formValues = $pluginBirthday::getPluginConfig(); $formBirthday = new FormPresenter( 'adm_preferences_form_birthday', $pluginBirthday::getPluginPath() . '/templates/preferences.plugin.birthday.tpl', SecurityUtils::encodeUrl(ADMIDIO_URL . FOLDER_MODULES . '/preferences.php', array('mode' => 'save', 'panel' => 'birthday')), null, array('class' => 'form-preferences') ); $selectBoxEntries = array( '0' => $gL10n->get('SYS_DISABLED'), '1' => $gL10n->get('SYS_ENABLED'), '2' => $gL10n->get('ORG_ONLY_FOR_REGISTERED_USER') ); $formBirthday->addSelectBox( 'birthday_plugin_enabled', Language::translateIfTranslationStrId($formValues['birthday_plugin_enabled']['name']), $selectBoxEntries, array('defaultValue' => $formValues['birthday_plugin_enabled']['value'], 'showContextDependentFirstEntry' => false, 'helpTextId' => $formValues['birthday_plugin_enabled']['description']) ); $formBirthday->addCheckbox( 'birthday_show_names_extern', Language::translateIfTranslationStrId($formValues['birthday_show_names_extern']['name']), $formValues['birthday_show_names_extern']['value'], array('helpTextId' => $formValues['birthday_show_names_extern']['description']) ); [...] $formBirthday->addSubmitButton( 'adm_button_save_birthday', $gL10n->get('SYS_SAVE'), array('icon' => 'bi-check-lg', 'class' => 'offset-sm-3') ); $formBirthday->addToSmarty($smarty); $gCurrentSession->addFormObject($formBirthday); return $smarty->fetch($pluginBirthday::getPluginPath() . '/templates/preferences.plugin.birthday.tpl'); }
Entity, Service and ValueObjects classes
If the plugin has specific Entity, Service or ValueObjects classes these should be placed in the corresponding subfolders as it is done with the Admidio modules.
Main plugin class
The main plugin class (e.g. Birthday) has to take place directly in the classes folder. It extends the abstract class PluginAbstract by at least the doRender method. In it's simplest implementation the doRender method could just call the PagePresenter show method:
public static function doRender(?PagePresenter $page = null) : bool { if (!isset($page)) { throw new Exception("The page parameter must be set."); } $page->show(); return true; }
db_scripts folder
This folder is optional and is used to place plugin-specific database scripts used when installing (db-install.sql) or uninstalling(db-uninstall.sql) the plugin. In addition to possible database scripts update scripts (e.g.: update_1_0.xml) for the plugin could be placed in this folder. These should be structured like the update scripts used for Admidio to updateto a new version.
Simmilar to the update scripts used for Admidio it is possible to call plugin-specific update steps. To implement these methods a final class named UpdateStepsCode has to be present in the folder “[PluginName]\classes\Service\”. The class implementation should look like this:
final class UpdateStepsCode { /** * @var Database */ private static Database $db; /** * Set the database * @param Database $database The database instance */ public static function setDatabase(Database $database) { self::$db = $database; } /** * @throws Exception */ public static function /*[method name used in update_x_x.xml]*/() { [...] } }
languages folder
This folder contains the plugin specific translation files as before.
templates folder
To move away from the deprecated classes HtmlPage and HtmlTable plugins should exclusively use the Smarty template engine whose files are stored in this folder.
Root plugin folder
Main plugin file
Inside the root plugin folder a main plugin file is necessary. This file can contain plugin specific logic like the module entry files of Admidio or simply initialize the plugin class like following example:
<?php use Plugins\Birthday\classes\Birthday; /** *********************************************************************************************** * Birthday * * The plugin lists all users who have birthday in a defined timespan. * * @copyright The Admidio Team * @see https://www.admidio.org/ * @license https://www.gnu.org/licenses/gpl-2.0.html GNU General Public License v2.0 only *********************************************************************************************** */ try { require_once(__DIR__ . '/../../system/common.php'); $pluginBirthday = Birthday::getInstance(); $pluginBirthday->doRender(isset($page) ? $page : null); } catch (Throwable $e) { echo $e->getMessage(); }
Plugin configuration file
Each plugin has to provide a JSON configuration file containing basic plugin informations and configurations:
{ "name": "PLG_BIRTHDAY_PLUGIN_NAME", "description": "PLG_BIRTHDAY_PLUGIN_DESCRIPTION", "version": "1.0.0", "author": "Admidio Team", "url": "https://www.admidio.org", "icon": "bi-cake2", "mainFile": "index.php", "dependencies": [ "Admidio\\Infrastructure\\Plugins\\Overview", "Admidio\\Infrastructure\\Plugins\\PluginAbstract", "Admidio\\Infrastructure\\Utils\\SecurityUtils", "Admidio\\Roles\\Service\\RolesService" ], "defaultConfig": { "birthday_plugin_enabled": { "name": "ORG_ACCESS_TO_PLUGIN", "description": "ORG_ACCESS_TO_PLUGIN_DESC", "type": "integer", "value" : 1 }, "birthday_show_names_extern": { "name": "PLG_BIRTHDAY_PREFERENCES_SHOW_NAMES_EXTERN", "description": "PLG_BIRTHDAY_PREFERENCES_SHOW_NAMES_EXTERN_DESC", "type": "boolean", "value" : false }, "birthday_show_names": { "name": "PLG_BIRTHDAY_PREFERENCES_SHOW_NAMES", "description": "PLG_BIRTHDAY_PREFERENCES_SHOW_NAMES_DESC", "type": "integer", "value" : 0 }, "birthday_show_age": { "name": "PLG_BIRTHDAY_PREFERENCES_SHOW_AGE", "description": "PLG_BIRTHDAY_PREFERENCES_SHOW_AGE_DESC", "type": "boolean", "value" : false }, "birthday_show_age_salutation": { "name": "PLG_BIRTHDAY_PREFERENCES_SHOW_AGE_SALUTATION", "description": "PLG_BIRTHDAY_PREFERENCES_SHOW_AGE_SALUTATION_DESC", "type": "integer", "value" : 18 }, "birthday_show_notice_none": { "name": "PLG_BIRTHDAY_PREFERENCES_SHOW_NOTICE_NONE", "description": "PLG_BIRTHDAY_PREFERENCES_SHOW_NOTICE_NONE_DESC", "type": "boolean", "value" : true }, "birthday_show_past": { "name": "PLG_BIRTHDAY_PREFERENCES_SHOW_PAST", "description": "PLG_BIRTHDAY_PREFERENCES_SHOW_PAST_DESC", "type": "integer", "value" : 1 }, "birthday_show_future": { "name": "PLG_BIRTHDAY_PREFERENCES_SHOW_FUTURE", "description": "PLG_BIRTHDAY_PREFERENCES_SHOW_FUTURE_DESC", "type": "integer", "value" : 2 }, "birthday_show_display_limit": { "name": "PLG_BIRTHDAY_PREFERENCES_SHOW_DISPLAY_LIMIT", "description": "PLG_BIRTHDAY_PREFERENCES_SHOW_DISPLAY_LIMIT_DESC", "type": "integer", "value" : 200 }, "birthday_show_email_extern": { "name": "PLG_BIRTHDAY_PREFERENCES_SHOW_EMAIL_EXTERN", "description": "PLG_BIRTHDAY_PREFERENCES_SHOW_EMAIL_EXTERN_DESC", "type": "integer", "value" : 0 }, "birthday_roles_view_plugin": { "name": "PLG_BIRTHDAY_PREFERENCES_ROLES_VIEW_PLUGIN", "description": "PLG_BIRTHDAY_PREFERENCES_ROLES_VIEW_PLUGIN_DESC", "type": "array", "value" : ["All"] }, "birthday_roles_sql": { "name": "PLG_BIRTHDAY_PREFERENCES_ROLES_SQL", "description": "PLG_BIRTHDAY_PREFERENCES_ROLES_SQL_DESC", "type": "array", "value" : ["All"] }, "birthday_sort_sql": { "name": "PLG_BIRTHDAY_PREFERENCES_SORT_SQL", "description": "PLG_BIRTHDAY_PREFERENCES_SORT_SQL_DESC", "type": "string", "value" : "DESC" } } }
Configuration keys:
The following table provides a overview over possible configuration keys defined in the JSON file:
Key: | Mandatory: | Description: |
---|---|---|
“name” | X | Defines the plugin name (can be a translation ID or plain text). |
“description” | A short description of the plugin shown on the Plugin Manager overview. | |
“version” | X | The current version of the plugin. |
“author” | The author of the plugin. | |
“url” | A URL to a Wiki page or a projekt page. | |
“icon” | The icon displayed in the Admidio sidebar and on the Plugin Manager overview. | |
“mainFile” | The filename of the main plugin entry point. If not set “index.php” or “PluginName.php” is assumed. | |
“dependencies” | (X) | An array of all dependencies the plugin needs to work properly. If this is not set the Plugin Manager isn't able to detect whether the plugin can be installed properly. |
“defaultConfig” | (X) | An object containing all configuration parameters used by the plugin. Every parameter needs to contain a “name”, “descprition”, “type” and “value” key. |