🎉🎉 Welcome to Maho 26.3.0 "Time Warp" 🎉🎉
We're barely two months into 2026 and Maho keeps accelerating. After the landmark multi-database and gift card release in 26.1.0, we've packed so many features into this release it feels like we're bending time.
Highlights include a one-step checkout, a product feed manager, content versioning, email logging, deferred image generation, bento grid layouts for our page builder WYSIWYG, blog categories, and even a new shipping method!
Creating Maho is a massive effort that requires all the help possible, please join our sponsorship program.
It will make all the difference in the world!

Maho rocks! 🚀
https://mahocommerce.com
https://demo.mahocommerce.com
🚀 New features and major improvements
One-Step Checkout
Checkout is the most critical conversion point in any online store, and multi-step checkouts are a proven source of cart abandonment. Maho now ships with a built-in one-step checkout that displays all checkout steps simultaneously in a clean, responsive 2-column layout.
This also provides a new unified discount/giftcard code input for both cart and checkout, a unique and simple way for users to input their coupons.
- All steps visible at once - billing, shipping, payment, and order review on a single page
- Auto-loading shipping methods - rates appear as soon as an address is entered
- Smart auto-selection - when only one shipping or payment method is available, it's pre-selected
- Fully configurable via admin toggle - switch between classic multi-step and one-step with a single setting
- 100% backward compatible with existing checkout customizations
FeedManager: Product Feed Export
Selling on Google Shopping, Facebook/Meta, Bing, Pinterest, or any marketplace? Nowadays it's a mandatory activity for every store and the platform should provide the best and most complete way to accomplish it. The new FeedManager module gives you a complete product feed export system built right into Maho - no third-party extensions needed.
- Visual feed builder - drag-and-drop field configuration for XML, CSV, and JSON formats
- Pre-built templates for Google Shopping, Meta Commerce, Bing, and Pinterest
- Dynamic attribute rules - transform, concatenate, and conditionally map product data
- Product filtering and category mapping - control exactly what goes into each feed
- Automated delivery - schedule exports via cron with SFTP/FTP upload destinations
- Batch processing - handles large catalogs without timeouts
Content Versioning
Ever accidentally overwritten a CMS page and wished you could go back? The new Maho_ContentVersion module automatically snapshots CMS pages, CMS blocks, and blog posts on every save.
- Versions tab in every edit form with preview and one-click restore
- Configurable retention - set maximum versions per entity and maximum age
Email Logging
Every outgoing email is now logged to a dedicated database table via a Symfony Mailer transport decorator - completely transparent, no configuration needed. Perfect for debugging delivery issues, auditing transactional emails, and compliance.
- Admin grid at System > Tools > Email Log with filtering, search, and detail view
- Configurable auto-cleanup via daily cron job
ShippingBridge: External Shipping Rate APIs
The new Maho_ShippingBridge module lets you connect to any external shipping rate API with zero custom code. Configure a REST endpoint, and Maho will POST cart data (items, quantities, product attributes) and map the JSON response back to standard shipping rates. This is especially important for medium/big companies with their internal CRM/PIM and custom shipping calculation rules. Simply deploy your API endpoint and manage precise shipping costs and possibilities to your customers.
- Three auth modes - API key, Bearer token, or no auth
- Configurable product attribute inclusion - send weight, dimensions, or any custom attribute
- Debug logging for troubleshooting
- Method logos - add a graphic logo for every shipping option
- Handles all product types: simple, configurable, bundle, and grouped
Blog Categories
The Blog module now has a full hierarchical category system, bringing it on par with dedicated blogging platforms.
- Nested tree structure - unlimited parent/child nesting with drag-and-drop reordering in admin
- Admin interface - category grid, edit form, and AJAX post associations
- Frontend sidebar styled as layered navigation for intuitive browsing
- SEO-friendly URLs - full-path slugs like
/blog/category/parent/child/ - Breadcrumbs - proper navigation context on category and post pages
Bento Grid for TipTap WYSIWYG
Maho is always on the path of building a modern and complete page building experience and today marks another step forward, our WYSIWYG editor gains a powerful new layout tool: bento-style CSS Grid layouts. Think Pinterest boards or Apple's product pages - asymmetric, visually striking grid compositions right inside your CMS editor.
- 12 layout presets across 2, 3, and 4-column configurations
- Drag-to-resize column handles (also retrofitted to the existing Columns extension)
- Bubble menu controls for quick layout adjustments
- Style options - padding, gap, background, borders
- Responsive collapse - gracefully stacks on mobile
- Shared grid infrastructure between Bento and Columns extensions
Deferred Image Thumbnail Generation
Product image thumbnails are no longer generated synchronously during page render. On a cache miss, instead of blocking the entire page for 10-15 seconds while thumbnails are created, Maho now returns a signed URL that lets the browser fetch and generate each thumbnail in parallel via a dedicated controller.
- HMAC-SHA256 signed tokens prevent abuse
- Parallel generation - the browser requests all missing thumbnails concurrently
- Zero overhead for cached images - they continue serving as direct static URLs
- Dramatically improves first-load performance after cache flushes or new product imports
Complete Serialize-to-JSON Migration
This is one of those changes that doesn't sound flashy but is massive for security and cross-database compatibility. PHP's serialize()/unserialize() has been a perennial source of object injection vulnerabilities, and it's completely incompatible with PostgreSQL and SQLite.
We've migrated every single serialize call across the entire codebase to JSON - over 72 callsites across 41 files, covering rule conditions, product options, EAV attributes, widgets, quote addresses, order shipments, and more. The infrastructure changes to _serializeField()/_unserializeField() auto-propagate dual-read (JSON-first with unserialize fallback) to all consumers, including third-party modules. Batch migration scripts are included for existing databases.
Alongside this, we added cross-database JSON query helpers (getJsonExtractExpr, getJsonSearchExpr, getJsonContainsExpr) to the DB abstraction layer, replacing fragile LIKE patterns with native JSON operations across MySQL, PostgreSQL, and SQLite.
Important, but not major
- Admin product grid COUNT query performance - Changed joins from INNER to LEFT so they're stripped from COUNT queries, reducing grid load from 3-5+ seconds to under 200ms on large catalogs
- Gift card refund cap fix - Fixed credit memos refunding the entire order total to the gift card instead of capping at the original gift card amount used
- MySQL 8.0+ report statistics compatibility - Fixed TypeError in
Locale::date()andONLY_FULL_GROUP_BYerrors in 10 report aggregation queries - MySQL 9.6 FK constraint fix for product imports - Fixed a MySQL 9.6 behavioral change that broke bulk product imports
- Web installer sample data fix - Fixed FK constraint violations when importing sample data via the web installer
- Scrollable TipTap editor with pinned toolbar - Toolbar stays accessible while content scrolls independently
- Updated TipTap from 3.16 to 3.19.0
- Fixed TipTap HTML comment text leaking as visible content
- Test email button and queue control in Mail Sending Settings - Verify SMTP configuration from admin and optionally bypass the email queue
- GTIN and MPN as default product attributes - Standard identifiers required by Google Shopping, Meta Commerce, Amazon, and other marketplaces
- Customizable demo store notice - Three modes: disabled, custom text, or CMS block. Also removed legacy browser capabilities detection
- Keep Frame and Background Color settings for product images - New admin settings under Catalog > Product Image
- FrankenPHP compatibility - Added
frankenphpto the recognized SAPI list - Web installer now uses direct method calls instead of HTTP self-calls - Fixes installer in Docker and containerized environments
- Localization options in installer - Region/state import and language pack installation for non-English locales
- No-cache headers on all admin responses - Prevents stale cached pages from reverse proxies and browsers
- Early 404 for static asset requests - Avoids full Maho bootstrap for missing images/CSS/JS/fonts
- Linked products respect out-of-stock display setting
- Gift card totals in PDF invoices and credit memos
- Fixed ConfigurableSwatches hardcoded .png extension - Now respects configured image format (e.g., WebP)
- Fixed checkout exception handling - Always returns JSON instead of a generic 503 page
- Fixed encryption key regeneration crash with legacy M1 keys
- Fixed memory exhaustion during encryption key re-encryption - Now processes in batches of 1000 rows
- Fixed AJAX add to cart breaking file upload custom options
- Fixed currency dropdowns for regional locales - Now shows all 307 currencies instead of ~11
- Fixed email template file lookup in Composer installs
- Fixed SOAP API in Composer installs
- Fixed sendmail transport blocking HTTP requests
- Fixed bulk attribute update form and field toggle crash / #620
- Fixed Db\Expr in UNION processing - Fixes catalog rule price reindexing in multistore setups
- Fixed duplicate key error during bulk website assignment
Less important changes and fixes
- Replaced admin grid pager arrows with SVG icons
- Improved slideshow image display with object-fit cover
- Added template directive processing to blog post content
- Fixed payment methods display for virtual orders in one-step checkout
- Fixed "headers already sent" error from Wishlist Collection
- Fixed fatal error with orphaned configurable super attributes
- Fixed PHP 8.5 deprecation in SalesRule address validation cache
- Fixed DynamicRule missing getConditions() method
- Fixed orphaned reorder sidebar layout references
- Fixed false positive orphaned skin directory warning in health-check
- Avoided unnecessary payment_method_is_active event on every page load
- Fixed admin:user:create failing when admin role has different name
- Made Altcha captcha texts translatable
- Skip confirmation prompt when install --force is used
- Added support for subdirectories in CLI commands
- Replaced broad data-* skip in JS defer with explicit data-maho-nodefer
- Skip JS preload hints when load-on-intent mode is active
- Pass store exceptions to error reporting
- Removed maho_ prefix from CustomerSegmentation resource code
- Removed redundant giftcard observer on every block render
Code quality & modernization
- Added declare(strict_types=1) to 648 type-safe files - Custom Rector rule ensures no runtime behavior changes
- Fixed PHPStan errors after upgrade to 2.1.39
- Refactored Weee total collector to fix PHPStan false positive
- Fixed incorrect @package docblock in 36 base_default theme files
- Fixed incorrect getUserParam() usage in controllers - Replaced all
getUserParam()withgetParam()across admin controllers
Security improvements
- Security hardening across multiple subsystems - Ownership verification for file downloads, innerHTML replaced with safe DOM construction, ADMIN_RESOURCE ACL constants added to controllers, LIBXML_NONET for API XML parsing, unescaped output fixed, exception stack traces gated behind developer mode
- Block sensitive file extensions in early 404 guard - Database dumps, backup files, PHP scripts, certificates, and config files blocked at the gate
Dependencies & infrastructure
- Added symfony/filesystem as production dependency - Fixes production-breaking image handling bug in non-dev Composer installs