Skip to content

Add ESI support for data-ps-fragment dynamic content - #107

Open
Codencode wants to merge 1 commit into
litespeedtech:masterfrom
Codencode:feature/data-ps-fragment-esi
Open

Codencode wants to merge 1 commit into
litespeedtech:masterfrom
Codencode:feature/data-ps-fragment-esi

Conversation

@Codencode

@Codencode Codencode commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

What does this PR do?

This PR adds support for dynamic ESI fragments identified through semantic data-ps-fragment attributes in the final HTML output.

This implementation depends on the Hummingbird change proposed in PrestaShop/hummingbird#1101. Without that change, Hummingbird does not expose the required fragment markers and these blocks cannot be handled through this mechanism.

It currently supports:

  • notifications
  • product-add-to-cart

These blocks are isolated from the full-page cache and regenerated through ESI using the current request/cart context.

This avoids stale cart-dependent content on cached pages, including:

  • the "Your cart contains..." notification;
  • an outdated product-add-to-cart block;
  • an incorrect enabled/disabled Add to cart button state;
  • stale cart quantity/minimum quantity information.

Why?

This is an alternative to the approach proposed in:

Those PRs required dedicated:

  • displayDynamicFragmentBefore
  • displayDynamicFragmentAfter

hooks in the theme templates.

Instead, Hummingbird exposes semantic markers directly on the existing dynamic block containers:

<div id="notifications" data-ps-fragment="notifications">

and:

<div
  class="product__add-to-cart-container product-add-to-cart js-product-add-to-cart"
  data-ps-fragment="product-add-to-cart"
>

LiteSpeed Cache detects these elements from the final HTML output, identifies their complete boundaries and replaces them with ESI includes.

No additional wrapper elements, dedicated cache hooks or LiteSpeed-specific logic are required in the theme.

The related Hummingbird implementation is:

PrestaShop/hummingbird#1101

If this PR and the related Hummingbird PR are merged, #103 can be closed because the previous before/after hook approach is no longer required.

Notifications

The existing hasNotification() safety behavior is preserved as a fallback.

The no-cache decision is postponed until the final HTML is available:

  • if data-ps-fragment="notifications" is successfully converted to ESI, the page itself may remain cacheable;
  • if the theme does not expose the fragment, ESI is unavailable, or replacement fails, the existing Has private notification behavior is preserved.

Notifications already generated during the initial cache MISS are preserved through ESI inline content.

The ESI request also uses the standard PrestaShop notification preparation mechanism when available and regenerates the product/cart notification from the current cart context.

Since Hummingbird now exposes the marker directly on the existing #notifications container, the ESI endpoint can render _partials/notifications.tpl directly without introducing additional wrapper markup.

Product add to cart

The complete product-add-to-cart block is regenerated through ESI rather than caching only the button state.

This allows the fragment to reflect the current context, including:

  • current cart quantity;
  • product combination;
  • minimum and required quantities;
  • customizations;
  • availability;
  • Add to cart enabled/disabled state;
  • modules rendered through displayProductActions.

The original fragment is replaced as a whole, which also prevents nested ESI markers generated inside product-add-to-cart from being stored in the full-page cache.

Product presentation

The ESI endpoint rebuilds the subset of product data required by the product-add-to-cart fragment.

The ESI request cannot safely reuse ProductController::getTemplateVarProduct(), and PrestaShop currently exposes no public reusable core API that gives a module exactly the same presented product prepared by the product page.

The implementation therefore uses the existing PrestaShop product presentation components and reconstructs the product-page-specific data required by this fragment.

This code is explicitly documented as a maintenance point and should be reviewed if the PrestaShop product presentation flow changes in future versions, especially around:

  • combinations / id_product_attribute;
  • minimum and requested quantities;
  • cart quantity;
  • customizations;
  • add_to_cart_url;
  • the product passed to displayProductActions.

If PrestaShop exposes a reusable public API for the product-page presentation in the future, it should be preferred over this manual reconstruction.

Fragment parsing

Dynamic fragments are detected directly from the final HTML without re-serializing the whole document through DOMDocument, preserving the original response markup.

The parser handles nested elements and text-content elements such as:

  • script
  • style
  • textarea
  • title

so tag-like text inside their content cannot incorrectly terminate a dynamic fragment.

For example, a literal </div> inside a textarea is treated as text and cannot truncate the surrounding product-add-to-cart fragment.

Safety / fallback

A block explicitly marked with data-ps-fragment is considered dynamic.

If a supported fragment cannot be safely converted to ESI, the response is marked as non-cacheable instead of storing the original dynamic HTML in the public full-page cache.

The same fallback is applied for invalid/ambiguous fragment markup or when ESI injection is unavailable.

Themes without these markers keep the existing behavior.

Manual testing

The implementation has been manually tested on a real PrestaShop installation using LiteSpeed full-page cache, including both cache MISS and HIT responses.

The tested scenarios include:

  • normal MISS → HIT product page caching;
  • empty notifications;
  • cart-dependent notifications;
  • Add to cart enabled/disabled state;
  • minimum and maximum available quantities;
  • product combinations, including unavailable combinations;
  • required product customizations;
  • multiple customization/cart scenarios;
  • output from displayProductActions;
  • textarea content containing a literal </div> inside the dynamic fragment;
  • Guest Mode disabled;
  • Guest Mode First Page Only;
  • Guest Mode enabled;
  • guest and authenticated customers;
  • independent browser sessions with different carts;
  • final HTML without duplicated wrappers, truncated markup or visible ESI tags.

In these tests, the main product page remained cacheable while the dynamic fragments correctly reflected the current cart/session context.

@Codencode
Codencode marked this pull request as draft September 8, 2026 14:18
@Codencode
Codencode force-pushed the feature/data-ps-fragment-esi branch from 9bebabb to 180aa55 Compare September 9, 2026 07:17
@Codencode
Codencode marked this pull request as ready for review September 9, 2026 07:39
@Codencode
Codencode force-pushed the feature/data-ps-fragment-esi branch from 180aa55 to 191be66 Compare September 14, 2026 10:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant