Skip to content

Maho 26.5.0 is out today!

Following the sprint of 26.3.0, this release goes deeper into the engine room: new flagship modules (PayPal, AI, Intelligence), a wave of core modernizations (typed routing, PHP attributes for observers and cron, rewritten date APIs), and the usual long tail of improvements, fixes and polish.

26.5.0 is one of the most ambitious modernization releases Maho has ever shipped.

Highlights

  • Brand-new Maho_Paypal module: Rebuilt from scratch on the PayPal JS SDK v6 and the official PayPal Server SDK.
  • Real-time EU VAT validation: VIES checks directly in checkout and address forms, with caching and offline fallback.
  • Symfony Routing with #[Route] attributes: Static, introspectable, ~7× faster matching on average.
  • Observers and Cron Jobs as PHP attributes: Native, compiled at build time, with the entire core migrated.
  • New Maho_Ai module: First-class multi-provider LLM platform on top of symfony/ai.
  • New Maho_Intelligence module: LSP and MCP server exposing the merged runtime config to editors and AI agents.
  • Official editor plugins: First-party Maho extensions for PhpStorm, VS Code, and Zed.
  • Vanilla JS image editor: Custom Canvas-based editor with on-device AI background removal.
  • Refactored date management APIs: Clear UTC/store semantics encoded into method names, ~130 files migrated.
  • Admin Health Check page: Configuration drift and misconfigurations surfaced at a glance.

New features and major improvements

Brand-new Maho_Paypal module on PayPal v6 SDK

The legacy Mage_Paypal module was a sprawling, decade-old monolith carrying SOAP IPN flows, Bill Me Later, and a lot of cruft. We threw it out and rebuilt PayPal integration from scratch on top of the PayPal JS SDK v6 and the official PayPal Server SDK. Production tested by one of our partner stores based in UK.

  • Three payment methods: Standard Checkout (PayPal Buttons, Pay Later, etc.), Advanced Checkout (PCI-compliant hosted card fields where card data never touches your server), and Vault (saved payment methods for both frontend and admin order creation)
  • Full payment lifecycle: Authorize, Authorize and Capture, partial/full capture, partial/full refund, void, fetch transaction info
  • Configurable button placement: checkout, shopping cart, product page
  • Pay Later messaging on product and cart pages, with currency passed through and auto-hidden on out-of-stock products
  • Vault with a dedicated My Account > Saved Payment Methods page and admin order creation support
  • Test Connection and Register Webhook buttons in admin, plus ./maho paypal:webhook:simulate for local testing

Upgrade note

Mage_Paypal is gone, no shim, no BC layer. Stores upgrading from 26.3.0 (or earlier) must reconfigure PayPal under the new Maho_Paypal module: obtain a v6 Client ID / Client Secret from your PayPal developer dashboard, enable the desired payment methods (Standard / Advanced / Vault), click Test Connection, then Register Webhook. The legacy paypal_express, paypal_direct, paypal_standard, paypaluk_*, verisign, payflow_*, and hosted_pro methods will no longer process orders. Any custom module that references Mage_Paypal_* classes or the maho_paypal/* alias must be updated (the alias was renamed to plain paypal/*).

Real-time EU VAT number validation

EU merchants know the pain: customers enter a VAT number, and you only discover it's invalid (or that the company name doesn't match) when accounting runs the books weeks later. Maho 26.5.0 ships real-time VAT validation against the official VIES service directly in the checkout and customer address forms. Wrong number? The customer fixes it before placing the order, not three weeks later.

  • Format validation via regex patterns for 30+ countries (EU, GB, CH, NO), with online VIES validation for EU countries
  • Cached results (configurable lifetime, default 24h) to reduce VIES API calls
  • Offline fallback mode: when VIES is unavailable, format-valid VAT numbers can optionally be accepted
  • Triggers on field blur and country change, on both admin and frontend address forms (including one-step checkout)
  • Existing checkVatNumber() callers benefit automatically from the new cache + offline fallback

Routing migrated to Symfony Routing with #[Route] attributes

The old XML router and getFrontName() chain were powerful but opaque, hard to debug, and impossible to introspect statically. No more.

Maho 26.5.0 migrates the entire routing layer to symfony/routing with PHP attributes directly on controller actions. Routes compile to a static matcher and generator on composer dump-autoload, so every URL is discoverable at design time, and matching is dramatically faster: in our benchmarks, ~7× faster on the mean and ~11× faster at the p99.

#[Maho\Config\Route('/catalog/product/view/{id}', methods: ['GET'], requirements: ['id' => '\d+'])]
public function viewAction() { ... }
  • Area auto-detection based on the controller's base class (frontend, adminhtml, install)
  • Admin frontName resolved at runtime, so you never hard-code it
  • HTTP method allow-list, regex requirements, named routes for URL generation
  • Full backward compatibility with legacy <frontend><routers> XML, evaluated before the Symfony matcher, preserving the historical "first declared wins" precedence
  • Admin/frontend controller override chains still work via <modules before|after="…"/> config

Documentation: mahocommerce.com/routing

Observers and Cron Jobs as PHP attributes

Maho 26.5.0 introduces a native PHP attribute alternative to XML-registered observers and cron jobs, and the entire core has been migrated to it.

#[Maho\Config\Observer('catalog_product_save_after')]
public function handleEvent(\Maho\Event\Observer $observer) { ... }

#[Maho\Config\CronJob('my_cron_job', schedule: '0 2 * * *')]
public function runJob(Mage_Cron_Model_Schedule $schedule) { ... }
  • Attributes are compiled at build time by maho-composer-plugin via composer dump-autoload, no per-request overhead
  • Compiled observers use class aliases (not FQCNs), so the rewrite system is fully respected (third-party rewrites still apply transparently)
  • XML and compiled observers go through the same module-dependency sort, no separate code paths
  • replaces: parameter lets an attribute-based observer replace an XML-registered one for clean overrides
  • Cron jobs run with per-job exception isolation, one failure no longer kills the whole run

Documentation: mahocommerce.com/observers and mahocommerce.com/cron

New Maho_Ai module: multi-provider LLM platform

Maho now has a first-class AI integration layer built on symfony/ai. Configure your preferred LLM provider once, and any Maho module or third-party extension can use it through a unified interface via Mage::helper('ai')->invoke(...).

More AI features will come to Maho in the future, but this module is the base for all core and custom AI functionalities. If you're developing a Maho store or a module and need something-AI, ask the core for the credentials and let the industry-leading symfony/ai handle the rest.

  • Seven built-in providers routed through symfony/ai-platform bridges: OpenAI, Anthropic, Google, Mistral, OpenRouter, Ollama (local / self-hosted), and a Generic OpenAI-compatible bridge (LiteLLM, vLLM, any custom host)
  • Three capabilities: chat, embeddings, image generation, depending on the provider
  • Async task queue with cron sweep, callback dispatch, retry, and stuck-task recovery
  • Vector storage (maho_ai_vector table) for embeddings
  • Safety guardrails: 15 prompt-injection patterns, admin-configurable blocklist, output sanitiser, PII detection
  • Admin pages: Tasks, Usage telemetry, Reindex, and System Configuration with a model-fetch button
  • Extensible: community providers can extend Maho_Ai_Model_Platform_Symfony and add custom shapes (e.g. video)

Documentation: mahocommerce.com/ai

New Maho_Intelligence module: LSP + MCP server

For developers and LLM coding agents, this is a game-changer. The new Maho_Intelligence module exposes the full merged runtime configuration of your store, class aliases, rewrites, events, layout handles, EAV attributes, routes, admin menu, ACL resources, cron jobs, and more, through both a Language Server Protocol implementation and a Model Context Protocol server.

  • MCP server with 11 tools for AI agents: resolve_alias, list_aliases, list_rewrites, list_events, get_merged_config, list_modules, list_config_paths, list_layout_handles, list_cron_jobs, list_tables, list_acl_resources
  • LSP server with 4 capabilities for editors: completion inside Mage::getModel()/helper()/getSingleton()/getStoreConfig()/dispatchEvent(), go-to-definition that jumps from alias string to the resolved PHP file, hover info with class/file/rewrite chain, and diagnostics that warn on unresolved aliases
  • Two CLI commands: ./maho dev:mcp:start and ./maho dev:lsp:start
  • Works with any MCP-compatible AI agent (Claude Code, Cursor, Windsurf, VS Code + Copilot, Zed) and any editor with native LSP support (Neovim, Sublime Text via the LSP package)
  • Structural XML autocomplete with a dynamic index for config.xml, system.xml, and layout files

Official editor plugins

With 26.5 we're shipping three first-party editor extensions that wire the LSP up automatically the moment you open a Maho project (detected by the presence of a maho CLI file in the project root). All three provide completion, hover, go-to-definition, and diagnostics across both PHP and XML files, including class alias completion ('catalog/product'), config paths, event names, layout handles, template paths, block types, observers, rewrites, and cron callbacks.

  • Maho for PhpStorm is published on the JetBrains Marketplace. Requires PhpStorm 2026.1+
  • Maho for VS Code / VSCodium is published on the Open VSX Registry (VS Code Marketplace listing in progress)
  • Maho for Zed ships as a manual-install extension today, marketplace listing pending

All three plugins support custom PHP paths and Docker-based PHP execution (e.g. docker exec mycontainer php) for containerized dev environments.

Vanilla JS image editor with local AI background removal

We replaced Filerobot Image Editor with a custom vanilla JS editor built on the Canvas API: zero dependencies, ~900KB shaved off, fully maintained in-tree. The killer feature: on-device AI background removal, running locally in the browser with zero data leaving your machine.

  • Tools: Crop (freeform or preset aspect ratios), Resize (interactive handles or manual entry), Transform (rotate, flip), Adjust (brightness, contrast, hue, saturation, blur, warmth), Annotate (rectangle, ellipse, arrow, line, freehand, text with font picker), Redact (solid or pixelated, destructive on export), Frame (solid fill, stroke, drop shadow, polaroid)
  • AI Background Removal powered by the BEN2 ONNX segmentation model via Transformers.js, using WebGPU when available and WASM as fallback. Model downloaded once and cached by the browser. After removal you can apply a solid color or gradient (linear/radial) background
  • Editor UX: mouse-wheel zoom centered on cursor, Space/middle-click pan, 30 levels of undo/redo (Ctrl+Z, Shift+Ctrl+Z), keyboard shortcuts, single-canvas rendering pipeline so what you see is what you export
  • Dynamic loading via import(), zero impact on page load when the editor isn't opened

Refactored date management APIs

Date handling is a complicated business, especially when you deal with worldwide timezones. Maho 26.5.0 ships a complete API rewrite with clear, opinionated semantics: DB columns are always UTC, conversions happen at the boundary, and method names encode the timezone so you can tell what's what just by reading a call site.

$locale->formatDateForDb('now');               // 'Y-m-d H:i:s' UTC, for DB columns
$locale->nowUtc();                             // UTC string for logs/CSV/API
$locale->utcToStore();                         // DateTimeImmutable in store timezone
$locale->utcToStore($store, $utcInput);        // Convert known UTC value to store TZ
$locale->storeToUtc($store, $storeInput);      // Convert known store value to UTC
  • ~130 files migrated to the new API. Fixed three latent mutation bugs exposed by the DateTimeImmutable flip (Giftcard expiration ×2, CustomerSegmentation cutoff, Payment CC expiry)
  • Breaking change for extensions: utcToStore() / storeToUtc() now return DateTimeImmutable instead of DateTime. Mutators like ->modify() / ->setTime() return a new instance, so either chain or reassign
  • Forced DB session timezone to UTC on connect so engines stop disagreeing
  • Fixed cron schedules being stored in the past when store TZ wasn't UTC

Documentation: mahocommerce.com/date-handling

Admin Health Check page

A new System > Tools > Health Check page surfaces configuration drift and common misconfigurations at a glance, complementing the existing ./maho health-check CLI command.

  • Shows Maho, Server, Database (MySQL/MariaDB/PostgreSQL/SQLite aware), PHP, OPcache with expandable directives, and PHP extensions (read from composer.lock)
  • Behind ACL (system/tools/healthcheck)
  • Detection of orphaned API ACL resources and orphaned role resources
  • Health check + CLI commands for legacy XML observer/cron migration

Improved cron management in admin

A redesigned System > Tools > Cron Jobs page replaces the old schedule history grid with a full overview of all defined cron jobs.

  • Schedule (with human-readable description), callback, last run, next run, and enabled/disabled status for every job
  • Run Now opens a modal with a live timer; the job runs in background via fastcgi_finish_request and the modal polls for completion
  • Enable/Disable jobs individually or via mass actions, persisted as per-job crontab/jobs/{job_code}/schedule/enabled config nodes
  • History dialog shows the last 50 executions with status, duration, and messages, plus a Clear History button
  • CLI: cron:list shows enabled/disabled status, cron:run warns about disabled jobs
  • Admin warning when cron isn't running

And much more, be sure to check the full release announcement.