This skill guides the creation of custom field types and field handlers for Hyvä CMS components. Custom field types extend the built-in field types (text, textarea, select, etc.) with specialized input controls for the CMS editor interface.
Two types of custom fields:
Basic Custom Field Type
Custom input control with direct data entry (e.g., date range, color picker, custom validation)
Field Handler
Enhanced UI with complex interactions (e.g., product selector with images, searchable dropdown, link configuration modal)
Command execution:
For commands that need to run inside the development environment (e.g.,
bin/magento
), use the
hyva-exec-shell-cmd
skill to detect the environment and determine the appropriate command wrapper.
Workflow
Step 1: Module Selection
If not already specified in the prompt, determine where to create the custom field type:
Option A: New Module
Use the
hyva-create-module
skill with:
dependencies
:
["Hyva_CmsBase", "Hyva_CmsLiveviewEditor"]
composer_require
:
{"hyva-themes/commerce-module-cms": "^1.0"}
Option B: Existing Module
Verify the module has required dependencies:
Hyva_CmsBase
and
Hyva_CmsLiveviewEditor
in
etc/module.xml
hyva-themes/commerce-module-cms
in
composer.json
Add missing dependencies if needed.
Step 2: Field Type Details
Gather information about the custom field type:
Field type name
(lowercase identifier, e.g.,
date_range
,
product_selector
,
color_picker
)
Purpose
(what data does it collect?)
UI pattern
:
Basic field
Simple input with validation (date picker, pattern input, enhanced text field)
Inline handler
Enhanced control in field area (searchable dropdown, color picker)
Modal handler
Separate dialog for complex selection (product selector, link builder, media gallery)
Data structure
(simple string, JSON object, array?)
Validation requirements
(pattern, required, custom rules?)
Step 3: Implementation Pattern Selection
Based on the UI pattern identified in Step 2:
Pattern A: Basic Custom Field Type
For simple inputs with custom HTML5 validation or specialized input controls:
Single template file for the field
No separate handler modal
Example: Date range selector, custom pattern validation, slider input
Pattern B: Inline Field Handler
For enhanced controls that remain in the field area:
Single template file with Alpine.js component
No separate handler modal
Example: Searchable select dropdown, color picker with swatches
Pattern C: Modal-Based Field Handler
For complex selection interfaces requiring more space:
Field template (displays selection + trigger button)
Handler modal template (separate dialog with full UI)
Layout XML registration for the handler
Example: Product selector, link configuration, media gallery
See
references/handler-patterns.md
for detailed implementation patterns and code examples for each type.
Use null coalescing for field value:
$block->getData('value') ?? ''
(NOT type casting)
Use the appropriate template from
assets/templates/
:
basic-field.phtml.tpl
- Basic custom field type
inline-handler.phtml.tpl
- Inline enhanced control
modal-field.phtml.tpl
- Modal handler field template
See
references/template-requirements.md
for detailed template requirements and patterns.
Step 5: Generate Handler Modal (if needed)
For modal-based handlers only, create the handler template at
view/adminhtml/templates/handlers/[handler-name]-handler.phtml
.
Handler modal structure:
container ensures the handler modal is loaded at the end of the page body, which is required for proper Alpine.js initialization and modal functionality
CRITICAL: Field Value Type Handling
NEVER use type casting for field values, always use null coalescing operator
✅ Correct:
$fieldValue = $block->getData('value') ?? '';
❌ Incorrect:
$fieldValue = (string) $block->getData('value');
Type casting
(string)
will fail when value is
null
, causing PHP errors
Use
?? ''
for string values,
?? []
for array values, or appropriate default for your data type
Reference: See built-in field types like
category.phtml
which use
?? []
pattern
CRITICAL: Dialog Modal Classes
Handler modals must use
open:flex
not static
flex
class
✅ Correct:
❌ Incorrect:
(modal always visible)
The
open:
prefix applies styles only when dialog is open (native HTML dialog state)
Reference: See built-in handlers like
category-handler.phtml
which use
open:flex flex-col
CRITICAL: Complex Data Type Handling
For fields storing JSON/array data, handle BOTH array and string types
Field values may be returned as already-decoded arrays OR as JSON strings (depends on storage/context)
✅ Correct pattern:
$data
=
[
'default'
=>
'structure'
]
;
if
(
$fieldValue
)
{
if
(
is_array
(
$fieldValue
)
)
{
$data
=
$fieldValue
;
// Already decoded
}
elseif
(
is_string
(
$fieldValue
)
)
{
$decoded
=
json_decode
(
$fieldValue
,
true
)
;
if
(
is_array
(
$decoded
)
)
{
$data
=
$decoded
;
}
}
}
// When outputting to hidden input, ALWAYS ensure it's a JSON string
$fieldValueJson
=
is_array
(
$fieldValue
)
?
json_encode
(
$fieldValue
)
:
$fieldValue
;
❌ Incorrect:
json_decode($fieldValue)
without type checking (fails if value is already an array)
❌ Incorrect: Using array directly in
value
attribute without JSON-encoding first