Skip to content

Maho 26.7.0 is out today!

Maho keeps accelerating: 26.7.0 lands with a completely rewritten API (REST v2, GraphQL, JWT auth, OpenAPI docs), a brand-new admin design with light and dark mode, and a declarative database schema system that replaces two decades of imperative upgrade scripts.

With 26.7.0, Maho gets a brand-new API and a brand-new face.

Highlights

  • The new API on API Platform: ~140 REST endpoints, GraphQL, JWT auth, granular permissions, OpenAPI docs. Ships as beta.
  • New backend design: complete admin redesign with light and dark mode, CSS-first, zero new dependencies.
  • Declarative DB schema: modules describe their target schema, Maho converges the database automatically.
  • Frontend 2FA: optional (or mandatory) TOTP two-factor authentication for customers.
  • Maho_Revocation: the EU-mandatory revocation button (Directive 2023/2673), built in.
  • Schema.org structured data: JSON-LD for products, breadcrumbs, organization, site search and blog posts.
  • Layered navigation SEO: noindex for filtered/paginated pages, canonical defaults, nofollow filter links.
  • PDF attachments for invoice, shipment, and credit memo emails.
  • Maho_MediaCleaner: find and clean orphan media files from the admin.
  • Bestsellers and On Sale widgets: merchandising blocks powered by data Maho already collects.

New features and major improvements

The new API: REST v2, GraphQL, JWT auth, granular permissions and OpenAPI docs

The one we've been working on for a long, long time. Maho's API has been rewritten from the ground up on API Platform, the amazing framework that generates REST and GraphQL endpoints, validation, serialization and OpenAPI documentation from a single set of resource definitions. Huge thanks to the API Platform team for such a solid foundation to build on.

Given the sheer surface area of this rewrite, Maho_ApiPlatform should be considered beta in 26.7.0: it's backed by 565 automated tests and ready to build on, but expect refinements in the next releases before we call it stable.

  • ~140 REST endpoints (212 operations) covering products, categories, orders/invoices/shipments/credit memos, customers, carts and guest carts, full checkout, CMS, blog, reviews, wishlists, newsletter, coupons, gift cards, inventory, tax, directory and stores
  • Dual protocol: every resource is available over REST (JSON/JSON-LD) and GraphQL, sharing the same providers and processors
  • JWT authentication (revocable tokens, per-request re-validation) with customer, client_credentials, and legacy api_user grants
  • Granular resource/operation permissions with a new admin role/user editor and store-scoped service accounts
  • HTTP caching (ETag/304 with tagged invalidation), DB-backed idempotency keys, rate limiting, CORS allowlist
  • OpenAPI 3.1 spec at /api/docs.json
  • Extensible: third-party modules add resources with a single #[Maho\Config\ApiResource] attribute and extend DTOs via events
  • New CLI commands to scaffold and inspect resources: ./maho dev:api:resource:create and dev:api:resource:list

The new API role editor with granular per-resource permissions

Upgrade note

All API protocols (including legacy SOAP/XML-RPC/JSON-RPC/REST) now default to OFF and must be re-enabled under System > Configuration > Services > API Platform. Legacy SOAP/XML-RPC/JSON-RPC need their laminas package installed, and nginx/Caddy setups need the documented rewrite rules for rest.php. The Mage_Api and Mage_Api2 modules are now deprecated.

New backend design with light and dark mode

The admin backend got a complete redesign: CSS-first, token-driven, zero new dependencies, no build step. A neutral graphite palette with Maho's chartreuse as the single brand accent, tuned for WCAG AA.

  • Automatic dark mode following your OS, plus a manual header toggle (system → dark → light) persisted and applied pre-paint, no flash
  • Everything restyled: header with pill global search, floating dropdown menus, ledger-style grids with unified toolbars, canonical form controls, tabs, system config accordion, dashboard, dialogs, media browser, login pages
  • Collapsible global search with full ARIA keyboard navigation and screen-reader support
  • 71 legacy GIF-era images deleted, float-based layouts replaced with flexbox, and the whole admin moved to relative units so it respects your browser font-size

Read the full story in the admin redesign blog post.

Declarative DB schema system on top of Doctrine DBAL

A fundamental architectural shift: each module now ships a sql/schema.php describing its target table structure, and Maho reconciles the live database against it automatically via Doctrine DBAL's Comparator - no more imperative version-bumped upgrade scripts for schema work.

  • All 47 core table-owning modules converted; existing installs migrate in place, idempotently, landing byte-identical to a fresh install on MySQL/MariaDB/PostgreSQL (SQLite handled via table rebuilds)
  • A Canonicalizer strips representation-only noise so only genuine structural deltas are applied; undeclared columns and tables are preserved
  • Data work stays imperative: legacy sql/ and data/ scripts coexist and run after the declarative phase, third-party modules keep working unchanged
  • Legacy '0000-00-00' zero-date sentinels finally replaced with proper nullable columns
  • The maho_setup mechanism has been retired, its scripts re-homed as ordinary module-version-gated upgrades

Upgrade note

Run ./maho migrate after updating. Custom indexes/FKs added directly to managed core tables are dropped on migration unless declared in a module's own schema.php (custom columns and data survive).

Optional TOTP-based 2FA for frontend customers

The TOTP two-factor authentication that already protected the admin is now available to frontend customers, opt-in per customer, with merchant toggles to allow it and even make it mandatory.

  • Customers manage 2FA from a dedicated account page: QR scan, enable with password + live code, disable with password
  • Two-step login: the login form detects 2FA and reveals a code field, mirroring the admin flow
  • Passwordless paths respect it too: magic-link and post-confirmation auto-login redirect to a TOTP challenge, and programmatic logins fail closed for enrolled customers
  • Mandatory mode forces logged-in, un-enrolled customers to the setup page while keeping catalog/CMS browsing accessible
  • Secrets are encrypted at rest

The two-factor authentication enrollment page in the customer account

New Maho_Revocation module: the EU mandatory revocation button

Since 19 June 2026, Directive (EU) 2023/2673 requires B2C shops selling into the EU to provide a revocation button. Maho now ships it as a first-class core module - no third-party extension needed.

  • Unauthenticated /revocation form, a merchant-placed CMS widget button, and a my-account entry point shown within a configurable 14-day cooling-off window
  • A revocation_request table acts as the legal receipt (written before any email, UTC timestamps, strict order matching so the public path can never touch someone else's order)
  • Layered invisible abuse protection - honeypot, render-timestamp check, Altcha, per-IP and per-email rate limits - since manual CAPTCHAs are legally inadmissible here
  • Full admin UI under Sales > Revocation Requests: grid, CSV export, accept/reject with order audit comments, receipt resend, split ACLs

The revocation form on the storefront

More details in the EU revocation button blog post.

Schema.org structured data (JSON-LD)

The new Maho_StructuredData module emits Google-compliant JSON-LD into your pages, improving rich-result eligibility in search. Enabled by default.

  • Product schema: sku, images, brand/GTIN/MPN via admin-mapped attributes, offers for every product type (with AggregateOffer for configurable/grouped/bundle), availability, priceValidUntil from special-price end date, ratings and recent reviews
  • BreadcrumbList (zero extra queries), Organization/OnlineStore/LocalBusiness with contacts and social profiles, WebSite with sitelinks SearchAction, BlogPosting for blog posts, ItemList on listing pages
  • Admin config under Catalog > Structured Data, and every graph passes through events so modules can enrich or suppress output

Layered navigation SEO

Aggressive crawl control for layered navigation, following Google's faceted-navigation guidance: filtered and paginated category views get NOINDEX,FOLLOW, filter links get rel="nofollow", and the category canonical tag is now on by default. No more duplicate content and wasted crawl budget - only clean category URLs compete for rankings.

Upgrade note

The new options default to on and the canonical default changed - if you intentionally indexed filtered/paginated URLs, review the settings under Catalog > Search Engine Optimizations.

PDF attachments for invoice, shipment, and credit memo emails

A classic merchant request, now in core: a per-store "Attach PDF to Email" setting for each of invoice, shipment, and credit memo emails (default off). PDFs are regenerated at send time via the existing renderers, working on both the direct-send and queued email paths - no new module, no schema change.

New Maho_MediaCleaner module: find and clean orphan media files

The popular community module Fballiano_ImageCleaner joins the core, rebuilt with modern Maho idioms as System > Tools > Media Cleaner.

  • Scans for orphan media by type (category images, product images, product image cache, WYSIWYG assets) with an AJAX grid, thumbnail preview, download, and single/mass delete
  • One-click flush of working directories: media/tmp, media/import, var/export, var/importexport
  • Hardened with forced form keys and proper ACL, and aware of Maho's WebP image cache

The Media Cleaner grid listing orphan media files with thumbnails

Bestsellers and On Sale product widgets

Two new merchandising widgets for data Maho already collects: a Bestsellers widget driven by real sales data (with period filters: all time, this year, this month, last 30/7 days) and an On Sale widget built from today's active catalog price rules (with optional single-rule selection for "offer of the month" campaigns, and ordering by newest, bestselling, biggest discount or random). Both work on MySQL, PostgreSQL and SQLite.

Attribute-based controller overrides, eliminating the last routing XML

The routing migration started in 26.5.0 is now complete: overriding an existing controller needs only a plain subclass - no XML, no attribute. The compiler detects it at composer dump-autoload and points the route at the most-derived class, with structural precedence regardless of module load order. Legacy XML <modules> chains still win for backward compatibility, and legacy:migrate-routes now migrates them too.

A word about the project

This cycle also brought news we're incredibly proud of: Maho has been selected for NLnet's NGI TALER Fund! A heartfelt thank you to NLnet and the European Commission's Next Generation Internet programme, their support will bring amazing things to Maho and to independent open source ecommerce. On top of that, we raised the bar on quality and security across the whole organization: immutable releases, a hardened supply chain, daily vulnerability scanning, and public SBOMs for every release.

And much more: shipment cancellation, RFC 8058 one-click unsubscribe, Meta Pixel Advanced Matching, a centralized locking service, a big wave of PayPal and Feed Manager fixes, and dozens of other improvements. Be sure to check the full release announcement.

If Maho helps your business, consider supporting its development:

Become a sponsor