Skip to main content
Version: Next

Upgrade Notes

v2026.1.0

Platform Requirements

  • Added support for PHP 8.5.
  • Removed support for PHP 8.3 and Symfony v6.
  • Removed legacy analytics.js trackers — the following classes have been permanently removed as Google sunset Universal Analytics in July 2023:
    • Pimcore\Bundle\EcommerceFrameworkBundle\Tracking\Tracker\Analytics\AbstractAnalyticsTracker
    • Pimcore\Bundle\EcommerceFrameworkBundle\Tracking\Tracker\Analytics\Ecommerce
    • Pimcore\Bundle\EcommerceFrameworkBundle\Tracking\Tracker\Analytics\UniversalEcommerce
    • Pimcore\Bundle\EcommerceFrameworkBundle\Tracking\Tracker\Analytics\EnhancedEcommerce
  • BREAKING: GoogleTagManager tracker updated from UA Enhanced Ecommerce to GA4 ecommerce schema. Event names, data structure, and item field names have changed:
    • Event names: detailview_item, addToCartadd_to_cart, removeFromCartremove_from_cart, checkoutbegin_checkout, purchase (unchanged)
    • Data structure: flattened (no more nested ecommerce.detail.products — now ecommerce.items)
    • Item fields: iditem_id, nameitem_name, branditem_brand, categoryitem_category, variantitem_variant, listitem_list_name, positionindex
    • Transaction fields: revenuevalue, idtransaction_id
    • Each dataLayer.push() now prepends {ecommerce: null} to clear previous ecommerce data
    • If you parse dataLayer pushes in custom GTM variables/triggers, update your references to match the new GA4 schema.
  • New Gtag tracker (\Pimcore\Bundle\EcommerceFrameworkBundle\Tracking\Tracker\Gtag) — generates direct gtag('event', ...) JavaScript calls for sites using gtag.js without GTM. Disabled by default.
  • 4 new GA4 tracking interfaces added:
    • ProductSelectInterfacetrackProductSelect($product, $list) (GA4: select_item)
    • CartViewInterfacetrackCartView($cart) (GA4: view_cart)
    • CheckoutShippingInfoInterfacetrackCheckoutShippingInfo($cart, $shippingTier) (GA4: add_shipping_info)
    • CheckoutPaymentInfoInterfacetrackCheckoutPaymentInfo($cart, $paymentType) (GA4: add_payment_info)
  • TrackingManagerInterface now extends the 4 new interfaces. Custom implementations of TrackingManagerInterface must add the new methods. You can use the Ga4TrackingManagerTrait to get no-op default implementations.
  • All trackers use TrackingCodeAwareInterface — tracked codes must be rendered manually in Twig templates. See Tracking Manager documentation for details.
  • BREAKING: Tracker formatPrice() now returns ?float instead of string. Price fields (price, value, tax, shipping) are output as JSON numbers instead of strings. null prices are omitted from the output via filterNullValues() instead of being rendered as empty strings. Custom trackers extending GoogleTagManager or Gtag that override transformProductAction(), transformTransaction(), or similar methods should expect numeric/null values from formatPrice().
  • BREAKING: Tracker getCartValue() now returns ?float instead of string. Returns the cart grand total as a float directly, with 0.0 fallback on error.
  • Fix: add_to_cart / remove_from_cart value now reflects total (price x quantity) instead of unit price, matching the GA4 specification.
  • Fix: trackCheckoutStep() fires begin_checkout and ignores $stepNumber / $checkoutOption — GA4 has no concept of checkout steps. Use trackCheckoutShippingInfo() and trackCheckoutPaymentInfo() for GA4 checkout progression.

Removed ExtJS / Admin Classic UI

All legacy ExtJS-based admin controllers and their associated frontend assets have been removed. The Admin Classic UI is no longer supported:

  • Removed src/Controller/AdminOrderController.php
  • Removed src/Controller/ConfigController.php
  • Removed src/Controller/IndexController.php
  • Removed src/Controller/PricingController.php
  • Removed src/Controller/VoucherController.php
  • Removed src/Event/AdminEvents.php — the event constants GET_VALUES_FOR_FILTER_FIELD_PRE_SEND_DATA and GET_INDEX_FIELD_NAMES_PRE_SEND_DATA no longer exist. Remove any listeners registered against these events.
  • Removed all ExtJS JavaScript files under src/Resources/public/js/ (startup, indexfieldselectionfield data/tags, pricing config/item/objects/panel, order/OrderTab, voucherservice/VoucherSeriesTab)
  • Removed legacy CSS files: src/Resources/public/css/back-office.css, backend.css, pricing.css, voucherservice/style.css
  • Removed all Webpack build artifacts under src/Resources/public/build/ecommerceFramework/
  • Removed frontend asset entry points: src/Resources/public/assets/bootstrap.js, flatpickr.js, leaflet.js, voucher.js
  • Removed vendor libraries: bootstrap4, chart.min.js, chart.doughnut.js, flatpickr, fontawesome, leaflet, findologic/export.xsd
  • Removed src/Routing/StudioRouteLoader.php — Studio routing is now handled via service configuration.

Removed Analytics Tracking Trackers

The following deprecated Google Analytics tracking trackers have been removed:

  • Pimcore\Bundle\EcommerceFrameworkBundle\Tracking\Tracker\Analytics\AbstractAnalyticsTracker
  • Pimcore\Bundle\EcommerceFrameworkBundle\Tracking\Tracker\Analytics\Ecommerce
  • Pimcore\Bundle\EcommerceFrameworkBundle\Tracking\Tracker\Analytics\UniversalEcommerce
  • Pimcore\Bundle\EcommerceFrameworkBundle\Tracking\Tracker\Analytics\EnhancedEcommerce

Use Google Tag Manager instead.

Studio Backend API (New)

All legacy admin controller endpoints have been migrated to modern Studio Backend API controllers. New Studio API controllers are available under src/Controller/Studio/:

  • Pricing: Collection, Config, Copy, Create, Delete, Item, Rename, Save, SaveOrder
  • Order: Collection, Item (Cancel, Complaint, Edit)
  • Voucher: Reservation/Cleanup, Token (Cleanup, Export, Generate), View/Tab
  • Back-office order views

New services and interfaces:

  • Pimcore\Bundle\EcommerceFrameworkBundle\Service\Studio\OrderServiceInterface — new interface for order Studio API
  • Pimcore\Bundle\EcommerceFrameworkBundle\Service\Studio\OrderViewService — new service for rendering order views
  • Pimcore\Bundle\EcommerceFrameworkBundle\Service\Studio\PricingServiceInterface — new interface for pricing rule Studio API
  • Pimcore\Bundle\EcommerceFrameworkBundle\Service\Studio\VoucherServiceInterface — new interface for voucher token management
  • Pimcore\Bundle\EcommerceFrameworkBundle\Service\Studio\VoucherViewServiceInterface — new interface for voucher view rendering

New hydrators with interfaces:

  • src/Hydrator/OrderHydratorInterface
  • src/Hydrator/OrderItemHydratorInterface
  • src/Hydrator/PricingHydratorInterface

New Studio pre-response events:

  • Pimcore\Bundle\EcommerceFrameworkBundle\Event\Studio\PreResponse\OrderDetailEvent
  • Pimcore\Bundle\EcommerceFrameworkBundle\Event\Studio\PreResponse\OrderListItemEvent
  • Pimcore\Bundle\EcommerceFrameworkBundle\Event\Studio\PreResponse\PricingConfigEvent
  • Pimcore\Bundle\EcommerceFrameworkBundle\Event\Studio\PreResponse\PricingRuleDetailEvent
  • Pimcore\Bundle\EcommerceFrameworkBundle\Event\Studio\PreResponse\PricingRuleListItemEvent

Studio UI Integration

  • Pricing Rules editor is now fully implemented in the Studio UI (React/TypeScript modules under assets/studio/js/src/modules/pricing-rules/)
  • Voucher Series tab is now available in the Studio UI
  • Index Field Selection field definitions (IndexFieldSelection, IndexFieldSelectionCombo, IndexFieldSelectionField) are now implemented as Studio class editor dynamic types (TypeScript)

Interface and Return Type Changes

CartManager

  • AbstractCart::isValidCartItem() — removed the instanceof CheckoutableInterface guard; the method now only checks for MockProduct exclusion. Any product type is now accepted as a valid cart item.
  • CartPriceCalculator::buildModificator() — removed the unnecessary null check before instantiating the modificator.

OrderManager

  • OrderManager::fillOrderItem() — removed instanceof CheckoutableInterface guard when calling getOSName()/getOSProductNumber(); these calls are now made unconditionally. Ensure your product classes implement ProductInterface properly.
  • OrderManager::applyVoucherTokens() — removed the is_array($voucherTokens) guard; getVoucherTokenCodes() is now expected to always return an array.
  • OrderManager::fillOrderItem() — removed is_object($item->getTotalPrice()) guard; getTotalPrice() must return an object.
  • OrderManager::fillOrderItem() — removed method_exists($orderItem, 'setPricingRules') check; setPricingRules is now expected to exist on the order item.

OfferTool

  • DefaultService::createOfferItem() — removed instanceof CheckoutableInterface guard when calling getOSName()/getOSProductNumber(); products are now assumed to implement ProductInterface directly.

FilterService

  • NumberRangeSelection::prepareData() (both FilterType\NumberRangeSelection and FilterType\Findologic\NumberRangeSelection) — removed method_exists checks for getPreSelectFrom()/getPreSelectTo(); these methods are now expected to always exist on filter definitions.
  • SelectCategory::prepareData() — removed method_exists($filterDefinition, 'getPreSelect') check; getPreSelect() is now assumed to always exist.
  • MultiSelectRelation::prepareData() (and Findologic variant) — removed is_array($objects) guard; $objects is assumed to always be an array at this point.

PricingManager

  • PricingManager\Condition\CatalogCategory::fromJson() — now strictly checks instanceof AbstractCategory before adding loaded objects to the category list (previously only truthiness was checked).
  • PricingManager\Condition\CatalogProduct::fromJson() — now strictly checks instanceof AbstractProduct before adding loaded objects (previously only truthiness was checked).
  • PricingManager\Condition\CatalogProduct::__wakeup() — now resets $this->products = [] instead of unset($this->products).
  • PricingManager\Condition\VoucherToken::check() — removed is_array($voucherTokenCodes) guard; getVoucherTokenCodes() is expected to always return an array.

VoucherService

  • AbstractTokenManager::checkOncePerCart() — removed is_array($cartCodes) guard; getVoucherTokenCodes() must return an array.
  • AbstractTokenManager::checkOnlyToken() — removed method_exists($this->configuration, 'getOnlyTokenPerCart') check; this method is expected to always exist.
  • AbstractTokenManager::export() / exportData() — removed is_array($data) guards; $data is expected to be an array when not null.

IndexService

  • AbstractOpenSearch::load() — removed the instanceof OpenSearch\Client type check; getOpenSearchClient() is now expected to always return a proper client.
  • AbstractElasticSearch::loadIndexVersion() — removed the is_array($result) guard; also changed getAlias() to accept ['name' => [$this->indexName]] (array) instead of a string.
  • DefaultMysql and ProductCentricBatchProcessingWorker — removed instanceof AbstractCategory checks when building category ID maps; categories from getCategories() are assumed to always be AbstractCategory instances.

Tracking

  • AbstractProductData::getCategory() — removed is_array($this->categories) guard; $this->categories is now always expected to be an array.

Other Changes

  • Removed Doctrine DBAL enum type mapping configuration (deprecated)
  • Removed src/Resources/config/studio_backend.yaml top-level file (routing consolidated)
  • Removed src/Resources/config/studio_ui.yaml top-level file
  • Removed view templates: src/Resources/views/includes/paging.html.twig, voucher/parts/statistics.html.twig, voucher/voucher_code_tab_error.html.twig, voucher/voucher_layout.html.twig

v2.1.0

Added the possibility to distinguish relations conditions applied as preconditions.

v2.0.0

Added bool as possible type to $condition parameter of addCondition function in ProductListInterface (and all implementing classes).

v1.2.1

  • Removed the package "rybakit/twig-deferred-extension". If you extend the twig layout from the E-Commerce Framework, please check if custom CSS/JS code added by pimcore_head_script and pimcore_head_link is still working.

v2.0.0

  • AbstractOfferToolProduct now only accepts int as the $id parameter.