A complete item field plugin
The pages of this guide:
- Item field plugins: start here
- Item field plugin events
- A complete item field plugin (this page)
This plugin adds a type named picker. It draws a field as radio buttons on the item page, for a variant field
and for an option, and nothing else. It is the shipped choice plugin reduced to one layout: every call in it
is one that choice makes. Every file is printed in full.
plugins/alfa-item-fields/picker/picker.xml
<?xml version="1.0" encoding="UTF-8"?>
<extension type="plugin" group="alfa-item-fields" method="upgrade">
<name>PLG_ALFA_ITEM_FIELDS_PICKER</name>
<author>Acme</author>
<creationDate>2026-11-12</creationDate>
<copyright>(C) 2026 Acme</copyright>
<license>GNU General Public License version 3 or later; see LICENSE</license>
<version>1.0.0</version>
<description>PLG_ALFA_ITEM_FIELDS_PICKER_XML_DESCRIPTION</description>
<namespace path="src">Acme\Plugin\AlfaItemFields\Picker</namespace>
<files>
<folder plugin="picker">services</folder>
<folder>src</folder>
<folder>tmpl</folder>
</files>
<languages folder="language">
<language tag="en-GB">en-GB/plg_alfa-item-fields_picker.ini</language>
<language tag="en-GB">en-GB/plg_alfa-item-fields_picker.sys.ini</language>
</languages>
</extension>
plugins/alfa-item-fields/picker/services/provider.php
<?php
defined('_JEXEC') or die;
use Acme\Plugin\AlfaItemFields\Picker\Extension\Picker;
use Joomla\CMS\Extension\PluginInterface;
use Joomla\CMS\Factory;
use Joomla\CMS\Plugin\PluginHelper;
use Joomla\DI\Container;
use Joomla\DI\ServiceProviderInterface;
return new class () implements ServiceProviderInterface {
public function register(Container $container): void
{
$container->set(
PluginInterface::class,
function (Container $container) {
$plugin = new Picker(
(array) PluginHelper::getPlugin('alfa-item-fields', 'picker'),
);
$plugin->setApplication(Factory::getApplication());
return $plugin;
},
);
}
};
plugins/alfa-item-fields/picker/src/Extension/Picker.php
<?php
namespace Acme\Plugin\AlfaItemFields\Picker\Extension;
defined('_JEXEC') or die;
use Alfa\Component\Alfa\Administrator\Event\ItemFields\ItemViewEvent;
use Alfa\Component\Alfa\Administrator\Plugin\ItemFieldsPlugin;
final class Picker extends ItemFieldsPlugin
{
// Declared by having the method: the base class reports it to Alfa.
public function onItemView($event): void
{
if (!$event instanceof ItemViewEvent) {
return;
}
$field = $event->getField();
$item = $event->getItem();
$fieldId = (int) $field->id;
$variant = $item->variant ?? null;
// A variant field: one dimension of the item's combinations.
if ($variant && in_array($fieldId, $variant->variantFieldIds ?? [], true)) {
$event->buyForm()
->setLayout('item-radio')
->variantSelector($fieldId)
->setData([
'field' => $field,
'values' => $field->values ?? [],
'selected' => (int) ($variant->selection[$fieldId] ?? 0),
'available' => $variant->availableValueIds[$fieldId] ?? [],
]);
return;
}
// An informational field has nothing to choose. This plugin does not draw it.
if (!empty($field->informational)) {
return;
}
// An option: only the values this item offers as extras.
$offered = [];
foreach ($item->options ?? [] as $option) {
$offered[(int) $option->value_id] = true;
}
$values = [];
foreach ($field->values ?? [] as $value) {
if (isset($offered[(int) $value->id])) {
$values[] = $value;
}
}
if ($values === []) {
return;
}
$chosen = array_flip(array_map('intval', $item->selectedOptionValueIds ?? []));
$selected = 0;
$available = [];
foreach ($values as $value) {
$available[(int) $value->id] = true;
if ($selected === 0 && isset($chosen[(int) $value->id])) {
$selected = (int) $value->id;
}
}
$event->buyForm()
->setLayout('item-radio')
->optionSelector($fieldId)
->setData([
'field' => $field,
'values' => $values,
'selected' => $selected,
'available' => $available,
]);
}
}
plugins/alfa-item-fields/picker/tmpl/item-radio.php
<?php
defined('_JEXEC') or die;
// $field, $values, $selected and $available come from setData().
// $inputName and $reloadScope are added by Alfa for the declared selector.
extract($displayData);
$esc = static fn ($v) => htmlspecialchars((string) $v, ENT_QUOTES, 'UTF-8');
?>
<div class="variant-field">
<span class="variant-field-label"><?php echo $esc($field->display_name); ?></span>
<div class="variant-options" role="radiogroup" aria-label="<?php echo $esc($field->display_name); ?>">
<?php foreach ($values as $value) :
$valueId = (int) $value->id;
$isAvailable = isset($available[$valueId]);
?>
<label class="variant-option<?php echo $isAvailable ? '' : ' is-unavailable'; ?>">
<input type="radio" name="<?php echo $esc($inputName); ?>"
value="<?php echo $valueId; ?>" data-item-reload="<?php echo $esc($reloadScope); ?>"
<?php echo $selected === $valueId ? 'checked' : ''; ?>
<?php echo $isAvailable ? '' : 'disabled'; ?>>
<span class="variant-option-label"><?php echo $esc($value->display_name); ?></span>
</label>
<?php endforeach; ?>
</div>
</div>
plugins/alfa-item-fields/picker/language/en-GB/plg_alfa-item-fields_picker.ini
PLG_ALFA_ITEM_FIELDS_PICKER="Alfa Item Fields - Picker"
PLG_ALFA_ITEM_FIELDS_PICKER_XML_DESCRIPTION="Adds the item field type 'picker' to Alfa Commerce: the values of a field as radio buttons."
plugins/alfa-item-fields/picker/language/en-GB/plg_alfa-item-fields_picker.sys.ini
PLG_ALFA_ITEM_FIELDS_PICKER="Alfa Item Fields - Picker"
PLG_ALFA_ITEM_FIELDS_PICKER_XML_DESCRIPTION="Adds the item field type 'picker' to Alfa Commerce: the values of a field as radio buttons."
What the sample relies on:
$item->variantis what the shopper's picks led to.variantFieldIdslists the fields that are dimensions of the item's combinations,selectionholds the chosen value per field, andavailableValueIdsholds, per field, the values that can still be reached with the other picks, as[value id => true].$item->optionslists the values the item offers as extras (value_id), andselectedOptionValueIdsthe ones chosen now.
Install the plugin, enable it, and leave its Access on Public. The type picker can then be chosen for a new
item field.