Skip to content
intermediate Phase 31 · Admin & System XML

system.xml Deep Dive

Sections, groups, fields, field types (text, boolean, select, multiselect, image), and backend models.

1h
0 problems
Topic Progress 0%

Section, Group, Field Hierarchy

system.xml follows a three-level hierarchy: Section → Group → Field.

Complete section example:

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Config:etc/system_file.xsd">
    <system>
        <section id="vendor_shipping" type="text" sortOrder="300"
                 showInDefault="1" showInWebsite="1" showInStore="0">
            <label>Vendor Shipping</label>
            <tab>sales</tab>
            
            <group id="general" type="text" sortOrder="10"
                    showInDefault="1" showInWebsite="1" showInStore="0">
                <label>General Settings</label>
                
                <field id="enabled" type="select" sortOrder="10"
                       showInDefault="1" showInWebsite="1" showInStore="0">
                    <label>Enable Module</label>
                    <source_model>Magento\Config\Model\Config\Source\Yesno</source_model>
                </field>
            </group>
            
            <group id="rates" type="text" sortOrder="20"
                    showInDefault="1" showInWebsite="0" showInStore="0">
                <label>Shipping Rates</label>
                
                <field id="flat_rate" type="price" sortOrder="10"
                       showInDefault="1" showInWebsite="0" showInStore="0">
                    <label>Flat Rate Fee</label>
                    <backend_model>Magento\Config\Model\Config\Backend\Price</backend_model>
                </field>
            </group>
        </section>
    </system>
</config>

Hierarchy levels:

Section (id="vendor_shipping")
├── Group (id="general")
│   ├── Field (id="enabled")
│   └── Field (id="title")
└── Group (id="rates")
    ├── Field (id="flat_rate")
    └── Field (id="free_threshold")

Field Types

system.xml supports various field types for different input needs.

Text field:

<field id="api_key" type="text" sortOrder="10" showInDefault="1">
    <label>API Key</label>
    <validate>required-entry</validate>
</field>

Boolean (Yes/No):

<field id="enabled" type="select" sortOrder="10" showInDefault="1">
    <label>Enable Module</label>
    <source_model>Magento\Config\Model\Config\Source\Yesno</source_model>
</field>

Select (dropdown):

<field id="shipping_method" type="select" sortOrder="20" showInDefault="1">
    <label>Default Method</label>
    <source_model>Vendor\Module\Model\Config\Source\ShippingMethods</source_model>
</field>

Multiselect:

<field id="allowed_countries" type="multiselect" sortOrder="30" showInDefault="1">
    <label>Allowed Countries</label>
    <source_model>Magento\Directory\Model\Config\Source\Country</source_model>
    <backend_model>Magento\Config\Model\Config\Backend\Serialized\ArraySerialized</backend_model>
</field>

Textarea:

<field id="custom_css" type="textarea" sortOrder="40" showInDefault="1">
    <label>Custom CSS</label>
    <backend_model>Magento\Config\Model\Config\Backend\Textarea</backend_model>
</field>

Image upload:

<field id="logo_image" type="image" sortOrder="50" showInDefault="1">
    <label>Logo Image</label>
    <backend_model>Magento\Config\Model\Config\Backend\Image</backend_model>
    <upload_dir>vendor/logo</upload_dir>
</field>

Obscure (password-like):

<field id="secret_key" type="obscure" sortOrder="60" showInDefault="1">
    <label>Secret Key</label>
    <backend_model>Magento\Config\Model\Config\Backend\Encrypted</backend_model>
</field>

Price:

<field id="handling_fee" type="price" sortOrder="70" showInDefault="1">
    <label>Handling Fee</label>
    <backend_model>Magento\Config\Model\Config\Backend\Price</backend_model>
</field>

Backend Models

Backend models handle save logic, validation, and data processing for configuration values.

Custom backend model:

<?php
namespace Vendor\Module\Model\Config\Backend;

class ApiKey extends \Magento\Config\Model\Config\Backend\AbstractBackend
{
    public function afterSave(): void
    {
        $value = $this->getValue();
        
        // Validate API key format
        if (!preg_match('/^[A-Za-z0-9]{32}$/', $value)) {
            throw new \Magento\Framework\Exception\LocalizedException(
                __('API Key must be 32 alphanumeric characters')
            );
        }
        
        // Process after save
        $this->cacheClean();
    }
    
    public function beforeSave(): void
    {
        $value = $this->getValue();
        
        // Trim whitespace
        $this->setValue(trim($value));
    }
    
    private function cacheClean(): void
    {
        // Clear relevant cache
    }
}

Backend model in system.xml:

<field id="api_key" type="obscure" sortOrder="20" showInDefault="1">
    <label>API Key</label>
    <backend_model>Vendor\Module\Model\Config\Backend\ApiKey</backend_model>
</field>

Built-in backend models:

Backend Model Purpose
Magento\Config\Model\Config\Backend\Price Price validation
Magento\Config\Model\Config\Backend\Image Image upload handling
Magento\Config\Model\Config\Backend\Textarea Textarea processing
Magento\Config\Model\Config\Backend\Encrypted Encryption for sensitive data
Magento\Config\Model\Config\Backend\Serialized\ArraySerialized Serialized array storage
Magento\Config\Model\Config\Backend\Note Display note/message

Backend model lifecycle:

1. User submits config form
2. beforeSave() called
3. Value validated
4. afterSave() called
5. Value stored in core_config_data

Source Models and Custom Options

Source models provide options for select and multiselect fields.

Custom source model:

<?php
namespace Vendor\Module\Model\Config\Source;

class ShippingMethods implements \Magento\Framework\Option\ArrayInterface
{
    public function toOptionArray(): array
    {
        return [
            ['value' => 'flat', 'label' => __('Flat Rate')],
            ['value' => 'free', 'label' => __('Free Shipping')],
            ['value' => 'table', 'label' => __('Table Rates')],
        ];
    }
}

Source model in system.xml:

<field id="shipping_method" type="select" sortOrder="20" showInDefault="1">
    <label>Default Method</label>
    <source_model>Vendor\Module\Model\Config\Source\ShippingMethods</source_model>
</field>

Dynamic source model (from database):

<?php
namespace Vendor\Module\Model\Config\Source;

class Countries implements \Magento\Framework\Option\ArrayInterface
{
    public function __construct(
        private \Magento\Directory\Model\ResourceModel\Country\CollectionFactory $countryCollection
    ) {}
    
    public function toOptionArray(): array
    {
        $countries = $this->countryCollection->create()->loadByStore();
        $options = [];
        
        foreach ($countries as $country) {
            $options[] = [
                'value' => $country->getId(),
                'label' => $country->getName()
            ];
        }
        
        return $options;
    }
}

Built-in source models:

Source Model Options
Magento\Config\Model\Config\Source\Yesno Yes/No
Magento\Config\Model\Config\Source\Enabledisable Enable/Disable
Magento\Config\Model\Config\Source\Locale All locales
Magento\Config\Model\Config\Source\Store All stores
Magento\Directory\Model\Config\Source\Country All countries

Validation rules:

<!-- required-entry: Must have value -->
<validate>required-entry</validate>

<!-- validate-email: Must be valid email -->
<validate>validate-email</validate>

<!-- validate-url: Must be valid URL -->
<validate>validate-url</validate>

<!-- validate-number: Must be numeric -->
<validate>validate-number</validate>

<!-- Multiple validations -->
<validate>required-entry validate-number validate-digits</validate>

Quiz

1. What field type is used for Yes/No options?

Question 1 options

2. What method does a backend model call after saving a value?

Question 2 options

3. Which field type should be used for image uploads?

Question 3 options

4. What interface do source models implement?

Question 4 options

Flashcards

Question

What are the three levels of system configuration?

Answer

Section → Group → Field

Question

What field type handles Yes/No selections?

Answer

select with Magento\Config\Model\Config\Source\Yesno

Question

What is a backend model responsible for?

Answer

Save logic, validation, and data processing for config values

Question

What validation rule makes a field required?

Answer

required-entry

Question

Where is system.xml located in a module?

Answer

Vendor/Module/etc/adminhtml/system.xml

Revision Notes

Key Takeaways

  • 1. system.xml follows Section → Group → Field hierarchy
  • 2. Field types: text, select, multiselect, textarea, image, price, obscure
  • 3. Source models provide dropdown options via toOptionArray()
  • 4. Backend models handle beforeSave/afterSave logic
  • 5. Visibility controlled by showInDefault/showInWebsite/showInStore
  • 6. Validate attribute supports multiple validation rules

Interview Tips

  • Explain the section/group/field hierarchy
  • Describe how to create custom source and backend models
  • Know the difference between all field types
  • Discuss scope configuration (default, website, store)

Cheat Sheet

system.xml Cheat Sheet

Field types:

  • text: Text input
  • select: Dropdown (with source_model)
  • multiselect: Multiple selections
  • textarea: Multi-line text
  • image: Image upload
  • price: Price with validation
  • obscure: Masked input (passwords)

Source model:

class MySource implements ArrayInterface
{
    public function toOptionArray(): array { ... }
}

Backend model:

class MyBackend extends AbstractBackend
{
    public function afterSave(): void { ... }
}

Visibility:
showInDefault="1" showInWebsite="1" showInStore="0"

Validation:
required-entry validate-email