Product page integration
On a designable product page the frontend orchestrates the full customization flow: it loads the FPD product configuration, mounts the designer, wires up the external modules, and intercepts the add-to-cart.
Lifecycle
- Bootstrap — the bundle (injected by the app embed) verifies
window.FPD/window.Shopify, loads shop options and language, and reads the Shopify product from#ProductJson-FPD. - Product load — the FPD product configuration (views, elements, modules, prices) is fetched from the FPD backend. If the URL carries
?_fpd-hash=…, the saved design is loaded in parallel. - Designer creation — the designer mounts into the container (
#fpdby default). Depending on the designer mode it renders inline, or stays hidden behind a "customize" button/modal. - Operators attach — add-to-cart interception, price display, save button, view selection, 3D preview, bulk order, and the external modules connect to the designer instance.
- Ready —
<body>gets the classfpd-enabled; theproductPageDonecallback fires;FPD.instanceis available.
External modules
The external modules render designer functionality outside the canvas — as cards directly in your product page layout. They live in shadow DOM, configure themselves via a JSON data-config attribute (usually filled by theme editor block settings), and connect to the designer automatically once it exists.
| Element | Purpose | Key config |
|---|---|---|
fpd-images-module | Image upload (drag & drop, gallery of previous uploads, optional QR-code tab) | showUploadTab, showGallery, showDropZone, enableQrCodeTab, targetMode (upload-zone / replace / add), uploadZoneName, replaceValue, displayMode, imageSize, imagesPerRow |
fpd-texts-module | Add text and edit all existing text layers (font, size, style, color) | showTextLayers, showAddText, showFontSize, showFontFamily, showFontStyles, showFontColor, showTextTemplates, textTemplates, editMode |
fpd-layouts-module | Switch the view between predefined layouts | displayMode, imagesPerRow, showClearOption, collapsible, autoApplyFirst, showPrices, swapLayoutConfirmation, layoutIds |
fpd-products-module | Choose between multiple FPD products (designs) | displayMode, imageSize, imagesPerRow |
fpd-designs-module | Browse and add pre-made designs/cliparts | displayAs (inline / popup), categoryLayout, categories, imagesPerRow, buttonText |
fpd-add-elements-module | Card grid combining "add text", "text templates", and "designs" | showAddText, showTextTemplates, showDesigns, hiddenCards, labels, defaultText, designs* passthrough |
fpd-info-popover | Info icon with a popover next to a module heading | text, moduleType, language |
fpd-share-button | Save & share the current design | buttonLabel |
Shared config for every module: language (auto / en / de), customCss, and additionalConfig — a free-form JSON object whose keys override the block settings (bind it to a product metafield for per-product behavior, see Configuration).
In the Shopify theme editor the modules render a static design-mode preview and re-read their config on shopify:section:load — safe to configure live.
Add-to-cart flow
When the customer clicks add-to-cart on a customized product:
- The original submit is intercepted (the button is replaced by a cloned one under FPD's control).
- The optional
beforeAddToCartcallback runs — throwing aborts the add (custom validation). - Elements outside the printing area trigger a warning modal.
- The design is uploaded to the FPD backend (line item cache), producing the
_fpd-hashand preview URL. - The line item properties are built (see Cart page) and the item is added according to the configured strategy:
- Form strategy — properties are written as hidden
properties[…]inputs and your theme's form submits normally. - JSON strategy — the frontend POSTs
/cart/add.jsitself (including Section Rendering data for cart drawers). - Event strategy — the frontend emits
fpd:atcPreparedwith the finished properties and leaves the cart add to your code.
- Form strategy — properties are written as hidden
- Afterwards, the configured after-behavior runs: redirect to cart, page refresh,
fpd:addToCartevent, or opening the cart drawer.
Strategies and after-behaviors are shop options — see Configuration.
Uncustomized products
With shopify_add_lic_only_when_customized enabled, a product that was not customized is added as a plain Shopify product without any design data.
Variant changes
The frontend watches URL changes (including history.pushState by your theme) for a new ?variant=:
- Same product, new variant → prices refresh; if the theme morphs the product section's DOM, the designer re-initializes in place.
- The displayed price = variant base price + designer extra (
FPD.instance.calculatePrice()+ optionalFPD.additionalPrice), rendered into the element matching the price selector (.fpd-shopify-priceby default) or an auto-created.fpd-total-extrablock.
For products with more than 250 variants the frontend falls back to the Storefront GraphQL API to resolve the current variant.
Editing an existing design
When the page is opened through a cart edit link (?_fpd-hash=…&li-key=…, see Cart page):
- The saved design is fetched and loaded into the designer.
- The designer auto-opens (option
shopify_open_designer_when_edit, default on). - Add-to-cart switches to update mode: the old cart line (
li-key) is removed and the edited design is added in its place. - The main product image is replaced with a snapshot of the loaded design.
Save button
Independent of add-to-cart, a dedicated save button can be enabled (shopify_use_save_button, or ?sbs= for testing). It stores the current design (line item cache) without adding to the cart — used for save-for-later / wishlist flows. By default it replaces the ATC button; with shopify_save_button_replace_atc disabled it appears alongside (anchor: #fpd-save).
Bulk orders
If your product template contains <div id="fpd-bulk-order-container">, the normal ATC button and quantity selector are hidden and a variant/quantity table renders instead. All selected combinations are added in one cart call, sharing a single stored design. Dispatch fpd:preview on document to refresh its preview image after external changes.