theme_info.json Reference
The theme manifest file. Read at discovery time and on every admin Themes page load.
Important Change 2.2.x to 2.3.x Same changes as plugin_info.json above — remove
slug, addfreefield, add required fields note, add URL fields table. Cron registration is plugin-only.
Complete Example
{
"name": "Default",
"version": "2.1.0",
"min_pubvana_version": "2.2.3",
"max_pubvana_version": "2.2.4",
"update_url": "https://pubvana.net/api/dstore/v1/update/check",
"author": "Pubvana",
"author_url": "https://pubvana.net",
"support_url": "https://pubvana.net/contact",
"description": "Clean Bootstrap 5 theme.",
"screenshot": "screenshot.png",
"css_framework": "Bootstrap",
"css_frame_ver": "5.x",
"icon_pack": "FontAwesome",
"icon_pack_ver": "6.x",
"js_framework": "Bootstrap",
"js_framework_ver": "5.x",
"widget_areas": {
"sidebar": "Main Sidebar",
"footer-1": "Footer Column 1",
"footer-2": "Footer Column 2",
"footer-3": "Footer Column 3",
"before-content": "Before Content"
},
"options": {
"show_sidebar": {
"type": "checkbox",
"label": "Show Sidebar",
"default": "1"
},
"footer_copyright": {
"type": "text",
"label": "Footer Copyright Text",
"default": ""
}
},
"css_class_mapping": {
"cls_widget": "widget mb-4",
"cls_title": "h6 fw-bold mb-3 pb-2 border-bottom",
"cls_btn_primary": "btn btn-primary",
"cls_pager_list": "pagination justify-content-center"
}
}
Metadata Fields
name
Type: string | Required: yes
Human-readable theme name. Displayed in the admin Themes gallery and the active theme indicator.
version
Type: string (semver) | Required: yes
Current theme version. Compared against update_url response for upgrade detection.
min_pubvana_version / max_pubvana_version
Type: string | Required: yes
Compatibility range. Activation is blocked below min, warning shown above max.
update_url
Type: string (URL) | Required: yes
Same contract as plugin update_url: POST { "folder": "...", "version": "..." }, expect { "has_update": bool, "latest_version": "...", "download_url": "..." }.
author, author_url, support_url
Type: string | Required: yes
Author name, author website URL, support/contact URL.
description
Type: string | Required: yes
One to three sentences. Shown in the Themes gallery.
screenshot
Type: string | Required: no (recommended)
Filename of the preview image relative to the theme root. Standard: "screenshot.png".
Framework Declarations
Informational — not enforced by the engine, but displayed in the admin UI and used by marketplace filters.
| Field | Example values |
|---|---|
css_framework |
"Bootstrap", "Tailwind", "Bulma", "None" |
css_frame_ver |
"5.x", "3.x" |
icon_pack |
"FontAwesome", "Bootstrap Icons", "None" |
icon_pack_ver |
"6.x", "5.x" |
js_framework |
"Bootstrap", "Alpine.js", "Vanilla" |
js_framework_ver |
"5.x", "3.x" |
widget_areas Object
Declares the named widget slots this theme supports. Keys are slugs (used in {! widget_area "slug" !}); values are human-readable labels shown in the admin Widgets UI.
"widget_areas": {
"sidebar": "Main Sidebar",
"footer-1": "Footer Column 1",
"footer-2": "Footer Column 2",
"footer-3": "Footer Column 3",
"before-content": "Before Content"
}
On theme activation, these areas are synced to the widget_areas database table. Widgets assigned to areas that no longer exist in the new theme's manifest are orphaned (not deleted, but not rendered).
options Object
Declares configurable theme options. The admin panel auto-generates a settings form from this schema. Values are stored per-theme in the theme_options table and accessible in templates as {{ theme_options.option_key }}.
Option Types
checkbox
"show_sidebar": {
"type": "checkbox",
"label": "Show Sidebar",
"default": "1"
}
Value is "1" (checked) or "0" (unchecked). Access: {{ theme_options.show_sidebar }} or {% if theme_options.show_sidebar %}.
text
"footer_copyright": {
"type": "text",
"label": "Footer Copyright Text",
"default": "© 2024 My Site"
}
select
"layout": {
"type": "select",
"label": "Layout",
"default": "sidebar-right",
"choices": {
"sidebar-right": "Sidebar Right",
"sidebar-left": "Sidebar Left",
"full-width": "Full Width"
}
}
textarea
"custom_css": {
"type": "textarea",
"label": "Custom CSS",
"default": ""
}
css_class_mapping Object
The most important and most extensive part of theme_info.json. Maps 100+ semantic keys to actual CSS class strings. Widgets and plugin templates use {{ cls.key_name }} instead of hardcoded CSS classes. This means widgets work across any CSS framework without modification.
Key Categories
Widget shell
"cls_widget": "widget mb-4",
"cls_title": "h6 fw-bold mb-3 pb-2 border-bottom",
"cls_widget_body": "widget-body"
Buttons
"cls_btn_primary": "btn btn-primary",
"cls_btn_secondary": "btn btn-secondary",
"cls_btn_success": "btn btn-success",
"cls_btn_danger": "btn btn-danger",
"cls_btn_sm": "btn btn-sm",
"cls_btn_lg": "btn btn-lg"
Layout
"cls_container": "container",
"cls_row": "row",
"cls_col": "col",
"cls_col_auto": "col-auto"
Cards
"cls_card": "card",
"cls_card_body": "card-body",
"cls_card_title": "card-title",
"cls_card_text": "card-text",
"cls_card_img_top": "card-img-top"
Typography
"cls_h1": "h1",
"cls_h2": "h2",
"cls_lead": "lead",
"cls_text_muted": "text-muted",
"cls_text_center": "text-center"
Lists
"cls_list_group": "list-group",
"cls_list_group_item": "list-group-item",
"cls_list_unstyled": "list-unstyled"
Forms
"cls_form_control": "form-control",
"cls_form_label": "form-label",
"cls_form_select": "form-select",
"cls_input_group": "input-group"
Alerts
"cls_alert_success": "alert alert-success",
"cls_alert_danger": "alert alert-danger",
"cls_alert_warning": "alert alert-warning",
"cls_alert_info": "alert alert-info"
Pagination
"cls_pager_list": "pagination justify-content-center",
"cls_pager_item": "page-item",
"cls_pager_link": "page-link"
Navigation / Breadcrumbs
"cls_nav": "nav",
"cls_nav_item": "nav-item",
"cls_nav_link": "nav-link",
"cls_breadcrumb": "breadcrumb",
"cls_breadcrumb_item": "breadcrumb-item"
Badges
"cls_badge": "badge",
"cls_badge_primary": "badge bg-primary",
"cls_badge_secondary":"badge bg-secondary"
The full mapping in the Default theme includes 100+ keys. Define all keys that any widget or plugin public template might reference. For keys you do not need, map them to an empty string "" or a safe neutral class.