Skip to main content
Transforms are functions that intercept product, variant, and option data right before it is rendered. Each function receives the relevant entity and returns the transformed value. Pass them under transforms in your SwishOptions.
Keys are prefixed with the entity they operate on (for example productTitle vs variantTitle) so the context is always unambiguous. Each transform falls back to the default behavior listed below when omitted.
Transforms run for every render, so keep them pure and inexpensive. If you need product metadata that is not already on product, declare it under metafields so it is preloaded rather than fetching it here. recommendations is the one exception - it runs once per product view and may return a promise, so it can await a request.

Product title

Replace the displayed product title without mutating the underlying Shopify data.

Product subtitle

Add a line under the product title on product cards, in the drawer and on the Wishlist page. The transform receives the resolved product and the card’s variant (when there is one). Return the text to show, or undefined for no line. The line sits between the title and the price in the subdued text colour, and truncates to a single line. Show the colour of a product from a combined listing once hideOption has taken Color out of the option select. A product of a combined listing carries its colour on its variants rather than in its own options, so read the variant first:
Show a value from a product metafield, declared under metafields so it is preloaded with the product:
The subtitle shows on product cards only. The product detail view, dialogs such as quick buy and Notify Me, and toasts show the title alone.

Product description

Replace the description HTML rendered on the product detail view. Return any HTML string - it is rendered inside the description block.

Product badges

Decorate product cards and the product detail view with badges. The transform receives defaultBadges, the badge Swish would render by default, and returns the badges to display. defaultBadges holds at most one badge: the first match in the badge priority list set under Global → Preferences → Product badges. The built-in Sale and Sold out badges arrive as strings unless the merchant gave them colours. A Badge can be a plain string or an object:
Return an empty array to hide all badges, or omit specific defaults to suppress them.

Product price

Replace or hide the price on product cards and the product detail view based on product attributes. The callback receives the resolved product and (when applicable) variant, and returns one of:
  • undefined to render the default price.
  • false to hide the price entirely.
  • A string to replace the price with custom text (for example, "Call for price").
The transform runs for every price display except notifications and order line items.
Replacement text inherits the default price typography and is wrapped in a container with the modifier classes .product-price-custom and .price-custom for additional styling.

Product image

Choose the image a product card shows. The transform receives the resolved product, the card’s variant (when there is one), and defaultImage - the image the card shows without the transform: the variant’s image, else the product’s featured image. Return an image object with at least a url, or undefined to keep defaultImage. Show the second image uploaded to the product. A product with only one image keeps its default:
Pick an image by its alt text, for example a flat lay. product.images holds the product’s first 20 images:
Show an image URL stored in a product metafield:
Store the URL in a URL or Single line text metafield. A File metafield reaches the transform as a gid://shopify/MediaImage/... ID rather than a URL, so it can’t be shown. Images on cdn.shopify.com are resized for the card; images on other hosts load at full size.
The transform applies to product cards in the drawer, on the Wishlist page, and in the product rows of the Home and product detail views. The product detail image slider and the images in dialogs such as quick buy and Notify Me keep the default.

Let customers switch images

Turn on Show image toggle for the grid in Views → Saves or Views → List detail to put a switch above the grid, as on a collection page that switches between model shots and flat lays. In code, it’s showImageToggle on the all-items-grid and list-items-grid sections.
  • Cards open on their default image. Turning the switch on shows the image productImage picks on every card, on both grids.
  • The choice lasts until the customer’s browser session ends.
  • The switch appears only when productImage is set. A grid without the switch always shows the transform’s pick.
The switch reads Alternate view. Rename it with the productCard.imageToggle translation key, for example to “Flat lay”.

Add to cart button

Show or hide Swish’s cart buttons per product: Add to cart on the product detail view, the buy button beneath product cards, and the quick-buy button on card images. This transform defaults to true, so cart buttons render wherever their section option allows. Reach for it when a product shouldn’t be bought from Swish at all - made-to-order items, pre-orders, B2B-only SKUs. Turn them off everywhere:
Or per product:
The section options that control these buttons gate them independently - a button renders only when both its section option and this transform allow it. showBuyButton covers the solid button on the card grids; showQuickBuyButton covers the floating one on all-items-grid, on both List Detail grids, and on the product detail complementary-products / related-products carousels. The two levels point opposite ways on purpose. This transform defaults to true, so a cart button is always available store-wide; every section option above defaults to false, so you choose the surfaces that actually show one.
One surface has no section option: featured collection rows on the Home view always render quick-buy, so there a button appears as soon as this transform allows it. To suppress it, return false from this transform for those products, or turn off the store-wide ui.productCard.showQuickBuyButton switch.
This transform is per product, not per view, so it can’t keep Add to cart on the product detail view while removing quick-buy from cards - returning false hides both. To do that, leave this transform alone and set ui.productCard.showQuickBuyButton to false, which hides quick-buy on every card and leaves the product detail button alone. Control whether product cards link to the PDP globally, or per product. Return true to make the card navigate to the product page; return false to keep the default in-drawer intent behavior. The transform decides only when ui.productCard.linkToProductPage is unset. The customiser always sends that setting from its Link card to product page switch (Global → Preferences → Product cards), so on a store set up in the customiser, the switch decides and this transform does not.
The standalone list detail page (ui.listDetailPage) always links its cards to the PDP, whatever this transform returns, since it has no in-drawer fallback.

Variant title

Customize how a variant’s title is rendered (for example, in the variant selector or saved item card).

Option values

Filter or reorder the option values shown in the variant selector. The transform receives the option (e.g. Size) and its full list of values, and returns the values to display.
Return a subset of values to hide options entirely.

Combined listing parent

Tell Swish that a product is part of a Shopify combined listing so the variant selector renders the correct set of options and switches between the underlying products as the customer makes their selection. Shopify does not expose any way to detect a combined listing from the Storefront API, so the merchant signals this via the transform. Returns one of:
  • false (default) - not part of a combined listing.
  • true - part of a combined listing, but no parent product reference is available.
  • A parent product GID (e.g. "gid://shopify/Product/7345123456")
The recommended pattern is to reference the parent product on each child product in a metafield, and return it from the transform:

Hide option

Hide a product option from the variant selector. Useful for combined listings where one option drives the underlying product (for example, “Color”). Hiding it prevents the customer from accidentally switching products mid-flow - especially when saving from a collection card, where switching products can cause an adjacent card’s heart to toggle instead of the one the customer clicked. The option is hidden only when a value can be auto-selected for it (from the product’s selectedOrFirstAvailableVariant). If no value is available, the option is shown as usual and a warning is logged.
The hidden option’s value still constrains the rest, so the visible options correctly reflect availability against the locked value.

Recommendations

Filter or reorder the products shown in the complementary-products and related-products sections of the product detail view. The transform receives the current product and the recommendations Shopify returned, and returns the list to render. This is the only transform that may return a promise, so you can call your own recommendation service:
Both defaultRecommendations and the values you return carry only id - the recommendations query fetches nothing else, and each card re-fetches its own product data. Return an empty array to render no recommendations.
Filtering by product attributes isn’t possible here - defaultRecommendations entries carry only id, so there are no tags or types to test. Cap, reorder, or replace the list with ids of your own instead.
If the transform throws or its promise rejects, Swish logs the error and falls back to the unfiltered Shopify recommendations rather than leaving the section in a loading state.

Combined listings end-to-end

Combined listings most often pair both transforms: signal the parent with combinedListingParent, then hide the option that drives the product switch with hideOption. The customer picks from the remaining options against the locked value, and never accidentally jumps to a sibling product.

Further reading