sbodak / magento2-checkout-custom-form
sbodak/magento2-checkout-custom-form
Add a custom form to Magento 2 checkout on the shipping step.
Magento 2 – Checkout Custom Form
Overview
Adds a configurable custom form to the Magento 2 checkout (shipping step), placed above the shipping-method selection.
The form works for both logged-in customers and guests.
After an order is placed, all entered data is stored in the sales_order table and exposed via extension attributes on OrderInterface.
Form data persists through page refreshes as long as the cart is active.
Fields can be individually enabled or disabled per store view from the admin panel.
Optional character-length limits can be configured for each field.
Default form fields
| Field | Config key |
|---|---|
| Buyer name | checkout_buyer_name |
| Buyer email | checkout_buyer_email |
| Purchase order no. | checkout_purchase_order_no |
| Goods mark | checkout_goods_mark |
| Comment | checkout_comment |
API endpoints
| Method | Endpoint | Auth |
|---|---|---|
PUT |
/V1/carts/mine/set-order-custom-fields |
Customer |
PUT |
/V1/guest-carts/:cartId/set-order-custom-field |
Guest |
Compatibility
| Module version | Magento | PHP |
|---|---|---|
2.0.* |
2.4.6 – 2.4.8 | 8.1 · 8.2 · 8.3 · 8.4 |
1.2.* |
2.3.x | 7.x |
1.1.* |
2.1.x – 2.2.x | (no longer supported) |
Installation
composer require sbodak/magento2-checkout-custom-form
php bin/magento module:enable Bodak_CheckoutCustomForm
php bin/magento setup:upgrade
php bin/magento setup:di:compile
php bin/magento cache:flush
Admin Configuration
Go to Stores → Configuration → Sales → Checkout → Checkout Custom Form Configuration.
- Enabled Form Fields – multiselect; choose which fields appear in the checkout.
- ** Character Limit fields – optionally restrict the maximum length of each field (leave empty for no limit).
Customisation
Adding / removing fields
- Add the constant to
Api/Data/CustomFieldsInterface.phpand theATTRIBUTESarray. - Add the column to
Setup/Patch/Data/AddCustomFields.php. - Extend
Model/Data/CustomFields.phpwith getters, setters, andisXxxEnabled(). - Register the field in
Model/Config/Source/Option.php. - Add it to
Model/Checkout/LayoutProcessor/Plugin.php($fieldsarray). - Update
Observer/AddCustomFieldsToOrder.phpif custom mapping is required. - Update
Observer/Sales/OrderLoadAfter.phpto populate the extension attribute. - Update templates in
view/adminhtml/templates/order/view/custom_fields.phtml
andview/frontend/templates/order/view/custom_fields.phtml.
Making a field required
In Model/Checkout/LayoutProcessor/Plugin.php, add a validation key to the field array:
[
'dataScopeName' => CustomFieldsInterface::CHECKOUT_PURCHASE_ORDER_NO,
'label' => 'Purchase order no.',
'validation' => ['required-entry' => true],
],
Overriding translations
Edit i18n/en_US.csv (or create a language-specific CSV, e.g. de_DE.csv).
Screenshots
Checkout – Guest
[image: Checkout frontend custom form – Guest]
Checkout – Logged in
[image: Checkout frontend custom form – Logged in]
Customer account – Order history
[image: Customer account – Order history view]
Admin panel – Order edit
[image: Admin panel – order edit]
Running Tests
composer install
vendor/bin/phpunit
Uninstall
php bin/magento module:uninstall Bodak_CheckoutCustomForm
This drops the custom columns from the sales_order and quote tables.
Changelog
See CHANGELOG.md.
License
Changelog
All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog,
and this project adheres to Semantic Versioning.
[2.0.0] - 2026-04-18
Breaking Changes
- Moved all module source code into
src/directory; onlycomposer.json,LICENSE,README.md,
docs/, andCHANGELOG.mdremain in the repository root. - Replaced deprecated
Setup/InstallData.phpwithSetup/Patch/Data/AddCustomFields.php
(Magento 2.3+ declarative data-patch API). - Removed
setup_versionfrometc/module.xml(no longer required in Magento 2.4). - Setter and getter signatures now use proper
?stringnullable types and return types.
Added
- Magento 2.4.8 compatibility — tested against M2.4.7 / M2.4.8.
- PHP 8.1 – 8.4 support in
composer.json. - Admin configuration (
etc/adminhtml/system.xml+etc/config.xml): enable/disable
individual form fields per store view and optionally set per-field character limits. Helper/Config— centralises access tobodak/checkout/*store configuration.Model/Checkout/LayoutProcessor/Plugin— injects enabled fields into the checkout JS layout
at runtime, replacing the hardcodedcheckout_index_index.xmlfield definitions.Model/Config/Source/Option— multiselect source model for the admin field selector.Model/CustomFields/Validator— validates field lengths against configured limits before
persisting to the quote; usesLaminas\Filter\Word\UnderscoreToCamelCase.Observer/Sales/OrderLoadAfter— populates Sales Order extension attributes after load
so custom fields are available via the REST API response.etc/extension_attributes.xml— declares extension attributes onOrderInterfacefor all
five custom fields.etc/events.xml— addedsales_order_load_afterobserver.etc/di.xml— addedLayoutProcessorplugin registration.i18n/de_DE.csv— German translations.- Custom textarea template (
view/frontend/web/template/form/element/textarea.html). - Unit test suite (
tests/Unit/) coveringCustomFields,Config,Validator, and
AddCustomFieldsToOrder.
Changed
Observer/AddCustomFieldsToOrder— only copies fields that are enabled in admin config
(previously always copied all fields).- Frontend and admin templates now conditionally render only enabled fields via
isCheckoutXxxEnabled()methods. checkout_index_index.xmlsimplified: field definitions are now managed entirely by the
LayoutProcessorplugin rather than XML items.- Dependency declarations in
composer.jsonnow includemagento/module-checkout,
magento/module-quote,magento/module-sales, andmagento/module-store. - Templates updated from deprecated
/* @escapeNotVerified */comments to$block->escapeHtml()
short syntax (<?= ?>). - Module sequence in
etc/module.xmlextended to includeMagento_Checkout,Magento_Quote,
andMagento_Store.
Fixed
Model/Data/CustomFieldsnow correctly callsparent::__construct()on
AbstractExtensibleObject.
[1.2.1] - Previous release
- Magento 2.3 compatibility.
[1.1.*] - Legacy
- Magento 2.1.x – 2.2.x support (no longer maintained).
| Version | Stability | QA Status | Released |
|---|---|---|---|
| 2.0.0 | stable | Fail | 2026-04-18 21:55:13 |
| 1.2.1 | stable | Not tested | 2019-03-27 21:10:42 |
| 1.2.0 | stable | Not tested | 2019-03-14 18:32:37 |
| 1.1.4 | stable | Not tested | 2018-09-19 20:57:26 |
| 1.1.3 | stable | Not tested | 2018-09-19 20:51:45 |
| 1.1.2 | stable | Not tested | 2018-04-04 18:42:51 |
| 1.1.1 | stable | Not tested | 2018-03-03 15:14:12 |
| 1.1.0 | stable | Not tested | 2018-03-03 13:12:24 |
| 1.0.3 | stable | Not tested | 2017-11-13 08:51:33 |
| 1.0.2 | stable | Not tested | 2017-11-12 21:21:21 |
| 1.0.1 | stable | Not tested | 2017-11-11 18:09:18 |
| 1.0.0 | stable | Not tested | 2017-11-11 17:23:55 |
Requires 7
| Package | Constraint |
|---|---|
| laminas/laminas-filter | ^2.25 |
| magento/framework | ^103.0 |
| magento/module-checkout | ^100.4 |
| magento/module-quote | ^101.2 |
| magento/module-sales | ^103.0 |
| magento/module-store | ^101.1 |
| php | ^8.1|^8.2|^8.3|^8.4 |
Requires-dev 1
| Package | Constraint |
|---|---|
| phpunit/phpunit | ^10.5|^11.0 |
| Tool | Status | Findings | Summary |
|---|---|---|---|
| PHPCS | Fail | 2 | 2 errors (gating threshold: error-severity=10, ruleset: Magento2) |
| PHPStan | Fail | 3 | 3 errors (level 4, ruleset: phpstan + bitexpert/phpstan-magento) |
| Cpd | Pass | 0 | |
| Security | Pass | 0 |
Turn an existing module into recurring revenue.
If you already maintain a Magento 2 module on GitHub or GitLab, listing it on Packagento takes about five minutes. We mirror your tags, handle distribution signing, and route paid licenses through Stripe Connect, so you can keep shipping the way you already do.