Plugins (extensions) in Seditio are flexible and lightweight software components designed to modify core behavior or add new features without directly editing the CMS's original files. This chapter discusses the hook concept, plugin directory structure, part manifest syntax, operation modes, and security.
8.1. Difference Between Plugins and Modules, and the Hook Concept
8.1.1. Modules vs. Plugins
- Modules: Large, independent content blocks (e.g., Pages, Forums, Gallery). They have dedicated controllers, their own entry point via the front controller (
index.php?module=module_name), and often have a standalone control panel. - Plugins: General-purpose extensions (e.g., captcha, anti-spam, statistics output, HTML compression). They run «under the hood» of the system, subscribing to specific extension points (hooks) of the core and modules.
8.1.2. How the Hook System Works
The hook system allows embedding plugin code into strictly defined locations in system files. In the Seditio core, extension points are marked with a special PHP comment and a call block:
/* === Hook === */
$extp = sed_getextplugins('hook_name');
if (is_array($extp)) {
foreach ($extp as $k => $pl) {
include(SED_ROOT . '/plugins/' . $pl['pl_code'] . '/' . $pl['pl_file'] . '.php');
}
}
/* ===== */
sed_getextplugins('hook_name', $cond): A core function that scans thesed_pluginstable in the database (which is cached in$sed_pluginsduring initialization) and returns a sorted array of active plugin files subscribed to this hook. The$condparameter (defaults to'R') specifies the required access permission level for the plugin to run.include(...): The core includes the PHP files of these plugins one by one. The plugin code runs in the same context (variable scope) as the calling core file itself, obtaining direct access to its global variables (e.g.,$usr,$cfg,$L,$tfor XTemplate).
8.2. Plugin Directory Structure and Parts
All plugins in Seditio reside in the plugins directory. The plugin folder must be named after its system code (written in lowercase, e.g., plugins/myplugin).
8.2.1. File Naming Conventions
Below is the standard directory structure of a custom plugin myplugin:
plugins/myplugin/
├── myplugin.setup.php # General manifest and configuration options
├── myplugin.install.php # SQL/PHP installation script (optional)
├── myplugin.uninstall.php # SQL/PHP uninstallation script (optional)
├── myplugin.urls.php # Plugin SEF URL rewrite/translation rules (optional)
├── myplugin.php # Executable file for a plugin part
├── myplugin.admin.php # Optional administration part file
├── admin/
│ └── myplugin.admin.menu.php # Returns sidebar menu item array (optional)
├── inc/
│ └── myplugin.functions.php # Plugin custom functions API (optional)
├── lang/
│ ├── myplugin.en.lang.php # English translations
│ └── myplugin.ru.lang.php # Russian translations
└── tpl/
├── myplugin.tpl # Template for standalone page mode (optional)
└── myplugin.admin.tpl # Template for plugin admin area (optional)
8.2.2. The Concept of Plugin Parts
Unlike other CMSs where a plugin is a single large file, in Seditio a plugin is divided into isolated parts. Each executable PHP file in the plugin folder (excluding setup, install, uninstall, and urls files) corresponds to a separate plugin part. For example, a plugin can validate a form during registration, log login events, and display a widget on the homepage:
- For form validation,
myplugin.register.phpis created (subscribes to theusers.register.add.firsthook). - For logging,
myplugin.login.phpis created (subscribes to theusers.auth.donehook). - For the widget,
myplugin.phpis created (subscribes to theindex.tagshook).
8.3. Plugin Setup Manifest {plugin_code}.setup.php
The .setup.php file (e.g., trashcan.setup.php) contains general metadata for the Seditio installer.
8.3.1. Installer Metadata ([BEGIN_SED_EXTPLUGIN])
This block registers the plugin in the system, defines dependencies, and configures default access rights:
/* ==================== [BEGIN_SED] File=plugins/myplugin/myplugin.setup.php Version=185 Updated=2026-apr-10 Type=Plugin Author=Developer Description=My custom plugin [END_SED] [BEGIN_SED_EXTPLUGIN] Code=myplugin ; Unique text code of the plugin Name=My Plugin ; Plugin name Description=Handles custom hooks ; Description Version=1.0.0 ; Version Date=2026-apr-10 ; Creation date Author=Developer ; Author Copyright= ; Copyright Notes= ; Notes SQL= ; Reserved Auth_guests=R ; Default guest rights (Read) Lock_guests=W12345A ; Locked guest rights Auth_members=R ; Default registered member rights (Read) Lock_members=W12345A ; Locked member rights Requires_modules=page,pfs ; Modules required (separated by commas, optional) Requires_plugins=tags ; Plugins required (separated by commas, optional) [END_SED_EXTPLUGIN] ==================== */
8.3.2. Plugin Configuration Options ([BEGIN_SED_EXTPLUGIN_CONFIG])
Declares settings that are output in the control panel at /admin/config?n=edit&o=plug&p=myplugin (or index.php?module=admin&m=config&n=edit&o=plug&p=myplugin without SEF URLs). Options are described using the following template: variable_name=order:type:values:default_value:description
Example:
[BEGIN_SED_EXTPLUGIN_CONFIG] limit=01:select:5,10,15,20:10:Limit of items to display enable_logs=02:radio:0,1:1:Log user activities custom_title=03:string::Widget Title:Title of the homepage block [END_SED_EXTPLUGIN_CONFIG]
These settings are automatically imported into the sed_config table on installation and are available in the code via the global array $cfg['plugin']['myplugin']['variable_name'].
8.4. Anatomy of Part Executable Files and Hook Registration
Each executable PHP file representing a plugin part (e.g., trashcan.admin.home.php) must contain a local manifest [BEGIN_SED_EXTPLUGIN] ... [END_SED_EXTPLUGIN] in its header.
8.4.1. Local Manifest of a Plugin Part
Example header content for myplugin.admin.php:
<?php
/* ====================
[BEGIN_SED]
File=plugins/myplugin/myplugin.admin.php
Version=1.0.0
Updated=2026-apr-10
Type=Plugin
[END_SED]
[BEGIN_SED_EXTPLUGIN]
Code=myplugin ; Plugin code this file belongs to
Part=admin ; Name identifier of this part
Hooks=admin.home.first ; System hooks to run on (separated by commas)
File=myplugin.admin ; Name of this PHP file (without extension)
Order=10 ; Execution priority (0..99, defaults to 10)
Lock=0 ; Lock flag: 1 - part cannot be disabled individually, 0 - yes
[END_SED_EXTPLUGIN]
==================== */
if (!defined('SED_CODE')) { die('Wrong URL.'); }
// PHP execution code...
- Multihooks Support: Since version 1.7.3, a single plugin part can subscribe to multiple hooks simultaneously. System hooks are separated by commas in the
Hooksparameter (e.g.,Hooks=index.tags,header.tags). You can also specify corresponding priorities in theOrderparameter (e.g.,Order=10,20orOrder=10for all). - The Lock Parameter: If
Lock=1is set, this part cannot be temporarily paused (disabled) in the control panel independently of the rest of the plugin.
8.4.2. Installer Registration Algorithm
When an administrator goes to /admin/plug (or index.php?module=admin&m=plug without SEF URLs):
- The installer scans the
/plugins/myplugin/folder and locates all.phpfiles (excluding setup, install, uninstall, and urls). - The
[BEGIN_SED_EXTPLUGIN]section is parsed from each PHP file. - For each part found, a record is inserted into the
sed_pluginsdatabase table with the following structure:pl_code— plugin code (myplugin).pl_part— part identifier (admin).pl_hook— hook name (admin.home.first).pl_file— associated filename (myplugin.admin).pl_order— execution priority (10).pl_active— part active status (1or0).pl_lock— lock flag (0or1).
- When the core executes the
admin.home.firsthook, an SQL query selects all active plugins for this hook sorted bypl_orderand includes their files.
8.5. Plugin Operation Modes
Depending on their purpose and hooks, plugins can operate in several modes:
8.5.1. Hook Mode (Event Handlers)
This is the classic mode. The plugin is embedded in the PHP backend execution flow.
- It can process arrays (e.g., sanitizing
$_POSTvariables before saving). - It can assign template TPL tags. For example, a part attached to
index.tagscan assign a value to a homepage placeholder:
$t->assign("MYPLUGIN_WIDGET", "Hello, this is plugin output!");
8.5.2. Standalone Mode
Allows a plugin to act as a full-featured isolated page of the website with standard design formatting. The plugin part must be registered to the standalone hook.
- Link to Plugin: The URL is generated as
/plug/myplugin(orindex.php?module=plug&e=mypluginwithout SEF URLs). - Routing: The request is redirected to the
system/core/plug/plug.phpcontroller, which reads theeparameter, checks access rights, and includes the standalone part (viasystem/core/plug/plug.inc.php). - Templating: The Seditio core automatically includes the global header
system/header.php(outputtingheader.tpl) before execution and the footersystem/footer.php(outputtingfooter.tpl) after execution. The plugin template file is searched for in the following order:- Skin directory:
skins/{skin_name}/{plugin_code}.tpl - Plugin directory:
plugins/{plugin_code}/{plugin_code}.tpl - System default template:
skins/{skin_name}/plugin.tpl(in this case,PLUGIN_TITLEandPLUGIN_BODYvariables are populated from the plugin code).
- Skin directory:
8.5.3. Direct Mode
Grants the plugin complete control over output formatting. The plugin part must be registered to the direct hook.
- Link to Plugin: Invoked similarly to standalone mode —
/plug/myplugin(orindex.php?module=plug&e=mypluginwithout SEF URLs). - Primary Difference: Unlike standalone mode, Seditio does not include the system
header.phpandfooter.phpfiles. The plugin runs directly, allowing the developer to output custom layouts, generate XML/RSS feeds, serve file downloads, or return JSON responses. - Access Rights: The core still checks access permissions before including the script.
8.5.4. Popup Mode
Used to run a plugin in a popup window with simplified styling. The part must be registered to the popup hook.
- Link to Plugin: Invoked at
/plug?o=myplugin(orindex.php?module=plug&o=mypluginwithout SEF URLs). - Features: The core includes the simplified template
popup.tpl(orskins/{skin_name}/popup.myplugin.tpl) and automatically passes the parent form/field name to the JS functionadd(text)to insert data (e.g., BB-codes or smilies).
8.5.5. AJAX Mode
Used to process background requests. The part must be registered to the ajax hook.
- Link to Plugin: Invoked at
/plug?ajx=myplugin(orindex.php?module=plug&ajx=mypluginwithout SEF URLs). - Features: No templates, headers, or footers are loaded. Only data printed directly by the plugin is returned (via
echoorexit).
8.5.6. Code Launchers (Manual Executables)
Allows running scripts without registering parts in the sed_plugins table.
- Link to Script: Invoked at
/plug?r=myscript(orindex.php?module=plug&r=myscriptwithout SEF URLs). - Features: Directly loads the PHP file at
plugins/code/myscript.php(if it exists). This is useful for utilities or administrative tasks running outside the hook architecture.
8.5.7. Plugin SEF URL Routing
A custom plugin can declare its own URL routing rules by creating a myplugin.urls.php file. The structure is identical to module URL files (see Chapter 6. Module Architecture and Development). Translation rules from this file are automatically imported during cache generation.
8.6. Installation, Menu Integration, and Access Control (ACL) Scripts
8.6.1. SQL and PHP on Installation (myplugin.install.php)
The myplugin.install.php script is run in a single click during installation. It handles table creation, importing default records, and checking folder write permissions:
<?php
if (!defined('SED_CODE') || !defined('SED_ADMIN')) { die('Wrong URL.'); }
// Creating custom table
$db_myplugin_table = $cfg['sqldbprefix'] . 'myplugin_table';
sed_sql_query("CREATE TABLE IF NOT EXISTS $db_myplugin_table (
log_id int(11) NOT NULL auto_increment,
log_text text NOT NULL,
PRIMARY KEY (log_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;");
The uninstallation script myplugin.uninstall.php performs the reverse operation — dropping tables when uninstalled.
8.6.2. Integrating Menu Links (admin/{plugin_code}.admin.menu.php)
If the plugin registers a section in the control panel (via the admin.plug hook), a file admin/myplugin.admin.menu.php is created to add a link to the sidebar, returning the menu configuration array:
<?php
if (!defined('SED_CODE')) { die('Wrong URL.'); }
return array(
'title' => 'My Plugin', // Menu item title
'order' => 15, // Sidebar sorting order
'adminlink' => sed_url('admin', 'm=myplugin'), // Link
'auth' => array('plug', 'myplugin', 'A'), // ACL check rule: area, code, option
'sections' => array() // Subsections (optional)
);
8.6.3. Access Control List (ACL) in Plugins
Plugin access permissions are configured in /admin/users per group. Upon installation, the system populates default permissions using the Auth_guests and Auth_members setup manifest parameters.
Within the plugin code (standalone, AJAX, or admin parts), the developer must validate the visitor's permissions:
// Check Read permission for the current plugin
// The first column 'plug' refers to the plugins area
list($usr['auth_read'], $usr['auth_write'], $usr['isadmin']) = sed_auth('plug', 'myplugin');
// Block access if Read permission is not granted
sed_block($usr['auth_read']);
This validation blocks unauthorized requests to the plugin.
Comments: (0)