Data Providers
The data provider system is how widgets retrieve dynamic data without writing PHP. You declare what data you need in widget_info.json; WidgetDataService fulfils the request at render time.
How It Works
When WidgetService::renderArea($slug) processes a widget instance:
- It reads the
output.providersmap from the widget manifest - It calls
WidgetDataService::resolve($providers, $options)with the provider declarations and the current instance's option values WidgetDataServiceiterates the providers, instantiates the declared model, maps parameters, and calls the method- The returned data is merged into the template variable bag under the declared key name
Provider Declaration Format
"providers": {
"variable_name": {
"provider": "ModelName.methodName",
"params": {
"method_param_name": "option_key"
}
}
}
variable_name— the key available in the template (e.g.posts,categories,author)provider—ModelName.methodNamewhereModelNameis the CI4 model class (without namespace), andmethodNameis the public method to callparams— maps method parameter names to option keys; the resolved option value is passed as the argument
Parameter Mapping
The params object maps method parameter names (left side) to option keys (right side). At resolve time, the option value for the right-hand key is fetched and passed as the named argument.
"params": {"limit": "count"}
This calls PostModel::getRecent(limit: $options['count']) — so if the widget instance has count = "5", the call becomes getRecent(limit: 5).
Type coercion: WidgetDataService casts numeric strings to integers before passing to the model method.
Context Variables
Parameter values beginning with @ are context variables, not option keys. They are injected by the render pipeline based on the current page. See the Context Variables article for the full list.
"params": {"post_id": "@current_post_id"}
Whitelist
Not every Model.method pair is available. WidgetDataService maintains a whitelist of approved combinations. Attempting to declare a non-whitelisted provider causes the widget to render an empty string with an error logged to activity_logs.
Approved combinations (non-exhaustive):
| Provider string | Method signature |
|---|---|
PostModel.getRecent | getRecent(int $limit): array |
PostModel.getByCategory | getByCategory(int $category_id, int $limit = 5): array |
CategoryModel.getAll | getAll(): array |
TagModel.getPopular | getPopular(int $limit = 10): array |
AuthorProfileModel.getByUserId | getByUserId(int $user_id): ?object |
Contact the Pubvana team to request new provider whitelist additions.
Multiple Providers
A widget can declare multiple providers. Each resolves independently and injects its own variable:
"providers": {
"posts": {
"provider": "PostModel.getRecent",
"params": {"limit": "count"}
},
"categories": {
"provider": "CategoryModel.getAll"
}
}
Template:
{% for post in posts %}
{{ post.title }}
{% endfor %}
{% for cat in categories %}
{{ cat.name }}
{% endfor %}
Provider Failure Behaviour
If a provider throws an exception or returns null, WidgetDataService catches the exception, logs it to activity_logs, and sets the variable to an empty array. The widget continues rendering — it will hit the {% empty %} branch or the outer {% if %} guard.