Widget Parameters and Admin Configuration (widget.xml)
Widget Parameters and Admin Configuration (widget.xml)
~7 Min. Lesezeit Zuletzt aktualisiert am August 9, 2026
The widget from chapter 56 works, but it's hard-wired: the tier badge is always on, with no way for an editor to adapt it to a given page's design. This chapter makes exactly that configurable in the admin.
Parameter types at a glance
text/textarea- free text input, e.g. for additional CSS classes.select/multiselect- dropdown with fixed<option>values, typically also used for yes/no toggles (no dedicatedbooleantype exists).block- a chooser dialog letting an editor pick an existing CMS block instead of typing an ID by hand.url- link chooser, identical to the URL field in Page Builder.date- date picker, e.g. for time-limited promotions.
widget.xml with two real parameters
<?xml version="1.0"?>
<widgets xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Widget:etc/widget.xsd">
<widget id="mironsoft_loyalty_points_balance"
class="Mironsoft\Loyalty\Model\Widget\PointsBalanceWidget"
is_email_compatible="false">
<label translate="true">Loyalty: My Points Balance</label>
<description translate="true">Displays the logged-in customer's points balance and loyalty tier.</description>
<parameters>
<parameter name="show_tier_badge" xsi:type="select" visible="true" required="false" sort_order="10">
<label translate="true">Show Loyalty Tier Badge</label>
<options>
<option name="yes" value="1" selected="true">
<label translate="true">Yes</label>
</option>
<option name="no" value="0">
<label translate="true">No</label>
</option>
</options>
</parameter>
<parameter name="css_class" xsi:type="text" visible="true" required="false" sort_order="20">
<label translate="true">Additional CSS Classes</label>
</parameter>
</parameters>
</widget>
</widgets>The widget class reads the parameters
<?php
declare(strict_types=1);
namespace Mironsoft\Loyalty\Model\Widget;
use Magento\Framework\View\Element\Template;
use Magento\Framework\View\Element\Template\Context;
use Magento\Widget\Block\BlockInterface;
use Mironsoft\Loyalty\ViewModel\PointsBalance;
/**
* Renders the "My Points" widget insertable into any CMS WYSIWYG content. Delegates all
* business logic to ViewModel\PointsBalance (chapter 48); the two getters added in this
* chapter (getShowTierBadge()/getCssClass()) expose only admin-configured presentation
* parameters that have no equivalent on the view model itself.
*/
class PointsBalanceWidget extends Template implements BlockInterface
{
/**
* @param Context $context Framework template context, required by the parent Template class.
* @param PointsBalance $pointsBalanceViewModel Same view model already used in chapters 48/51/52 - reused unmodified here.
* @param array<string, mixed> $data Additional block data, populated by Magento's widget system from the admin-configured parameters below.
*/
public function __construct(
Context $context,
private readonly PointsBalance $pointsBalanceViewModel,
array $data = [],
) {
parent::__construct($context, $data);
$this->setTemplate('Mironsoft_Loyalty::widget/points-balance-widget.phtml');
}
/**
* Returns the injected view model.
*
* @return PointsBalance
*/
public function getViewModel(): PointsBalance
{
return $this->pointsBalanceViewModel;
}
/**
* Whether the tier badge should render, defaulting to true when the admin left the
* parameter unset (e.g. a widget instance saved before this parameter existed).
*
* @return bool
*/
public function getShowTierBadge(): bool
{
$value = $this->getData('show_tier_badge');
return $value === null || (bool) $value;
}
/**
* Returns any additional CSS classes configured in the admin, empty string if none.
*
* @return string
*/
public function getCssClass(): string
{
return (string) ($this->getData('css_class') ?? '');
}
}Achtung: From here on, $this->setTemplate() points at a NEW file, widget/points-balance-widget.phtml, instead of continuing to use widget/points-balance.phtml from chapter 53. Reason: Magento\Framework\View\Element\AbstractBlock extends \Magento\Framework\DataObject and inherits the same __call() magic chapter 49 already explained for AbstractModel::getData() - the generic Template block from chapters 51/52 would therefore also accept $block->getShowTierBadge() without error, just always returning null instead of a real default. Letting one and the same template file behave differently and silently across two contexts is exactly the kind of unnecessary coupling chapter 49 already warned about - hence a clean split as soon as the template contracts genuinely diverge.
<?php
declare(strict_types=1);
use Magento\Framework\Escaper;
use Mironsoft\Loyalty\Model\Widget\PointsBalanceWidget;
use Mironsoft\Loyalty\ViewModel\PointsBalance;
/**
* @var PointsBalanceWidget $block
* @var Escaper $escaper
*/
/** @var PointsBalance $viewModel */
$viewModel = $block->getViewModel();
?>
<?php if ($viewModel->canShow()): ?>
<div class="my-4 rounded-xl border border-gray-200 bg-white p-4 shadow-sm sm:p-6 <?= $escaper->escapeHtmlAttr($block->getCssClass()) ?>">
<dl class="flex flex-col gap-1 sm:flex-row sm:items-baseline sm:justify-between">
<div>
<dt class="text-sm font-medium text-gray-500">
<?= $escaper->escapeHtml(__('Your points balance')) ?>
</dt>
<dd class="text-3xl font-bold tracking-tight text-gray-900">
<?= $escaper->escapeHtml($viewModel->getFormattedPointsBalance()) ?>
</dd>
</div>
<?php if ($block->getShowTierBadge()): ?>
<span class="inline-flex w-fit items-center rounded-full bg-amber-100 px-3 py-1 text-sm font-semibold capitalize text-amber-800">
<?= $escaper->escapeHtml($viewModel->getTier()) ?>
</span>
<?php endif; ?>
</dl>
</div>
<?php endif; ?>Admin configuration in practice
- Content > Elements > Widgets > "Add Widget" - pick the "Loyalty: My Points Balance" widget type.
- Set the design theme and store view assignment (the standard widget instance fields, the same for every widget).
- "Widget Options" tab:
show_tier_badgeandcss_classshow up automatically as form fields - generated directly fromwidget.xml, no admin form of our own needed. - "Layout Updates" tab: pick the page or container where the widget should appear - internally generates the layout XML update from chapter 55.
Alternatively: click "Insert Widget" directly in any CMS page's WYSIWYG editor - the same parameter dialog appears as a modal there, and the result lands as a {{widget type="Mironsoft\Loyalty\Model\Widget\PointsBalanceWidget" show_tier_badge="1"}} directive right in the page content, with no saved widget instance at all.
Tipp: After every widget.xml change: bin/cache-clean config. After every template change, bin/cache-clean block_html is enough - both cache types independent of each other, same as in previous blocks of this series.
Achtung: css_class and show_tier_badge are purely presentational - they change nothing about the full page cache danger described in chapter 56 for customer-specific widgets on public pages. That warning applies unchanged no matter which parameters are set in the admin.