Skip to main content

Breadcrumbs

Breadcrumbs on PLP and PDP pages are driven by a single Shopify metaobject type: Breadcrumb Categories (breadcrumb_categories). This metaobject defines the full category hierarchy and serves as the single source of truth for both page types.

Please note this metaobject is live on both production and staging, so we can test out future changes on the staging store before making it live on production.

Metaobject Structureโ€‹

Each entry in the breadcrumb_categories metaobject has:

FieldTypeRequiredDescription
titlesingle_line_text_fieldYesDisplay label in the breadcrumb (e.g., "Shoes"). This can also be customized for marketing purposes: "20% off Shoes"
urlsingle_line_text_fieldYesCollection handle used to build the breadcrumb URL (e.g., bridesmaid-shoes-heels โ†’ /collections/bridesmaid-shoes-heels)
subcollectionlist.metaobject_referenceNoReferences to child category entries. Defines the parent โ†’ child hierarchy.
product_typeslist.single_line_text_fieldNoProduct type strings used by PDP to resolve a product to this category. See PDP Product Type Mapping.

Hierarchyโ€‹

The category hierarchy is defined through the subcollection field. Parent entries list their children as metaobject references. At runtime, this relationship is inverted โ€” each child stores a reference back to its parent โ€” so the breadcrumb builder can walk up the chain.

Exampleโ€‹

Pajamas & Robes (url: bridesmaid-getting-ready-outfits)
โ”œโ”€โ”€ Robes (url: bridesmaid-robes)
โ”œโ”€โ”€ Pajamas (url: bridesmaid-pajamas)
โ””โ”€โ”€ Slippers (url: bridesmaid-slippers)

Jewelry & Accessories (url: bridesmaid-bridal-accessories)
โ”œโ”€โ”€ Shoes (url: bridesmaid-shoes-heels)
โ”œโ”€โ”€ Shawls (url: shawls-cover-ups)
โ”œโ”€โ”€ Intimates (url: intimates)
โ”œโ”€โ”€ Scarves (url: bridesmaid-dress-scarves)
โ””โ”€โ”€ Dog Bow Ties (url: pet-accessories)

A product or collection under "Robes" produces the breadcrumb:

Birdy Grey > Pajamas & Robes > Robes > [Page Title]

How PLP Uses Itโ€‹

Each Shopify collection (PLP) has a breadcrumb_category metafield (namespace: config, key: breadcrumb_category, type: metaobject_reference) that directly references its category entry in the metaobject.

Data flowโ€‹

  1. The collection query resolves the breadcrumb_category reference inline (returns the metaobject's id and fields)
  2. The PLP loader calls loadPlpBreadcrumbs(), which fetches all breadcrumb_categories metaobjects and builds a CollectionBreadcrumbMap (Record<metaobjectId, { title, url, parentId? }>)
  3. createPlpBreadcrumbs() looks up the collection's referenced metaobject ID in the map and uses buildCategoryChain() to walk up the parentId chain to build the full breadcrumb path
  4. If the collection's handle matches the category's url, the collection is treated as the category page itself (no duplicate crumb appended)
  5. If no breadcrumb_category is set on the collection, a simple fallback breadcrumb is returned: [collection title]

Setting up a collectionโ€‹

To add breadcrumbs to a collection:

  1. Ensure the category entry exists in the breadcrumb_categories metaobject (create it if needed)
  2. If it's a subcategory, add it to the parent entry's subcollection field
  3. On the collection in Shopify Admin, set the breadcrumb_category metafield to reference the correct metaobject entry

How PDP Uses Itโ€‹

Products don't have a breadcrumb_category metafield. Instead, the PDP resolves a product to its category using the product_types field on each metaobject entry.

PDP Product Type Mappingโ€‹

The product_types field contains a list of strings that match either:

  • product.productType โ€” the Shopify product type (e.g., "Bridesmaid Dress", "Swatch", "Shoes")
  • product.type.value โ€” the attr.type metafield value (e.g., "Dress", "Robe", "Pajamas")

At runtime, a reverse lookup map is built: product type string โ†’ metaobject ID. When rendering a PDP, the system tries productType first, then falls back to type.value.

Why product_types existsโ€‹

Shopify product types and metafield values don't always match the metaobject entry titles. For example:

Product fieldValueMetaobject title
productType"Seamless Underwear"Intimates
productType"Little White Dress"Little White Dresses
type.value"Pajama Set"Pajamas
type.value"Robe"Robes

The product_types field bridges this gap by listing all the product type strings that should resolve to a given category. Multiple strings can map to the same entry (e.g., both "Pajamas" and "Pajama Set" resolve to the Pajamas category).

When to add product_typesโ€‹

Only entries that PDP products should resolve to need product_types. Parent-only entries that serve as hierarchy containers (like "Pajamas & Robes" or "Ties & Accessories") don't need it since no product has those as their type.

Data flowโ€‹

  1. The PDP loader fetches all breadcrumb_categories metaobjects (same cached query as PLP)
  2. Two maps are built: CollectionBreadcrumbMap (same as PLP) and ProductTypeBreadcrumbMap (Record<product type string, metaobject ID>)
  3. createPdpBreadcrumbs() looks up the product's type in the product type map, finds the metaobject ID, then uses buildCategoryChain() to walk up the parent chain
  4. If no match is found, a simple fallback breadcrumb is returned: [product title]

SEO Schemaโ€‹

Both PLP and PDP emit a BreadcrumbList JSON-LD schema via getBreadcrumbSchema(). The schema prepends a "Birdy Grey" home link (https://www.birdygrey.com/) and outputs full absolute URLs for each breadcrumb item.

Cachingโ€‹

The metaobject query uses CacheStrategy.slower (15-minute max age, 4-hour stale-while-revalidate). This data rarely changes โ€” only when categories are added, renamed, or reorganized.

Key Filesโ€‹

FilePurpose
app/lib/plp/breadcrumbs.server.tsparseBreadcrumbMetaobjects(), parseProductTypeLookup(), buildCategoryChain(), createPlpBreadcrumbs(), loadPlpBreadcrumbs()
app/lib/pdp/helper.server.tscreatePdpBreadcrumbs()
app/lib/plp/router/next.server.tsPLP loader โ€” calls loadPlpBreadcrumbs()
app/routes/products.$handle.tsxPDP loader โ€” fetches metaobjects, builds breadcrumbs
app/lib/seo/helper.tsgetBreadcrumbSchema() โ€” JSON-LD structured data
app/graphql/storefront/MetaobjectQuery.tsMETAOBJECT_TYPE_QUERY โ€” GraphQL query for metaobjects
app/graphql/storefront/CollectionQuery.tsCollection query with breadcrumb_category metaobject reference
app/components/BreadCrumbs/breadCrumbs.component.tsxUI breadcrumb component