Skip to Content
FrontendBlog Slices (Dev)

Blog Slices — Developer Reference

Technical reference for developers working on blog product slices. For content editor instructions on creating blog posts in Prismic, see Creating Blog Content.

Overview

Blog content is managed through Prismic CMS and rendered by the Next.js frontend. Content editors create blog posts in Prismic, add slices (reusable content blocks) to the body, and the frontend hydrates those slices with live product data from the CardNexus API.

ComponentPurpose
PrismicCMS for content creation and management
Slice ZoneThe body area of a blog post where slices are added
Product HydrationServer-side process that collects product IDs from slices and pre-fetches them
Slice ComponentsReact components that render each slice type

Blog Post Structure

Every blog post in Prismic has these fields:

FieldTypeDescription
UIDUIDURL slug (e.g. my-article → /blog/my-article)
TitleRich Text (H1)Post title
DescriptionRich TextSubtitle/summary shown below the title
CategoryDocument LinkLinks to a blog_category document
TagsRepeatable GroupLinks to blog_tag documents
GamesRepeatable GroupLinks to game documents (for filtering)
AuthorDocument LinkLinks to a person document (image, name, bio)
DateDatePublication date
ImageImageHero/featured image
VideoDocument LinkOptional video document
Push CardGroup (non-repeatable)Optional promotional card in the sidebar
SlicesSlice ZoneThe post body content

Push Card

The push card appears in the blog sidebar on desktop. It’s a promotional card with a background image, foreground logo, and a link.

FieldTypeDescription
background_imageImageFull artwork/background image
foreground_imageImageLogo overlay (supports transparency)
linkLinkWhere the card navigates on click

The push card only renders when the background_image is populated.

Available Slices

The blog post Slice Zone supports these slice types:

SlicePurposeRequires Product IDs?
ContentRich text content (paragraphs, headings, lists)No
ImageFull-width imageNo
VideoEmbedded video playerNo
QuoteBlockquote with attributionNo
ProductHighlightSingle product card with details or price chartYes
ProductCarouselHorizontal carousel of product cards with pricingYes
DecklistProduct list with sorting and card previewYes

Product Slices

These slices embed live CardNexus product data into blog posts. They all follow the same pattern:

  1. Content editor adds product IDs in Prismic
  2. The product hydration system collects all product IDs from all slices on the page
  3. Products are fetched in a single batch via product.getProducts
  4. Each slice component reads from the shared product cache

How Product Hydration Works

The hydration code lives in apps/frontend/libs/marketing/prismic/product-hydration.ts. It scans each slice type and extracts product IDs:

  • ProductHighlight: reads slice.primary.product_id
  • ProductCarousel: reads slice.primary.products[].product_id
  • Decklist: reads slice.primary.products[].product_id

The product query atoms live in apps/frontend/libs/marketing/prismic/product-queries.ts.

All product slices share the same product cache. If the same product ID appears in multiple slices on the same page, it’s only fetched once.

Finding Product IDs

Product IDs are MongoDB ObjectIds. You can find them by:

  1. Navigating to a product on the CardNexus explore page
  2. The ID is in the URL: /explore/[game]/[expansion]/[type]/[product-slug]-[PRODUCT_ID]
  3. Or from the staging/production database directly

ProductHighlight Slice

Embeds a single product with full details. Has two variations.

Default Variation

ProductHighlight Default

Shows a product card with image, expansion info, attributes, pricing details, and a “See Product Page” link.

Prismic Fields:

FieldTypeDescription
product_idTextThe product’s MongoDB ObjectId
captionRich TextOptional caption below the product card

Graph Variation

ProductHighlight Graph

Shows a product card with a price history chart. Users can toggle between 1 day, 1 week, and 1 month periods.

Prismic Fields:

Same as default — product_id and caption.

How it works:

  • The graph fetches price history via orpc.price.getProductPrices for both Standard and Foil finishes
  • Period selection uses a Jotai atom (highlightPeriodAtom) to avoid full component re-renders
  • The initial load triggers Suspense; subsequent period changes use unwrap in derived atoms for non-blocking updates
  • Chart data is processed through fillMissingChartDays to create a continuous line even with sparse data

Component Structure:

ComponentFilePurpose
ProductHighlightGraphCardproduct-highlight-graph-card.tsxData fetching wrapper (triggers Suspense)
ProductCardGraphDetailsproduct-card-graph-details.tsxLayout shell with card visual
ProductCardGraphHeaderproduct-card-graph-header.tsxTitle, period selector (ButtonGroup), market price
ProductCardGraphproduct-card-graph.tsxChart rendering with line data

ProductCarousel Slice

ProductCarousel

Displays a horizontal carousel of product cards with market pricing and trend indicators.

Prismic Fields:

FieldTypeDescription
productsRepeatable GroupList of products
products[].product_idTextThe product’s MongoDB ObjectId
products[].background_colourSelectCard background: blue, pink, or yellow

Component Structure:

ComponentFilePurpose
ProductCarousel (index)index.tsxExtracts items from Prismic, wraps in Suspense
ProductCarouselContentproduct-carousel-content.tsxFetches products, resolves IDs to ProductDTOs
ProductCarouselCardproduct-carousel-card.tsxIndividual card with image, name, price

Pricing Logic:

All product cards use the same pricing resolution:

  1. Check if product is a card (not sealed)
  2. Prefer pricesByFinish.Standard
  3. Fall back to the first available finish (e.g. foil-only cards)
  4. Pass pricing through getEffectivePriceForMarketplace for the user’s marketplace

Decklist Slice

Decklist

Displays a list of products with quantities, sorting, and a card image preview panel.

Prismic Fields:

FieldTypeDescription
titleRich Text (H2)Decklist title
productsRepeatable GroupList of products
products[].product_idTextThe product’s MongoDB ObjectId
products[].quantityNumberHow many copies of this card

Features:

  • Sort dropdown — Sort by name, price (low/high), or default Prismic ordering
  • Card preview — Hovering a row shows the card image on desktop (lg+)
  • Product links — Clicking a row navigates to the product’s explore page
  • Share links — Social share buttons (shares the blog post URL)
  • Market price total — Sum of all card prices Ă— quantities

Component Structure:

ComponentFilePurpose
Decklist (index)index.tsxExtracts items, wraps in Suspense with skeleton
DecklistContentdecklist-content.tsxFetches products via shared product cache
DecklistCarddecklist-card.tsxComposes header, product list, preview
DecklistHeaderdecklist-header.tsxTitle, market price, share links
DecklistProductListdecklist-product-list.tsxCard count, sort dropdown, product rows
DecklistProductRowdecklist-product-row.tsxIndividual row with quantity, name, price
DecklistProductPreviewdecklist-product-preview.tsxCard image, details, “See Product Page” button
DecklistSortSelectdecklist-sort.tsxSort dropdown component + sort logic

The Decklist slice does not use the Lists API. Products are defined directly in Prismic via product IDs. The “Add to Collection” button is planned for a future release when proper decklist/list integration is built.


Adding a New Product Slice

If you need to create a new slice that embeds product data, follow this pattern:

Define the Prismic Model

Create model.json in apps/frontend/libs/marketing/slices/[SliceName]/. Include product_id text fields for product references.

Add to Product Hydration

Update product-hydration.ts to extract product IDs from your slice. Add a case to the switch statement matching your slice_type.

Create the Components

Follow the pattern: index (Prismic props → Suspense) → content (data fetching via productsSwrAtom) → card/details (pure rendering).

Register the Slice

Add the slice to apps/frontend/libs/marketing/slices/index.ts and to the blog_post custom type’s slice zone choices in customtypes/blog_post/index.json.

Add i18n Keys

Add translation keys to both en.json and fr.json under the blog namespace.

Update Generated Types

Update apps/frontend/types.generated.ts and prismicio-types.d.ts with the new slice types.


Code Locations

ComponentLocation
Blog layoutapps/frontend/libs/marketing/components/blog/blog-layout.tsx
Blog sidebarapps/frontend/libs/marketing/components/blog/blog-sidebar.tsx
Product hydrationapps/frontend/libs/marketing/prismic/product-hydration.ts
Product query atomsapps/frontend/libs/marketing/prismic/product-queries.ts
Price history atomsapps/frontend/libs/marketing/prismic/product-price-history-queries.ts
All marketing slicesapps/frontend/libs/marketing/slices/
ProductHighlightapps/frontend/libs/marketing/slices/ProductHighlight/
ProductCarouselapps/frontend/libs/marketing/slices/ProductCarousel/
Decklistapps/frontend/libs/marketing/slices/Decklist/
Blog post custom typecustomtypes/blog_post/index.json
Slice registryapps/frontend/libs/marketing/slices/index.ts
i18n (English)apps/frontend/libs/shared/i18n/locales/en.json
i18n (French)apps/frontend/libs/shared/i18n/locales/fr.json
Last updated on