User Docs Developer Docs | |

WidgetService

Registered as service('widgets'). Manages widget discovery, database sync, and area rendering.

Methods

discover(): void

Scans the widgets/ directory for widget_info.json manifests. Inserts new widget records into the widgets table. Does not overwrite existing records.

sync(): void

Reconciles the widgets table with the filesystem. Marks widgets as unavailable if their directory or manifest no longer exists. Called automatically during discover().

renderArea(string $slug): string

Renders all active widget instances assigned to the named area slug. Returns concatenated HTML.

// In a theme layout or controller
$sidebar = service('widgets')->renderArea('sidebar');

Render Pipeline (renderArea)

For each widget instance in the area (ordered by sort_order):

  1. Load the widget record and its manifest from the widgets table
  2. Merge the instance's options_json with the manifest's schema defaults
  3. Call WidgetDataService::resolve($providers, $mergedOptions) to fetch provider data
  4. If any required context variable is missing, skip this instance (return empty string)
  5. Load views/widget.tpl from the widget's directory
  6. Render the template with the Pubvana template engine, passing: options, cls, and all provider-resolved variables
  7. Append rendered HTML to the output buffer

WidgetDataService::resolve()

WidgetDataService is a companion service (service('widgetData')). Its primary method:

resolve(array $providers, array $options): array

Returns an associative array of [variable_name => data] ready to merge into the template data bag.

Parameter mapping:

// Provider declaration:
// "posts": {"provider": "PostModel.getRecent", "params": {"limit": "count"}}
// options: {"count": "5"}
// Result: PostModel::getRecent(limit: 5)

Setting Context

Before calling renderArea(), controllers should set page context on WidgetDataService:

service('widgetData')->setContext([
    'current_post_id'   => $post->id,
    'current_author_id' => $post->user_id,
]);

Context is cleared after each renderArea() call to prevent bleed between areas on the same request.