User Docs Developer Docs | |

Widget Structure

Every widget is a self-contained directory under widgets/. The minimum viable widget has two files. Additional files are optional but supported.

Directory Layout

widgets/
  recent_posts/                  ← directory name = slug
    widget_info.json             ← required: manifest
    views/
      widget.tpl                 ← required: main render template
    Language/
      en/
        Widget.php               ← optional: i18n strings

No other file types are recognized or loaded by the widget system. PHP files in a widget directory are never executed — the widget engine does not scan for or autoload them.

widget_info.json

The manifest file. Must be valid JSON. Parsed by WidgetService::discover() when discovery is triggered. Keys:

  • name — human-readable display name (shown in admin)
  • slug — identifier, must match directory name
  • description — short description shown in admin widget list
  • version — semver string, stored in widgets.version column
  • min_pubvana_version, max_pubvana_version — compatibility bounds (advisory)
  • update_url — URL polled by the auto-update system for new versions
  • support_url — linked from admin widget detail
  • author — credit string
  • admin.options — option schema (drives the admin configuration form)
  • output.template — template file path relative to views/
  • output.providers — data provider declarations (optional)

views/widget.tpl

The template rendered by WidgetService::renderArea(). Uses the Pubvana template engine syntax (.tpl files, not PHP). Receives the following variables:

VariableTypeSource
optionsobjectWidget instance options merged with schema defaults
clsobjectCSS class mapping from the active theme
(provider keys)mixedResults from declared data providers

The template file name is set by output.template in the manifest. Convention is widget.tpl but any filename is valid.

Language Files

Optional. Place PHP array files at Language/en/Widget.php (or other locale codes). These are loaded by CI4's Lang service when the widget is rendered. Access strings in templates via {! lang "Widget.key" !}.

Example Language/en/Widget.php:

<?php
return [
    'no_posts' => 'No posts found.',
    'read_more' => 'Read More',
];

What Is NOT Supported

  • PHP class files — never executed
  • CSS or JS files — no asset pipeline for widgets; inline styles or theme-provided classes only
  • Sub-templates ({% include %} inside widget.tpl) — widget templates are standalone; includes reference the active theme's partials directory, not the widget directory
  • Widget-to-widget dependencies — each widget is isolated