Development Contract
Last updated: 2026-03-23
This document defines the official contract for community frontend themes in Pagify.
Scope
Frontend themes are stored at:
themes/main/{THEME_NAME}
This contract applies to:
- Theme discovery in admin Theme Manager
- Theme activation per site
- Public page rendering fallback chain
Directory Structure
A valid theme MUST follow this baseline structure:
themes/main/{slug}/
theme.json
README.md
assets/
js/
css/
img/
pages/
home.json
lang/
en/
theme.php
vi/
theme.php
Manifest Contract: theme.json
theme.json is mandatory.
Required fields
slugstring, max 120, regex:^[a-z0-9]+(?:-[a-z0-9]+)*$namestring, max 255versionstring, max 64
Optional fields
descriptionstringauthorstring, max 255requiresobjectsupportsobjectrenderobject withengineset towsre
Example
{
"slug": "default",
"name": "Default Main Theme",
"version": "1.0.0",
"description": "Default frontend theme for Pagify public pages.",
"author": "Pagify",
"render": {
"engine": "wsre"
},
"requires": {
"php": ">=8.2",
"laravel": "^12.0"
},
"supports": {
"pagify": "^1.0"
}
}
Runtime Behavior
Activation scope
- Active theme is resolved per site via setting key:
theme.main.active. - Admin can activate a theme for a target site.
Fallback chain
When rendering public pages, Pagify resolves theme view paths in order:
- Active theme for current site
- Config fallback theme (
FRONTEND_THEME_FALLBACK) - Config default theme (
FRONTEND_THEME)
A theme is considered runtime-usable only when:
- Theme directory exists
theme.jsonexists and passes validationtheme.json.slugmatches directory namerender.engineiswsrepages/home.jsonexists
If no usable page document is found after fallback chain, Pagify continues to fallback runtime sources (including page-builder published output).
Business Rules
- Default theme cannot be deleted (
THEME_LOCKED). - A theme currently active on any site cannot be deleted (
THEME_IN_USE). - Invalid manifest themes cannot be activated (
THEME_INVALID).
UX Requirements for Theme Manager
Theme Manager should clearly show:
- Manifest validity
- Current-site active status
- Usage count and active sites
- Delete eligibility and reason when disabled
Compatibility and Safe Updates
Theme authors should:
- Keep
theme.json.versionsemantic and updated - Avoid removing
pages/home.json - Test fallback behavior after changes
- Document breaking changes in
README.md
Troubleshooting Checklist
- Theme not listed in manager:
- Check
theme.jsonexists and valid JSON - Ensure
slugmatches folder name
- Theme cannot activate:
- Check manifest errors shown in manager
- Verify target site exists and active
- Theme selected but not rendered:
- Confirm
pages/home.jsonexists - Verify fallback theme/default theme manifests are valid
- Clear cache:
php artisan optimize:clear
Theme Asset Exposure
Frontend theme static assets are served from:
- Source folder:
themes/main/{THEME}/assets/{js,css,img} - Public URL pattern:
/theme-assets/{THEME}/{path}
Security rules:
- Only
js,css,imgtop-level directories are allowed. - Path traversal (
..) is blocked. - Theme manifest must be valid and slug must match directory.
Use in WSRE document nodes via plain URLs:
{
"tag": "link",
"attrs": {
"rel": "stylesheet",
"href": "/theme-assets/default/css/app.css"
}
}
Cache busting:
- Theme asset URLs support configurable strategies via
core.frontend_ui.assets.cache_busting.strategy. - Supported values:
mtime(default):?v={filemtime}hash:?v={sha1_file}(truncated byhash_length)off: do not append version query
- Config keys:
FRONTEND_THEME_ASSET_CACHE_BUSTING(mtime|hash|off)FRONTEND_THEME_ASSET_HASH_LENGTH(default12)
WSRE Dynamic Extensions
For runtime dynamic rendering, use WSRE resolver nodes and register resolvers via core WSRE resolver registry/hooks.