FlexPlat logoFlx Modernize

15. Storefront: sections in TypeScript

You will: let a JavaScript developer replace parts of a store page, one section at a time.

Result: the modern-cards theme: a new product card and product page in TypeScript, on the live demo, with WooCommerce's cart, variations and gallery still working. To write one yourself, see Writing a Storefront theme.

WooCommerce's output is the default

Up to here, a developer can change the header, footer and CSS, but not what a product looks like. The design keeps WooCommerce's output as each section's default, and lets a theme replace it:

  1. Boundaries. During the build, the plugin hooks both ends of the section and prints comment markers around it. The hooks are removed afterwards, so a native page never has markers.
  2. Data. Structured data for the section goes in the payload.
  3. No theme. The renderer removes the markers, and the page is byte-identical to before, so fidelity keeps measuring that path.
  4. With a theme. A function gets the data and returns HTML, which replaces what is between the markers.
function productCard(card: ProductCard): string {
  return `<div class="my-card">
${productImage(card)}
<h2>${escWpText(card.name)}</h2>
<div>${card.price_html}</div>
${addToCartLink(card)}
</div>`;
}

Keep what WooCommerce's scripts need

A card's button needs WooCommerce's classes and data attributes, or AJAX add to cart stops working. Rather than copy WooCommerce's logic, the plugin reads the arguments WooCommerce itself used to build the button, from its woocommerce_loop_add_to_cart_link filter. So plugins that change those arguments carry over, and addToCartLink() prints them.

The product page goes further. The gallery and purchase form are tied to scripts that depend on their exact markup, so the theme doesn't replace them. It gets them as HTML, and writes everything around them:

function productPage({ product, galleryHtml, purchaseHtml, afterHtml }: ProductPageParts): string {
  return `<div class="my-layout">
<div>${galleryHtml}</div>
<div class="summary entry-summary">
<h1 class="product_title">${escWpText(product.name)}</h1>
${purchaseHtml}
<div class="product_meta"><span class="sku">${escWpText(product.sku ?? '')}</span></div>
</div>
</div>
${afterHtml}`;
}

To find what those scripts look for, read them. add-to-cart-variation.js updates .product_meta .sku, and Storefront's sticky add to cart watches .entry-summary. A variation's image swap and the lightbox work from inside galleryHtml.

Fail closed

  • A card with unusable data keeps WooCommerce's markup.
  • A function that throws gives success: false, and the page is native, never half-themed.
  • Markers out of order with a theme on throw too. If a plugin removes a hook, one card could otherwise swallow its neighbour. With no theme, markers are simply removed.

Prove it

Run the browser checks with the theme on: every card replaced, add to cart, "View cart", a variation's price, image and SKU, tabs, reviews, the lightbox, and a form add to cart.

Also repeat the cart-holder byte comparison with the theme on. With no theme, card data never reaches the page, so the earlier check says nothing about it.

What a theme drops

A replaced card or summary drops what other plugins print there: wishlist buttons, badges, brand or sharing output. That is the developer's choice when taking over a section, so check the store's plugins first.

Next: 16. Cart, Checkout, My account.

Published from rickey29/twenty-twenty-five at commit 837705d · Flx Modernize 1.11.0 · Flx Render 1.11.0