storetown-media / module-onepagecheckout

storetown-media/module-onepagecheckout

One Page Checkout for Magento 2 — All checkout steps on a single page with AJAX validation, real-time shipping calculation, and responsive design. Compatible with Luma, Blank, and Hyvä themes.

magento2-module Compatibility: 2.4.7-2.4.9 Code Quality: Fail Tests: N/A Security: Pass proprietary

IA24 One Page Checkout for Magento 2

A complete, theme-independent One Page Checkout extension for Magento 2.

Features

  • Theme-independent — Works with Hyva, Luma, Blank, or any custom theme
  • All steps on one page — Address, shipping, payment in a single view
  • AJAX-based — No page reloads, real-time shipping/payment calculation
  • Responsive design — Optimized for desktop, tablet, and mobile
  • Admin-configurable — Colors, layout, form fields, trust badges
  • PLZ autofill — Automatic city lookup for DE/AT/CH postal codes
  • Guest checkout with optional registration — Create customer account during checkout
  • Method icon customization — Custom icons and descriptions for shipping/payment methods
  • Trust badges — Configurable trust badges (SSL, shipping, returns, etc.)
  • PSP integrations — Mollie, Adyen, Stripe, PayOne, Unzer, Amazon Pay, PayPal, Klarna
  • i18n ready — Full translation support via Magento's i18n system (de_DE included)

Requirements

  • PHP: 7.4, 8.0, 8.1, or 8.2
  • Magento: 2.4.4 or higher
  • Dependencies: Magento_Checkout, Magento_Customer, Magento_Sales, Magento_Quote, Magento_Payment, Magento_Shipping, Magento_Directory, Magento_Tax, Magento_Eav, Magento_Paypal

Installation

Via Composer (recommended)

composer require ia24/module-onepagecheckout
php bin/magento module:enable IA24_OnePageCheckout
php bin/magento setup:upgrade
php bin/magento setup:di:compile
php bin/magento cache:clean
php bin/magento setup:static-content:deploy de_DE -f

Manual Installation

  1. Copy the module to app/code/IA24/OnePageCheckout/
  2. Run:
php bin/magento module:enable IA24_OnePageCheckout
php bin/magento setup:upgrade
php bin/magento setup:di:compile
php bin/magento cache:clean
php bin/magento setup:static-content:deploy de_DE -f

Configuration

Stores > Configuration > IA24 > One Page Checkout

General

  • Enabled: Yes/No
  • Title: Checkout page title

Design

  • Primary color: Hex code (default: #0078b3)
  • Accent color: Hex code (default: #e85e0c)
  • Layout: One column / Two columns / Accordion

Form Fields

  • Show company: Yes/No
  • Show telephone: Yes/No
  • Telephone required: Yes/No
  • Show order comment: Yes/No
  • Show VAT ID: Yes/No

Trust Badges

  • Show trust badges: Yes/No
  • Badge position: Above order button / Below summary / Sidebar / Footer
  • Badge style: Horizontal / Vertical / Grid / Compact

PLZ Autofill

  • Enable PLZ autofill: Yes/No
  • Countries: DE, AT, CH (configurable)

Usage

After activation, the standard checkout is automatically redirected to the One Page Checkout:

  • Standard URL: /checkout/ → Redirected to /ia24checkout/
  • Direct URL: /ia24checkout/

Payment Integrations

The module supports all Magento-compatible payment methods. Special handling is included for:

PSP Features
PayPal Express Checkout, redirect handling, Error #10413 fix
Mollie Pre-order redirect, payment token generation
Adyen State data preparation, payment status checking
Stripe Checkout session handling, redirect
PayOne Multiple sub-methods with individual icons
Unzer SDK integration, redirect handling
Amazon Pay Session management, adapter integration
Klarna Redirect handling via generic fallback

Customization

CSS Variables

Colors are defined via CSS custom properties and configurable via admin:

:root {
    --ia24-primary: #0078b3;
    --ia24-accent: #e85e0c;
}

Layout Options

  1. one-column — Vertical layout, optimal for mobile
  2. two-column — Forms left, summary right (default)
  3. two-column-reverse — Summary left, forms right
  4. accordion — Steps as collapsible accordion elements

Troubleshooting

Checkout shows no shipping methods

  • Verify shipping methods are configured for the selected country
  • Check var/log/system.log for errors

Shipping/payment methods not loading

  • Run php bin/magento setup:di:compile after any constructor changes
  • Delete generated/ directory and re-compile
  • Check AJAX responses in browser DevTools (Network tab)

PLZ autofill not working

  • Verify PLZ data files exist in data/postcode/ directory
  • Check that the country is enabled in admin config
  • See docs/PLZ_AUTOFILL.md for detailed documentation

Styling issues

  • Clear browser cache
  • Run php bin/magento cache:flush
  • Re-deploy static content: php bin/magento setup:static-content:deploy de_DE -f

PayPal Error #10413

  • This is handled automatically by the PayOne/NVP plugins
  • If it persists, check PayPal merchant account settings

Support

For questions or issues, check:

  • var/log/system.log
  • var/log/exception.log
  • Browser DevTools (F12) Network tab for AJAX errors

Changelog

All notable changes to the IA24 OnePageCheckout module are documented in this file.

[1.5.1] - 2026-07-04

Added (Consumer Rights + account withdrawal)

  • Checkout Consumer Rights feature set (EU consumer rights, effective 2026-06-19). New admin section Stores → Configuration → STM → One Page Checkout → Consumer Rights:
    • Statutory warranty notice (configurable heading + HTML text) with selectable placements (checkout above the order button, order confirmation page)
    • Online right-of-withdrawal form for both registered customers and guests at ia24checkout/withdrawal — name, address, order number, order/receipt dates, full vs. partial scope, item description and optional reason; standard POST (form_key protected) so it works without JavaScript
    • Configurable placement of the withdrawal link (checkout legal notices, order confirmation page, checkout footer)
    • Logged-in customers get the form prefilled from their default address; submitted values are repopulated via DataPersistor on validation errors
    • Soft order matching: the entered order number + e-mail is linked to the real sales_order when found, but a submission is never blocked on a mismatch
    • Online form auto-fill: entering the order number together with the order e-mail pre-fills name, address and order date via an AJAX lookup (ia24checkout/withdrawal/lookup), and the order's purchased items are offered as a selectable checkbox list
    • Per-order withdrawal from the customer account: every order in My Account → My Orders → View Order shows a "Submit a withdrawal for this order" button that opens the form pre-filled for that exact order (order number, e-mail, name, address, date) with the order's products as selectable checkboxes; access is ownership-checked server-side. The button is hidden for canceled and closed orders, and an optional setting ("Account Button Only Within Period", default off) hides it once the withdrawal period has elapsed (based on shipment date + withdrawal period)
  • Withdrawal persistence + admin workflow:
    • New table ia24_withdrawal_request (declarative etc/db_schema.xml) with ORM model/resource/collection
    • Admin grid under Sales → STM Withdrawals (UI component listing, ACL IA24_OnePageCheckout::withdrawal) plus a detail view with status (new/acknowledged/processed/rejected) and internal notes
  • Automated notifications via Model\WithdrawalNotifier: merchant alert (recipient configurable, falls back to the general store e-mail) and an optional consumer confirmation; two transactional e-mail templates (ia24_withdrawal_merchant, ia24_withdrawal_customer)
  • German translations for all new strings (i18n/de_DE.csv); other locales fall back to the English source

Fixed (Adobe Marketplace QA — resubmission 2026-05-15)

  • Place order fails with "regionId is required": countries with required state/province (US, CA, AU, …) never received a region because the #shipping-region-container / #billing-region-container were rendered hidden and no JavaScript populated them. Added initRegionLoader() in checkout-core.js (reads ia24OnePageCheckout.regions[countryId] already provided by CheckoutConfigProvider), wired to shipping-country / billing-country change events with pre-selection from quote.shipping_address.region_id. Added matching #billing-region-container to checkout.phtml (previously only shipping had one). getAddressData() and the place-order payload now also carry billing_region_id. SaveAddress.php reads it; PlaceOrder.php reads region_id / billing_region_id from request, looks them up via Directory\Model\RegionFactory and calls setRegionId() / setRegion() / setRegionCode() on the matching quote address.
  • "No Payment Information Required" shown on paid orders: SaveShipping::getPaymentMethods() and the CheckoutConfigProvider::getPaymentMethods() fallback path enumerated payment methods by config active flag only, never calling $methodInstance->isAvailable($quote). Magento's built-in Magento_OfflinePayments::free method (title "No Payment Information Required") is active=1 out of the box and only gates itself on grand-total = 0 via isAvailable(), so without that check it surfaced on every paid order. Both code paths now skip methods that fail isAvailable($quote) (with \Throwable guard so a buggy third-party method does not break the checkout).
  • PlaceOrder error surfacing: the outer catch (\Exception) block masked all errors as a generic "An error has occurred. Please try again." — including actionable Magento validation messages such as the regionId / telephone ones. Added a dedicated catch (\Magento\Framework\Exception\LocalizedException) ahead of the generic catch that forwards $e->getMessage() to the JSON response, so the customer sees the real reason and can correct their input.
  • PlaceOrder telephone fallback: ensureAddressData() now reads telephone / billing_telephone from the request and falls back to the placeholder 0000000000 if the EAV-required telephone attribute is empty on either address — same defensive pattern that already existed in the PayPal-Express redirect path, but applied to the main order flow too. Fixes the secondary "telephone" is required validation error observed alongside the regionId failure when the storefront's phone field was hidden by configuration.
  • Translation key select_region_placeholder ("Please select...") added to Block\Checkout::getJsTranslations() for the region dropdown placeholder.

Added (1.5.1 initial — 2026-04-23)

  • Demo design refinements merged into marketplace distribution (CSS +636 lines, 9 new DOM selectors for header/footer substructure: ia24-checkout__header-logo-img, ia24-checkout__header-icons-inner, ia24-checkout__footer-inner, ia24-checkout__footer-links, etc.)
  • State-based step progression in sticky-progress.js (replaces scroll-based viewport detection, fixes wrong active step in ultra-compact layout where all sections are simultaneously visible)
  • isAddressComplete() and isShippingMethodSelected() helpers with MutationObserver hooks on address-input and shipping-change events
  • Out-of-box design defaults in etc/config.xml: ultra-compact layout, #0000a0 primary / #ff8000 accent, Open Sans typography, sidebar-top trust badges, "Developer Support" custom badge with headset icon
  • Progress bar default enabled

Fixed

  • CSP compliance: 3x inline onchange="window.ia24SelectPayment/Shipping(...)" handlers replaced with event delegation via new initMethodEventDelegation() function (addEventListener on shipping/payment containers)
  • CSRF handling: centralized handleFetchResponse() wraps all fetch responses, handles 403/CSRF with translated error message; 7x raw fetch().then(r => r.json()) replaced
  • Composer package namespace updated to storetown-media/module-onepagecheckout (Adobe Marketplace SKU)
  • Composer dependency constraints widened from ^ to >= for all Magento modules — fixes installation failure on Magento 2.4.8-p3 where magento/module-paypal is version 101.x (^100.4 did not match)
  • Minimum PHP version raised to >=8.1 (Magento 2.4.6+ requirement)
  • Admin config page crash (TypeError) on Magento 2.4.8-p3 with PHP 8.4: MethodCustomization model now catches \Throwable (not just \Exception) — TypeError extends \Error, not \Exception, so previous catch-Exception blocks let PayPal-Vault afterIsAvailable() TypeErrors bubble up and crash the Admin → Stores → Configuration → OPC page. All 6 defensive catch blocks in Model/MethodCustomization.php widened to \Throwable.
  • PHP 8.4 TypeError in PlaceOrder.php, SaveShipping.php, ApplyCoupon.php: Exception::__construct() requires string, but __() returns Magento\Framework\Phrase — fixed with (string) cast on all 7 occurrences
  • system.xml fully translated to English (704 lines, 0 German umlauts) for Adobe Marketplace review
  • Admin "About This Module" section (view/adminhtml/templates/system/config/about-info.phtml) fully translated to English: header subtitle, info cards (Developer / Support / Website / License), all 8 Premium Features cards (Trust Badges, Postcode Autofill, Customizable Design, Mobile Optimized, AJAX Validation, Coupon Integration, GDPR-compliant, Performance), Support & Contact form labels, placeholders, button, and all JavaScript status messages
  • Admin Support contact controller (Controller/Adminhtml/Support/Send.php) response messages translated to English (validation errors, success message, email subject fallback)
  • Admin support request email template (view/adminhtml/email/support_request.html) fully translated to English (subject, var labels, body, footer)
  • PHPCS Magento2 standard compliance: 0 errors + 0 warnings across the entire module — added missing @var DocBlocks for all private class properties in Model/Psp/RedirectResolver.php, broke long lines in checkout.phtml (6 places) and json-fix-loader.phtml (1 place), fixed indentation of <?php if isProgressBarEnabled()> block children, removed spurious blank line before closing class brace in Plugin/Paypal/ConfigPlugin.php
  • Logo dimensions admin config (Logo Width (px) / Logo Height (px)) now actually affects checkout — previously max-height: 50px !important was hardcoded in checkout-layout.css and silently overrode any admin value. Replaced with CSS variables --ia24-logo-max-width / --ia24-logo-max-height populated from Config::getLogoWidth() / getLogoHeight() via Block\Checkout::getCssVariables() (sanity-capped: width ≤2000px, height ≤500px)
  • Logo overflow into step bar when configured larger than 50px — header-inner min-height now scales with the logo via max(50px, var(--ia24-logo-max-height, 50px)), keeping the progress bar below the logo regardless of configured size
  • Payment method cards in One-Column layout no longer break each title word onto its own line — grid minmax(180px, 1fr) widened to minmax(260px, 1fr) so titles like "No Payment Information Required" and "PayPal Billing Agreement" fit on one or two lines instead of fragmenting per-word
  • Admin "Customize Payment Methods" section showed "No installed payment methods found" on Magento 2.4.8 with PayPal-Vault installed — root cause was a single try/catch in Model\MethodCustomization::getAllPaymentMethodsInternal() wrapping both paymentHelper->getStoreMethods() (throws TypeError in admin context because PayPal-Vault plugin requires a quote) and the config-based fallback enumeration. Split into two isolated try/catch blocks so the admin-safe paymentHelper->getPaymentMethods() config walk runs even when getStoreMethods() fails
  • Admin "Customize Payment / Shipping Methods" preview rendered without an icon — Block\Adminhtml\System\Config\MethodCustomizer::getIconUrls() calls getViewFileUrl('IA24_OnePageCheckout::images/method-icons/<file>.svg') which resolves against the adminhtml area, but the 33 method-icon SVGs only existed under view/frontend/web/images/method-icons/, producing 404s on every preview-icon URL. Moved the entire method-icons/ folder to view/base/web/images/method-icons/ so the same IA24_OnePageCheckout::images/method-icons/... view-file path resolves correctly in both frontend AND adminhtml. No PHP changes; static-content redeploy required

Changed

  • Removed misleading "(Coming Soon)" hint from method_customization admin config group comment — the Payment & Shipping Methods customization feature has been fully wired to the frontend since v1.5.1 (enrichPaymentMethods() / enrichShippingMethods() apply configured icons, subtexts, and custom titles to checkout cards on every AJAX response)

Removed

  • STM License module integration fully decoupled — stm/module-license dependency no longer required
  • License validation removed from Controller/Index/Index.php (removed $licenseService property, constructor param, license-check block)
  • License validation removed from Plugin/Checkout/RedirectPlugin.php
  • STM\License\Model\ExtensionRegistry removed from etc/di.xml
  • stm/module-license removed from composer.json suggest section

[1.4.0] - 2026-03-09

Added

  • STM License Integration — license validation via stm/module-license module
  • di.xml — Extension registration with STM\License\Model\ExtensionRegistry (key: ia24_onepagecheckout)

Changed

  • composer.json — Added dependency stm/module-license: ^1.0
  • module.xml — Added STM_License to module sequence

[1.3.1] - 2026-03-05

Changed

  • Adobe Commerce Marketplace PHPCS Compliance: 0 ERRORS, 0 WARNINGS across all PHP/PHTML files
  • Composer version constraints hardened (>= to ^ for all Magento dependencies)
  • Header logo repositioned to the left with centered title and back-link
  • Server-based changelog sync via sync-changelog.sh -- automatic WooCommerce update on every Satis build
  • Updated build-zip.ps1 with changelog sync integration

Fixed

  • PHTML line-length and indentation warnings (checkout.phtml, method-customizer.phtml)
  • Empty catch blocks, missing DocBlocks, and inline control structures across all PHP files
  • PHPCS rule conflict for multi-line function calls resolved by variable extraction

[1.3.0] - 2026-02-27

Security

  • Restored CSRF protection -- removed global CSRF bypass plugin (CsrfValidatorSkip.php), Magento's form_key validation now active on all AJAX endpoints
  • Added brute-force protection via Magento's AccountManagement lockout (UserLockedException)
  • Fixed XSS vulnerabilities -- all innerHTML injections now use escapeHtml() for server-supplied data
  • Removed debug data (exception class names, stack traces) from all API responses -- generic user messages only
  • Added CSS color sanitization via sanitizeColor() for admin-configured theme colors
  • Hardened CheckEmail endpoint -- removed email from response, removed info-level logging of email addresses
  • Hardened Login endpoint -- removed email logging, added generic error messages for LocalizedException
  • PII logging protection -- 40+ log statements masked in PlaceOrder.php (email: first 3 chars, name: first 2, phone/street: fully masked, VAT-ID: last 4 only)
  • SaveAddress.php logs only field names (array_keys()), not values
  • All user inputs type-cast to (string) across all controllers -- prevents PHP 8.1+ TypeError attacks
  • Payment method regex validation (preg_match('/^[a-z0-9_]+$/i')) before setMethod()
  • Shipping method validation with type casting and regex in SaveShipping.php
  • Order comment sanitization: trim() + length limit 5000 chars via mb_substr()
  • Custom icon path traversal protection: basename($filename) + check against . and ..
  • Font-scale range validation (10-24) prevents CSS injection via oversized/zero scale values
  • Coupon action whitelist: only apply and remove allowed, fallback to apply
  • Double-submit protection: isPlacingOrder flag prevents duplicate order placement
  • Fetch timeouts with AbortController on all 5 fetch calls (10s email/PLZ, 15s shipping/payment/login, 30s order)
  • XHR postcode-lookup timeout: xhr.timeout = 10000 with onerror/ontimeout handlers
  • Sensible POST-body logging removed from PlaceOrder.php (DSGVO/PCI compliance)
  • Coupon code reflection sanitized -- generic error messages instead of user-input echo
  • showCouponMsg() type validation: whitelist check (success/error only)

Added

  • Virtual/downloadable products support (6 files): conditional shipping section, 2-step vs 3-step progress bar, auto-flow SaveAddress -> SaveShipping -> PaymentMethods, is_virtual flag in API responses
  • Newsletter subscription functional: checkbox value sent in order payload, PlaceOrder.php subscribes customer via SubscriberFactory after successful order
  • Newsletter hint text with privacy policy link: "(Jederzeit abstellbar, die Datenschutzerklarung habe ich gelesen.)"
  • Separate agreement system: individual checkboxes for Terms, Privacy Policy, and Cancellation Policy with 9 config fields, required/optional toggle per agreement, bidirectional sync between sidebar and sticky bar
  • Ultra-compact layout (4th layout variant): float-based 3-column architecture with address left, shipping+payment right-stacked, sidebar below -- hides progress bar, header icons, sidebar logo, trust badges (~250 lines CSS)
  • Header logo for ultra-compact layout: visible only in ultra-compact, uses backend settings via getLogoStyle()
  • Numbered section headings (1-4): CSS counter with white digit in primary-color circle, accent-colored heading text
  • Configurable header icon bar: 46 payment + 36 shipping icons, 3 custom upload slots, ICON_FILE_MAP with 80+ mappings, multiselect backend fields, grayscale filter with hover effects, 3 responsive breakpoints
  • Typography backend fields: font family dropdown (13 options incl. Google Fonts), font size dropdown (7 options), font color picker
  • Google Fonts loading: getGoogleFontUrl() with <link preconnect> tags (only when Google Font selected)
  • Font-size scaling system: CSS variable --ia24-font-scale with calc(Xpx * var(--ia24-font-scale, 1)) on all ~55 hardcoded font-sizes
  • Font-color cascading: 7x heading color, 4x section text, 4x label color made dynamic via --ia24-font-color
  • 33 SVG method icons created in view/base/web/images/method-icons/ (accessible in frontend and admin)
  • Admin "Uber dieses Modul" section: version from ComponentRegistrar (reads composer.json), features grid, AJAX contact form via TransportBuilder
  • Admin email template for support requests (etc/email_templates.xml)
  • Admin route (etc/adminhtml/routes.xml, frontName: ia24checkout)
  • Admin payment/shipping icon preview: live preview with background-image rendering in MethodCustomizer
  • Only active payment/shipping methods shown in MethodCustomizer (changed from all installed)
  • RequireJS stub for Hyva compatibility: minimal require/define stubs to prevent ReferenceError from Magento core scripts
  • prefers-reduced-motion media query: disables all animations/transitions for motion-sensitive users
  • Print stylesheet: hides progress bar, sticky bar, security hints, header icons; sidebar non-sticky
  • Focus-visible styling on all interactive elements: place order button, back-link, coupon toggle/button, progress steps, login button, form inputs, selects, textarea, AGB links (WCAG 2.1 compliance)
  • Checkbox touch targets: min-height: 44px (WCAG)
  • IntersectionObserver for sticky order bar: smart detection of original button visibility
  • :has() CSS fallback: updateMethodSelectedClass() JS function with .ia24-checkout__method--selected class toggle
  • Sidebar scrollbar styling: scrollbar-width: thin + ::-webkit-scrollbar custom styling
  • PLZ autofill CSS class: .ia24-checkout__input--autofilled with dynamic primary-color background
  • Coupon toggle keyboard accessibility: tabindex="0", role="button", aria-expanded, Enter/Space handlers
  • Coupon button touch-target: min-height: 44px
  • IA24_DEBUG flag: externally activatable via window.IA24_DEBUG_ENABLED, protects all console output
  • Billing form: 5 input fields given required attribute (firstname, lastname, street, postcode, city)
  • Missing config.xml defaults: all 7 footer_links fields and 4 trust-badge custom fields
  • <depends> chain for sticky bar AGB: show_sticky_order_bar added as dependency
  • "Coming Soon" hint for method_customization backend group
  • composer.json for Composer-based installation via Satis repository
  • LICENSE file with proprietary license terms
  • CHANGELOG.md with full version history
  • i18n/de_DE.csv with 155+ translation strings from all module files
  • Block/Checkout::getTaxRateLabel() for dynamic tax rate display
  • Block/Checkout::sanitizeColor() for CSS injection prevention
  • Distribution setup: build-zip.sh, Satis server at packages.storetown-media.de

Changed

  • Moved CSS from inline styles to checkout-layout.css (1377 lines extracted)
  • Deleted obsolete checkout.css (replaced by checkout-layout.css)
  • Hardcoded "zzgl. MwSt. (19%)" label now shows dynamic tax rate from Magento Tax configuration
  • Hardcoded 0.19 tax rate fallback replaced with 0.0 in all controllers (was incorrect for AT/CH stores)
  • Removed 111 console.log/error/warn statements from production JavaScript code
  • Updated README.md with complete feature list, requirements, and PSP documentation
  • Backend admin panel restructured to 10 logical groups (from 11 unorganized): Allgemein, Design & Layout, Checkout-Formular, PLZ-Autofill, Zahlungs-/Versandmethoden, Bestelloptionen, Gutscheincode, Vertrauen & Sicherheit, Footer & Rechtliches, Uber dieses Modul
  • Template restructuring: progress bar, messages, and login section moved above grid container -- forms and sidebar now start at exactly the same height
  • Sidebar restructured as single card with sticky action zone: cart items/coupon/comment in scrollable area, totals/agreements/place-order button always visible
  • Order comment moved to sidebar (from left form area)
  • Logo moved from header to sidebar
  • Header made compact: single row (title left, "Back to cart" right), padding reduced
  • Unified color system with dynamic CSS variables from backend: --ia24-primary-rgb, --ia24-accent-rgb for transparency support
  • 20+ hardcoded color values replaced with dynamic CSS variables (focus glow, validated fields, progress steps, customer account box)
  • Validation colors (~30 places) changed from hardcoded red to var(--ia24-accent) with RGB transparency
  • 29x var(--ia24-primary) fallbacks unified from mixed values to #0078b3
  • Accent fallback values standardized: #ff8000 to #e85e0c, #d96b00 to #c44d0a
  • Footer inline styles moved to CSS classes: .ia24-checkout__footer-inner, .ia24-checkout__footer-separator, .ia24-checkout__footer-links
  • AGB link in sidebar uses $block->getTermsUrl() (configured URL) instead of $block->getUrl('agb')
  • Agreement label fallbacks use own translated defaults instead of footer-link labels
  • Agreement text joining uses proper German grammar (und, und die) instead of comma separation
  • Sidebar totals moved from scrollable area to always-visible action zone
  • escapeHtml() enhanced with quote escaping (" to &quot;, ' to &#39;)
  • All inline scripts wrapped in IIFE, const/arrow functions converted to var/function() (ES5 compatibility)
  • checkout-core.js init(): each init step wrapped in try/catch (one error no longer blocks others)
  • PLZ autofill: XHR replaced with fetchWithTimeout() (10s timeout)
  • Hardcoded German strings replaced with translation keys (gateway_redirect, gateway_fallback, order_success, account_created_suffix)
  • SaveAddress.php: RegionResource DI injected, deprecated load() replaced
  • PlaceOrder.php: setCustomerDataAsLoggedIn() instead of deprecated Model::load()
  • ApplyCoupon.php: CouponResource DI injected, deprecated load() replaced
  • Config.php: DEFAULT_PRIMARY_COLOR + DEFAULT_ACCENT_COLOR constants added
  • PayPal logging reduced: ~40 info calls changed to 16 debug calls, logRequestSummary() removed from NvpPlugin
  • system.xml sortOrder fix: newsletter_checkbox 20 changed to 25 (collision resolved)
  • ConfigPlugin.php: mixed return type removed (PHP 7.4 compatibility)
  • Admin CSS: save-button style scoped to OPC page only
  • checkout-core.js handleLogin(): null-checks added
  • requirejs-config.js cleaned: all IIFE mappings removed
  • setup_version attribute removed from etc/module.xml (deprecated since Magento 2.3)
  • 3 dead Block methods marked as @deprecated: getCartItemCount(), getTrustBadgesStyle(), getFooterLinks()
  • Border colors unified: #e0e0e0 changed to #e5e7eb, footer separator #ccc to #e5e7eb
  • Progress bar accent shimmer: static white/gray changed to dynamic accent gradient
  • Method text overflow: text-overflow: ellipsis with min-width: 0 on method content (all layouts)
  • Array.isArray() guards on all API response arrays (payment_methods, shipping_methods)
  • Two-column-reverse mobile: flex-direction: column !important at <=900px
  • Coupon button: btn.disabled = true/false during AJAX requests
  • overflow-wrap: break-word added to sidebar text elements

Fixed

  • SaveShipping.php line 245: $paymentHelper corrected to $this->paymentHelper (DI migration bug causing payment methods to fail)
  • PlaceOrder.php: 3x $orderRepository corrected to $this->orderRepository (DI migration bug)
  • Sticky bar AGB config: showAgreements() corrected to showAgreementsStickyBar()
  • Logo debug leftover: $block->hasLogo() || true changed to $block->hasLogo()
  • Duplicate event observer: PrepareQuoteForOrder removed from global events.xml, kept in frontend/events.xml
  • Duplicate window.ia24ReloadShipping assignment removed from checkout-core.js
  • Duplicate window.IA24Progress assignment removed from sticky-progress.js
  • Duplicate blur-listener on email field removed
  • Duplicate sticky-bar visibility CSS rule removed
  • Duplicate border-top on .ia24-checkout__totals removed
  • 4 orphaned/misassigned PHPDoc comments fixed in Checkout.php
  • Virtual products: null-safe container access in loadShippingMethods(), 4 additional null-safety fixes in checkAndLoadShipping() and initIA24Checkout()
  • Initial payment message for virtual products: "Bitte Adresse ausfullen" instead of "Versandart wahlen"
  • Ultra-compact logo: CSS wildcard selector exception via :not() prevents height: auto !important override
  • :has() CSS fallback: selectors wrapped in @supports selector(:has(*)) for older browsers
  • Footer/header wildcard CSS selectors: :not([class*="ia24"]) guards added (Porto/Ultimo theme compatibility)
  • system.xml XSD error: hyphen in <base_url> path violated Magento XSD pattern
  • system.xml: header-icons path changed to headericons (XSD compliance)

Removed

  • Plugin/CsrfValidatorSkip.php -- CSRF bypass plugin (security fix)
  • CsrfAwareActionInterface from Login.php (redundant with global CSRF)
  • Debug data fields (debug_error, debug_class) from SaveAddress API response
  • All console.log() statements from checkout.js and checkout.phtml
  • Controller/Router/CustomUrl.php -- dead code, not registered in any XML
  • etc/events.xml -- empty after observer move to frontend/events.xml
  • view/frontend/templates/js/button-fix-loader.phtml -- orphaned, not in layout XML
  • view/frontend/web/js/checkout-button-fix.js -- RequireJS dead code
  • view/frontend/web/js/checkout-json-fix.js -- RequireJS dead code
  • view/frontend/web/js/checkout.js -- RequireJS/jQuery legacy, duplicated checkout-core.js
  • Block/Adminhtml/System/Config/BrandingHeader.php -- replaced by AboutInfo.php
  • view/adminhtml/templates/system/config/branding-header.phtml -- replaced by about-info.phtml
  • Trust-badge dead code from Block/Checkout.php: TRUST_BADGE_ICONS constant, getTrustBadges(), getTrustBadgeIcon(), getTrustBadgeContainerClasses() (~50 lines)
  • Internal FEATURE_ROADMAP.md from distribution
  • Accordion layout option (no working JS existed, CSS stubs deleted)

[1.2.0] - 2026-01

Added

  • Sticky sidebar button (desktop): sidebar restructured into scrollable summary zone and sticky action zone with place order button, terms, trust badges
  • Dynamic color system: CSS variables --ia24-primary-rgb and --ia24-accent-rgb for rgba() transparency support
  • Configurable header icon bar: 46 payment icons, 36 shipping icons, 3 custom upload slots with grayscale filter and hover effects
  • Backend admin panel restructured to 10 logical groups with clear separation of concerns
  • Typography backend fields: font family (13 options), font size (7 options), font color picker with Google Fonts support
  • CSS variable --ia24-font-scale for proportional font-size scaling across all ~55 hardcoded sizes
  • ARIA accessibility attributes: role="alert", aria-live, role="button", tabindex, aria-expanded, aria-controls, aria-busy, role="radiogroup", aria-label, aria-hidden
  • Block/Checkout.php: getJsTranslations() with 22 translation keys, getHeaderIcons() with deduplication
  • ObjectManager to DI migration (35 calls reduced to 8, remaining are PSP-specific)
  • German text internationalization -- 40+ strings wrapped in __()/$t()

Changed

  • 246 logger->info() calls changed to logger->debug() across 4 controllers
  • Sticky bar PHP conditional removed (always visible now, matching HTML/CSS)
  • Order comment moved from left form area to right sidebar
  • Logo moved from header to sidebar with compact header design
  • Sidebar merged into single card with sticky bottom action area
  • Validation colors (~30 places) changed from hardcoded red to dynamic accent color
  • 20+ hardcoded color values replaced with dynamic CSS variables
  • Place order button accent color changed from --ia24-primary to --ia24-accent
  • Layout CSS rules added for one-column and two-column-reverse
  • Deprecated isPayPalRedirectMethod() removed (replaced by GatewayHandler)

Fixed

  • Placeholder '-' replaced with empty string '' across 7 files (~40 places)
  • beforeValidate() changed to no-op in AddressValidationPlugin.php and AddressPlugin.php
  • !important reduction: 63 to 60 (3 removed from sticky-bar-btn + footer padding)

[1.1.0] - 2025-12

Added

  • JavaScript extraction from checkout.phtml: created checkout-core.js (~1050 lines) as standalone IIFE module
  • sticky-order-bar.js (~85 lines) extracted from inline script block
  • sticky-progress.js extended with payment observation features
  • Hyva theme compatibility: all JS files converted from RequireJS define() to IIFE pattern
  • Inline coupon JS in checkout.phtml (replaces jQuery/RequireJS dependency)
  • window.ia24ReloadShipping global function for manual shipping reload trigger
  • 2-second retry mechanism for shipping method loading
  • Debug logging in isAddressCompleteForLoading() showing which field is missing
  • checkout-core.js init(): each initialization step wrapped in try/catch

Changed

  • checkout.phtml reduced from 3154 to 919 lines (4 inline script blocks extracted)
  • All JS modules converted from RequireJS define([], function() {...}) to (function() {...})()
  • requirejs-config.js: deps array removed (no RequireJS on Hyva)
  • json-fix-loader.phtml and button-fix-loader.phtml: text/x-magento-init converted to inline IIFE
  • Script loading changed from RequireJS to <script src> tags
  • Coupon code changed to jQuery event delegation (no re-binding after replaceWith)

Fixed

  • PayPal Express Checkout: shipping method no longer lost during redirect
  • Billing address handling for separate billing addresses
  • Missing EAV form attributes for adminhtml_customer_address
  • SaveShipping.php: $paymentHelper corrected to $this->paymentHelper (DI migration bug)
  • PlaceOrder.php: 3x $orderRepository corrected to $this->orderRepository (DI migration bug)
  • Sticky bar AGB config: showAgreements() corrected to showAgreementsStickyBar()
  • :has() CSS fallback: selectors wrapped in @supports selector(:has(*))
  • Footer/header wildcard selectors: :not([class*="ia24"]) guards added

Removed

  • Inline script Block 2 (coupon JS) deleted from checkout.phtml (was duplicating checkout.js, causing double AJAX calls)
  • text/x-magento-init blocks removed from checkout.phtml

[1.0.0] - 2025-11

Added

  • Initial release
  • Complete One Page Checkout with server-rendered PHP/PHTML architecture (no Knockout.js)
  • AJAX validation for all form fields with real-time error feedback
  • Admin configuration for design, form fields, and checkout behavior
  • 4 layout variants: two-column (default), two-column-reverse, one-column, ultra-compact
  • Responsive design for desktop, tablet, and mobile with sticky order bar
  • Payment gateway handler with PSP auto-detection (PayPal, Stripe, Mollie, Adyen, Braintree, Unzer, Amazon Pay, Klarna, and more)
  • Method icon customization system with 80+ icon mappings
  • Trust badge system with configurable position and style
  • PLZ autofill for DE/AT/CH (postcode database lookup)
  • Guest checkout with optional customer registration
  • Order comment field
  • Coupon code application with AJAX
  • Sticky progress bar with step indicators
  • PHP-to-JS data bridge via window.ia24CheckoutConfig
  • CSS variable color system: --ia24-primary, --ia24-accent with dark/light/RGB variants
  • Compatible with Luma, Blank, and Hyva themes
  • 11 language translations (DE, EN, FR, IT, ES, NL, PL, PT, SV, DA, NO)
Versions
Version Stability QA Status Compatibility Released
v1.6.3 stable Fail Magento 2.4.7-2.4.9 Details 2026-08-23 10:50:39

Requires 20

Package Constraint
magento/framework >=103.0
magento/module-backend >=102.0
magento/module-catalog >=104.0
magento/module-checkout >=100.4
magento/module-checkout-agreements >=100.3
magento/module-config >=101.2
magento/module-customer >=103.0
magento/module-directory >=100.4
magento/module-eav >=102.1
magento/module-newsletter >=100.4
magento/module-payment >=100.4
magento/module-paypal >=100.4
magento/module-quote >=101.2
magento/module-sales >=103.0
magento/module-sales-rule >=101.2
magento/module-shipping >=100.4
magento/module-store >=101.1
magento/module-tax >=100.4
magento/module-ui >=101.2
php >=8.1

Compatibility

Each Magento release line is installed on its supported PHP versions, then the module is built (DI compilation + static-content deploy) and its unit and integration suites are run. The matrix shows the lines and PHP versions the module is confirmed to install and run on. Code-quality results further down (phpstan, phpcs, …) are reported separately and never affect compatibility.

Compatibility matrix (Magento × PHP)
Magento PHP 8.2 PHP 8.3 PHP 8.4 PHP 8.5
2.4.7 Pass Pass
2.4.8 Pass Pass
2.4.9 Pass Pass

Code Quality

Advisory checks against the module's source. Static analysis runs once across the whole module; PHPStan re-runs per Magento + PHP version because resolvable symbols differ between releases. These NEVER affect the Compatibility badge. A phpcs finding can't make a module incompatible.

Static analysis

Coding standards (phpcs), mess detection (phpmd), copy-pasted code (cpd), PHP cross-version compatibility, composer.json validity. Each runs once for the whole module.

Static analysis results
Tool Status Findings Summary
PHPCS Warning 2 2 warnings (ruleset: Magento2)
PHPMD Warning 239 239 rule violations (UnusedPrivateField:234, ExcessiveClassLength:4, TooManyFields:1)
Cpd Warning 7 7 duplicated chunks spanning 320 total lines (min-lines=5, min-tokens=70)
Composer validate Info 19 valid; 19 advisory notes (composer validate --strict)

PHPStan

Type-checks the module's PHP against a real Magento install at the configured gate level. Re-runs per Magento and PHP version because resolvable symbols differ between releases.

PHPStan results by Magento and PHP version
Magento PHP 8.2 PHP 8.3 PHP 8.4 PHP 8.5
2.4.7 77 77
2.4.8 77 77
2.4.9 77 77

Tests

Unit and integration suites, run for each applicable Magento and PHP version. A test failure speaks to the module's behaviour, not its compatibility with a Magento line, so it is reported here separately and never reddens the compatibility matrix.

Unit tests

Unit tests results by Magento and PHP version
Magento PHP 8.2 PHP 8.3 PHP 8.4 PHP 8.5
2.4.7 N/A N/A
2.4.8 N/A N/A
2.4.9 N/A N/A

Integration tests

Integration tests results by Magento and PHP version
Magento PHP 8.2 PHP 8.3 PHP 8.4 PHP 8.5
2.4.7 N/A N/A
2.4.8 N/A N/A
2.4.9 N/A N/A

Security

Security checks run directly against the module: an audit of its declared dependencies for known vulnerabilities (composer audit) and a scan of its source for malware and web-shell signatures. Each runs once. A malware detection fails the version outright.

Security results
Tool Status Findings Summary
Composer audit Pass 0
Malware scan Pass 0
License
proprietary
Homepage
https://www.storetown-media.de
Authors

More from Storetown Media

View vendor
Make it pay

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.