-
Notifications
You must be signed in to change notification settings - Fork 0
webrium plugin system
The Webrium plugin system allows you to package and distribute reusable components — controllers, models, views, assets, and more — as installable .zip archives. Plugins are managed entirely through the Webrium Console.
- How It Works
- Plugin Structure
- plugin.json Reference
- Creating a Plugin
- Commands
- Security
- Registry
- Backups
A plugin is a .zip file containing a plugin.json manifest and a src/ directory with the files to be installed. When you run plugin:install, the installer reads the manifest, validates all paths, runs any defined hooks, copies the files to their designated locations inside your Webrium project, and records the installation in a local registry.
Every plugin zip must follow this layout:
my-plugin.zip
├── plugin.json
└── src/
├── Controllers/
│ └── MyController.php
├── Models/
│ └── MyModel.php
├── Views/
│ └── my-view.html
└── Assets/
└── my-style.css
Rules:
-
plugin.jsonmust be in the root of the zip (not inside a subdirectory). - All installable files must be inside the
src/directory. - The
src/layout is up to you — the manifest maps each file to its destination individually.
{
"name": "my-plugin",
"version": "1.0.0",
"description": "A brief description of what this plugin does",
"author": "Your Name",
"require": {
"webrium": ">=1.0.0"
},
"files": [],
"hooks": {
"before_install": [],
"after_install": []
}
}| Field | Required | Description |
|---|---|---|
name |
Yes | Unique plugin identifier. Lowercase letters, numbers, -, _ only. |
version |
Yes | Semantic version string (e.g. 1.0.0, 2.1.4). |
description |
No | Short human-readable description. |
author |
No | Author name or contact. |
require |
No | Minimum framework version requirements. |
files |
Yes | Array of file entries defining what gets installed and where. |
hooks |
No | Console commands to run before or after installation. |
Each object in the files array describes one file to install:
{
"src": "Controllers/FileManagerController.php",
"dest": "controllers",
"subpath": "Plugins",
"overwrite": false
}| Field | Required | Description |
|---|---|---|
src |
Yes | Path to the file inside src/ in the zip archive. |
dest |
Yes | Destination directory key (see Destination Keys). |
subpath |
No | Optional subdirectory to create inside the destination. null to install directly. |
overwrite |
No | Whether to overwrite if the file already exists. Defaults to false. |
Example result: with dest: "controllers" and subpath: "Plugins", the file will be installed at:
app/Controllers/Plugins/FileManagerController.php
The dest field must be one of the following keys, which map to the standard Webrium directory structure:
| Key | Resolves To |
|---|---|
app |
app/ |
controllers |
app/Controllers/ |
models |
app/Models/ |
views |
app/Views/ |
routes |
app/Routes/ |
config |
app/Config/ |
middleware |
app/Middleware/ |
helpers |
app/Helpers/ |
services |
app/Services/ |
storage |
storage/ |
storage_app |
storage/App/ |
sessions |
storage/Framework/Sessions/ |
cache |
storage/Framework/Cache/ |
logs |
storage/Logs/ |
langs |
storage/Langs/ |
public |
public/ |
assets |
public/assets/ |
uploads |
public/uploads/ |
Using an unrecognized key will cause the installation to fail with a clear error message.
Hooks let you run Webrium Console commands automatically at two points in the installation lifecycle.
"hooks": {
"before_install": [
"make:model File --table=files"
],
"after_install": [
"make:controller FileManager",
"make:route Files"
]
}Each hook entry is a console command string — exactly what you would type after php webrium. The installer runs them internally through the Symfony Console Application, not through the system shell.
Allowed hook commands:
| Command | Description |
|---|---|
make:model |
Generate a model file |
make:controller |
Generate a controller file |
make:route |
Generate a route file |
init |
Initialize the project structure |
Any command outside this list will cause the installation to abort immediately. This is intentional — hooks cannot run arbitrary shell commands, access the filesystem directly, or execute system utilities.
Execution order:
before_install hooks
↓
file copy
↓
after_install hooks
If any hook command fails, the installation stops and reports the error.
my-plugin/
├── plugin.json
└── src/
Organize files however you like inside src/. The manifest will map them to their destinations individually.
my-plugin/
├── plugin.json
└── src/
├── Controllers/
│ └── FileManagerController.php
├── Models/
│ └── FileModel.php
└── Views/
└── file-manager.html
{
"name": "file-manager",
"version": "1.0.0",
"description": "File manager component for Webrium",
"author": "Your Name",
"files": [
{
"src": "Controllers/FileManagerController.php",
"dest": "controllers",
"subpath": "Plugins",
"overwrite": false
},
{
"src": "Models/FileModel.php",
"dest": "models",
"subpath": null,
"overwrite": false
},
{
"src": "Views/file-manager.html",
"dest": "views",
"subpath": "plugins",
"overwrite": true
}
],
"hooks": {
"before_install": [],
"after_install": []
}
}Zip the contents so that plugin.json is at the root level of the archive (not inside a parent folder):
# From inside the my-plugin/ directory:
zip -r my-plugin.zip plugin.json src/Verify the structure:
my-plugin.zip
├── plugin.json ← must be at root
└── src/
└── ...
php webrium plugin:info ./my-plugin.zipThis shows the full install plan, resolved destination paths, hook commands, and the SHA-256 checksum — without touching anything on disk.
php webrium plugin:install ./my-plugin.zipInstall a plugin from a local zip file or a remote URL.
php webrium plugin:install <source> [options]Source formats:
# Local file
php webrium plugin:install ./my-plugin.zip
# Direct HTTPS URL
php webrium plugin:install https://example.com/releases/my-plugin.zip
# GitHub release asset
php webrium plugin:install https://github.com/user/repo/releases/download/v1.0.0/my-plugin.zipOptions:
| Option | Description |
|---|---|
--force, -f |
Overwrite existing files without asking. |
--dry-run |
Preview the full install plan without writing anything. |
--no-backup |
Skip automatic backup of files that would be overwritten. |
The SHA-256 checksum of the zip is always displayed before any files are written.
If a file already exists and overwrite is false in the manifest, installation will stop and list the conflicts unless --force is passed.
Update an already-installed plugin to a newer version.
php webrium plugin:update <source> [options]The source format is identical to plugin:install.
Options:
| Option | Description |
|---|---|
--force, -f |
Update even if the new version is the same as or older than the installed one. |
--no-backup |
Skip backup of the current version before updating. |
The update process:
- Compares the zip SHA-256 against the stored hash — warns if the zip is identical.
- Compares version strings — warns if the new version is not newer.
- Backs up all currently installed files for this plugin.
- Removes files that exist in the old version but not in the new manifest.
- Copies all new files to their destinations.
- Updates the registry with the new version and file list.
Remove an installed plugin and delete its files from the project.
php webrium plugin:remove <name> [options]Options:
| Option | Description |
|---|---|
--no-backup |
Skip backup before deleting files. |
--keep-files |
Remove the plugin from the registry only; do not delete files from disk. |
A confirmation prompt is shown before any files are deleted.
Display a table of all installed plugins.
php webrium plugin:listOutput columns: Name, Version, Author, Files (count), Installed At, Updated At.
Preview a plugin's details and full install plan without installing it.
php webrium plugin:info <source>Displays:
- Plugin name, version, description, author.
- Installation status (whether it is already installed and at which version).
- A table showing each file, its resolved destination path, and whether a conflict exists.
- All
before_installandafter_installhook commands. - SHA-256 checksum of the zip.
The installer enforces the following constraints on every plugin, regardless of its source:
Path traversal prevention
All src paths and subpath values are resolved with realpath() and verified to remain inside the project root. A value like ../../etc/passwd or ../bootstrap/app.php will cause the installation to abort immediately.
Allowed file extensions
Only the following extensions may be installed: php, html, htm, js, css, json, md, txt, svg, xml. Any other extension causes an error.
Destination key whitelist
The dest field must be one of the recognized directory keys listed in Destination Keys. Arbitrary paths are not accepted.
Plugin name validation
Plugin names must match ^[a-z0-9\-_]+$. Names with special characters, slashes, or uppercase letters are rejected.
Archive limits
- Maximum zip size: 100 MB
- Maximum number of files inside the zip: 1,000
Hook command sandbox
Hook commands are limited to a fixed set of allowed Webrium Console commands. They are executed through the application's own command dispatcher — not through exec, shell_exec, or any other system call.
HTTPS only for remote sources
Remote URLs must use https://. Plain http:// URLs are rejected.
After installation, the plugin is recorded in:
storage/App/plugins.json
This file tracks every installed plugin and is used by plugin:update, plugin:remove, and plugin:list. Do not edit it manually unless you know what you are doing.
Example entry:
{
"installed": [
{
"name": "file-manager",
"version": "1.0.0",
"description": "File manager component for Webrium",
"author": "Your Name",
"installed_at": "2025-01-01 12:00:00",
"updated_at": null,
"hash": "a3f1c2d4e5b6...",
"files": [
"app/Controllers/Plugins/FileManagerController.php",
"app/Models/FileModel.php",
"app/Views/plugins/file-manager.html"
]
}
]
}Before overwriting existing files (during install or update) and before deleting files (during remove), the installer automatically creates a backup unless --no-backup is passed.
Backups are stored in:
storage/App/plugin-backups/<plugin-name>_<tag>_<timestamp>/
Each backed-up file has a .bak extension appended to its original filename. Backups are never deleted automatically.