5 min readAug 14, 2026by jakub
Changelog
Current version: 2.0.0
Combined history for qoliber/omnibus-directive and its two optional
companions. qoliber/mysql-utils and qoliber/hyva-module-registration are
shared dependencies with their own release cycles and are not tracked here.
2.0.0 — 2026-08-13
Omnibus Directive
Findings F1–F24 refer to the repository's code-review audit, which documents each one in full: the defect, the file and line as originally imported, the failure it caused, the fix, and the test (where one exists) that proves it.
Removed
- BREAKING The Hyvä presentation layer — layouts, templates, and
ViewModel\HyvaHistoricalPrice— moved to the newqoliber/omnibus-directive-hyvapackage. This module no longer renders anything on a Hyvä storefront by itself; stores running Hyvä must also install and enableQoliber_OmnibusDirectiveHyva. The pricing pool wiring, the registry,GetDynamicPrice, andModel\Configurationstay here and are shared by both storefronts. qoliber/coredependency, replaced by a<tab id="qoliber">declaration in this module's ownsystem.xml(see F23 below).
Changed
- BREAKING
Model\Configuration's five getters (isEnabled,getProductPricesType,isShowOnPlp,isShowOnPdp,isAlwaysShow) now accept an optional store code and resolve atScopeInterface::SCOPE_STORE;etc/adminhtml/system.xmlopens the section, its group, and all five fields toshowInWebsite="1" showInStore="1"(F7). A multi-store install can now set the Omnibus configuration per store view, which was not possible before. - BREAKING The price-recording observer was renamed
Observer\UpdateHistoricalPriceAdminhtmlObserver→Observer\UpdateHistoricalPriceObserverand rebound fromcatalog_product_save_after(global, but a no-op — see F2) tocatalog_product_save_before(global).etc/adminhtml/events.xml, which duplicated the binding for the admin area only, was deleted. composer.json:"license"corrected to"proprietary"; explicitphp(~8.1.0||~8.2.0||~8.3.0||~8.4.0||~8.5.0) andmagento/frameworkconstraints added; theqoliber.dev"source"block dropped (F19, F20, F21).
Fixed
- F1
Service\GetDynamicPrice::execute()treated a registry miss as a real price of0.0instead of falling back to a per-product query, becauseHistoricalPriceRegistry::getPrice()(F10) always returned afloat, nevernull. Any product outside a bulk-loaded registry silently lost its historical price. Now branches onisBulkLoaded() && hasPrice(). - F2 The price-history observer was bound to
catalog_product_save_afterglobally and tocatalog_product_save_beforeonly underadminhtml. Onsave_afteritssetData()calls are never persisted, so REST, SOAP,bin/magentoimport, and ERP-driven price changes — most real-world price changes — recorded no history at all. Now bound once, tocatalog_product_save_before, globally. - F3
Model\Indexer\MinPrice::executeList()issued oneSELECTper price row to read the existing minimum (measured: 8278 queries over an 8156-row index). Replaced with one batchedSELECT ... WHERE product_id IN (?)per call (1687 queries after). - F4
getAllProductIdsBatch()hardcodedentity_type_id = 4for thestatusattribute. Now resolved viaMagento\Eav\Model\Config. - F5
deleteOldPrices()ran once per 1000-product batch insideexecuteList()instead of once per reindex. Hoisted toexecute(),executeFull(), andexecuteRow(). - F6 The product-status join filtered
attribute_idbut notstore_id, so a product with a store-scoped status value was yielded once per scope row (12 duplicates measured on this catalogue). Addedcpev.store_id = 0. - F7 See "Changed" above.
- F8
Plugin\Block\Product\AbstractProductPluginwas anaroundplugin that called$subject->getDetailsRenderer('historical_price')with no null guard.getDetailsRenderer()returnsnullwhenever a layout has no renderer-list block at all, which fatals the unguarded call. Converted toafter, added a null/instanceofguard, and an explicitisShowOnPlp()check. - F9
Pricing\Render\HistoricalPriceBox::__construct()used implicit nullable parameters, deprecated as of PHP 8.4. Made the?Typenullability explicit. - F10
HistoricalPriceRegistry::getPrice()cast a missing entry to0.0. Now returns?float;hasPrice()remains the presence check. - F11 the Hyvä Tailwind safelist template (now in
qoliber/omnibus-directive-hyva) built a$classesarray that was never output — Tailwind's regex file scanner picked it up regardless, so the mechanism worked by accident. Now rendered into a hidden element so intent and mechanism agree. - F12
system.xmlgave three fields the samesortOrder="10". PHP 8's stable sort meant declaration order was preserved regardless, so this was a determinism/hygiene fix, not a live rendering bug. Renumbered 10/20/30/40/50. - F22 Categories with Display Mode "Static block only" render their product
grid through
Magento\CatalogWidget\Block\Product\ProductsList, whose renderer list (category.product.type.widget.details.renderers) this module never targeted — only the native category grid's list was wired. Every such category showed no historical price at all. Addedview/frontend/layout/catalog_widget_product_list.xmlregistering the same renderer on the widget's list. - F23
etc/adminhtml/system.xmlreferenced<tab>qoliber</tab>with no matching<tab id="qoliber">declared anywhere — previously supplied by the now-droppedqoliber/corepackage. Magento throws while assembling the tab tree, which broke Stores → Configuration for every admin user, not only this section. The module now declares its own tab and no longer depends on another Qoliber package to be installable. - F24
MinPrice::executeList()computed the minimum acrossprice,final_priceandmin_price. Composite types (grouped, bundle, downloadable) carryNULLinprice/final_priceincatalog_product_index_price; PHP'smin()ranksNULLbelow any real number, so it was chosen over a genuinemin_price, and MySQL coerced thatNULLto0in theNOT NULLindex column — a permanent, silent "price has never dropped" for every composite product. Non-applicable candidates are now filtered out before the minimum is taken, and a row is skipped entirely rather than written as a fabricated0.
Known limitations
- F4, F9, F11, F21 have no dedicated falsifying test — each is a portability, hygiene, or packaging fix with no observable behavioural difference on the reference installation.
Omnibus Directive for ElasticSuite
Fixed
- ElasticSearch lookups never executed: the service called
Layer\Resolver::create()at view time, which throws once the catalog controller has created the layer, and a barecatch (\Exception)silently fell back to MySQL. The service now consumes the resolved layer. - The database fallback queried
website_id = 0because a null website id was cast to int. - Fallbacks are logged instead of discarded.
Removed
- BREAKING
GetDynamicPricePlugin, which walked the whole layer collection once per product on a listing page while bypassing the registry. - BREAKING
ElasticSearchHistoricalPriceService::getHistoricalPriceForProduct(), whose only caller was that plugin.
Changed
- Depends on
RequestInterfacerather than the concreteHttprequest. - Requires
qoliber/omnibus-directive^2.0 and PHP 8.1–8.5.
1.0.2 — 2025-10-16
Omnibus Directive for ElasticSuite
Fixed
- Fixed ElasticSearchHistoricalPriceService for better compatibility with ElasticSuite
1.0.1 — 2025-09-17
Omnibus Directive for ElasticSuite
Changed
- Updated HistoricalPriceData datasource to align with changes in main OmnibusDirective module
- Improved integration with OmnibusDirective configuration changes
1.0.0 — 2026-08-13
Omnibus Directive for Hyvä
Released 2026-08-13.
Added
- Initial release. The Hyvä presentation layer moves here out of
qoliber/omnibus-directive, which shipped it up to and including 1.0.6. ViewModel\HyvaHistoricalPrice, exposing the historical price to Hyvä templates without pullingHyva\Themeclasses into the core module.- Hyvä layout handles for the product page, category page, search results page,
and the Tailwind safelist template (
hyva_catalog_product_view.xml,hyva_catalog_category_view.xml,hyva_catalogsearch_result_index.xml,hyva_default.xml). - Product list renderer templates (
historical-price.phtmland the Alpine.js varianthistorical-price-alpine.phtml) rendered through the core module's theme-agnosticBlock\Product\List\Renderer\HistoricalPrice.
Notes
- The pricing pool wiring, the registry, the dynamic price service and the
configuration model stay in
qoliber/omnibus-directiveand are shared with the Luma templates; only the Hyvä view layer and itsHyvaHistoricalPriceview model live here.
Omnibus Directive for ElasticSuite
Released 2025-08-28.
Added
- Initial release of Omnibus Directive ElasticSuite integration module
- Implemented ElasticSearch index integration for historical prices
- Added HistoricalPriceData datasource for Smile ElasticSuite fulltext indexing
- Implemented ElasticSearchHistoricalPriceService for retrieving prices from ElasticSearch
- Added plugin for BulkLoadHistoricalPrices to use ElasticSearch when available
- Added plugin for GetDynamicPrice to leverage ElasticSearch for price retrieval
- Implemented elasticsuite_indices.xml configuration for historical price indexing
- Added historical price fields to the ElasticSearch product index:
historical_price(decimal) andhistorical_price_date(date) - Enabled high-performance price retrieval from ElasticSearch instead of MySQL
- Added automatic fallback to the database when ElasticSearch is unavailable
- Implemented dependency on smile/elasticsuite and qoliber/omnibus-directive modules
Performance
- Significantly improved historical price loading performance on category pages using ElasticSearch
- Reduced database queries by leveraging ElasticSearch for bulk price operations
- Optimized price data retrieval for large product catalogs
Integration
- Seamless integration with the Smile ElasticSuite search engine
- Compatible with the OmnibusDirective module's registry and service layer
- Automatic detection and usage of ElasticSearch when the module is enabled