Extension Points
Pubvana has three first-class extension types. Each is self-contained, auto-discovered, and managed through the admin UI. No core file edits are required to install or build any extension.
Important Changes for 2.2.x to 2.3.x
Folder as Identifier
As of v2.3.0, the addon's folder name is the canonical unique identifier. The slug field in *_info.json files is no longer read or used. Remove it from your theme_info.json, widget_info.json, and plugin_info.json files.
The folder name is used for:
- Vetting and safety checks
- Marketplace product resolution
- Update checks
- License validation
- All internal lookups
Comparison
| Feature | Plugin | Theme | Widget |
|---|---|---|---|
| PHP code | Yes | No | No |
| Routes | Yes | No | No |
| Admin UI | Yes | No | No |
| Database migrations | Yes | No | No |
| .tpl templates | Yes (public views) | Yes | Yes |
| CSS/JS assets | Yes (public/) | Yes (assets/) | Via theme |
| Manifest file | plugin_info.json |
theme_info.json |
widget_info.json |
| Directory | plugins/ |
themes/ |
widgets/ |
| Namespace | PluginsMyPlugin |
None | None |
| Activation required | Yes | Yes (one active) | Yes (per area) |
Plugins
Plugins are full MVC packages. They can do anything a core CI4 application can do:
- Define HTTP routes (public and admin)
- Add admin panel menu items
- Create database tables via migrations
- Render admin pages (Bootstrap 4 SB Admin 2 PHP views)
- Render public pages inside the active theme (.tpl templates)
- Register event listeners and CI4 service overrides
- Expose REST API endpoints
- Exempt specific routes from CSRF validation
Location: plugins/{PluginName}/
Namespace: Plugins{PluginName}
Entry point: Plugin.php implementing PluginInterface
Plugins are discovered by scanning the plugins/ directory, inserted into the plugins table as inactive, vetted (if the vetting service is configured), and then manually activated by an administrator.
Themes
Themes control the visual presentation of the public-facing site. They consist entirely of .tpl templates, CSS, JavaScript, and a JSON manifest — no PHP allowed in theme directories.
Location: themes/{folder}/
Entry point: theme_info.json
Required files: views/layout.tpl and seven page-type templates
Themes declare:
- Widget areas — named slots where widgets can be placed (
sidebar,footer-1, etc.) - CSS class mapping — 100+ semantic class keys mapped to actual CSS framework classes, decoupling widget/template structure from the CSS framework
- Options — configurable values (show sidebar, copyright text, etc.) with an auto-generated admin UI
Only one theme is active at a time. Switching themes is instant — no data migration required.
Widgets
Widgets are data-driven content blocks placed into theme widget areas. Each widget has:
widget_info.json— manifest declaring name, slug, version, and admin form optionsviews/widget.tpl— the template rendered in the widget area- Optionally a PHP data provider class that fetches data before rendering
Widgets are assigned to widget areas through the admin UI (Appearance → Widgets). Multiple instances of the same widget type can exist in different areas.
Location: widgets/{folder}/
Manifest: widget_info.json
Auto-Discovery
All three extension types are auto-discovered by scanning their respective directories:
PluginManager::discover() → scans plugins/
ThemeService::discover() → scans themes/
WidgetService::discover() → scans widgets/
Discovery reads the manifest JSON, validates required fields, and inserts a record into the database if one does not already exist. This means you can deploy an extension by copying its directory — no manual DB manipulation required.
No Core File Edits
Pubvana is designed so that extension developers never need to edit core files. All integration is driven by:
- The manifest JSON (declares metadata, capabilities)
PluginInterfacemethods (declare routes, menu items, exemptions)- CI4's event system (for hooks that don't fit the interface)
- The settings table (for configuration shared between core and plugins)