Skip to main content

Technical Implementation

Overviewโ€‹

This is a Product Listing Page (PLP) component responsible for rendering collection pages with advanced filtering, sorting, and pagination capabilities.

Key Featuresโ€‹

  • Dynamic product listing with load more functionality
  • Advanced filtering options
  • Sorting capabilities
  • Configurable marketing content
    • Visual navigation
    • Sub-navigation
    • Editorial content
    • Recommendation Trays ("Rec" Trays)
  • Rollup product display (grouping similar products)
  • Analytics tracking
  • Responsive design

Dataโ€‹

What data points are we leveraging to generate a collection, or product listing page.

  • Searchspring
  • Shopify Storefront API
    • Deferred product card data (price, product tags)
  • Builder CMS
    • Site Settings
      • Color Family
        • Content Model: Color Swatches

Data Loading Processโ€‹

  1. Retrieves critical collection data from Shopify Storefront API: e.g. configurable content, PLP type (rollup versus exploded)
  2. Fetches initial search results from Searchspring.
  3. Loads additional components like visual navigation and recommendation tray.
  4. Manages pagination and session tracking.

How It Worksโ€‹

  1. When a customer lands on a PLP, we make session storage, Storefront collection, and Searchspring results queries.
  2. After querying, we check the promised Storefront collection data if the PLP is a rollup or exploded type.
  3. If the PLP is a rollup, the app checks for a cached RollupMap for that collection page; if none is found, we generate the map and store it in our cache-fetchem microservice.
  4. After the map is generated, we loop through the sanitized Searchspring results (see sanitizeSearchResults helper function) and populate the rollupListings map, which will determine what product cards to display for that page.
  5. After accounting for all rolled up product cards (aka multivariant), we append productDataPromise and colorBubblePromise data to the first 7 (or what number our DESKTOP_BUBBLE_MAX is set to) variants to later be fulfilled.
  6. We set the new session cookie with the transformed data, cached rollup map, and window scroll position and return the server-side rendered data to our component.
  7. If a customer lands on an "exploded" PLP, we skip steps 3 + 4, and append productDataPromise but no colorBubblePromise. With this in mind, exploded PLPs will have a faster page load, though rollup PLPs will include lots of caching to offset slow page loads when a customer has visited a previously seen collection before.
  8. When the loader data reaches the component, we pass the props into our reusable components to lazy-load/fulfill their promise โ€” e.g. passing the productDataPromise and colorBubblePromise to PlpProductCard to resolve.
  9. When a customer clicks on the "Load more products" button or applies sorting/filters, this triggers an internal navigation that updates the current page. This navigation state will run through the loader functionality from steps 1-7 again. This way we're utilizing cached data, and updating our session cookies for easy user browsing.

Loader functionsโ€‹

PLP 2.0 Critical Data:

  • Shopify Storefront collection data
  • Searchspring Search API data

If there is no critical data, we navigate to a 404 page.

How we're grabbing critical data:

getCollectionSessionโ€‹

A server-side async function that retrieves the session storage cookie that holds onto the user's last PLP scroll position, current page...etc.

queryStorefrontCollectionโ€‹

A server-side async function that queries the Shopify Storefront API to return collection data: e.g. metafields, collection description/title.

queryForSearchspringCollectionโ€‹

A server-side async function that uses our custom API route (/api/collection-page/[COLLECTION_HANDLE]) to query Searchspring's Search API. This query is then cached and referred to when transforming the data for our use cases.

const isRollup = storefrontCollection?.collection?.enable_rollup?.value === 'true'; // Check if the collection is a 'rollup'

const searchspringCollection = await queryForSearchspringCollection(
request,
context.withCache,
handle,
'1',
isRollup // If `true` we want to append `resultsPerPage=72` (or double the MAX_RESULTS)
);

Helper Functionsโ€‹

fetchInBatchesโ€‹

An async function that helps us parallelize the Searchspring results for "rollup" PLPs.

The purpose of this function is when a user lands on a rollup PLP, we fetch every page in the Searchspring API to create a map of every result keyed by style-fabric-type. This rollup map is then used to generate multivariant product cards, by pushing the variant data into the sanitized search result object.

After fetching all the results from Searchspring, logging failed pages and resolving the data promise, we return a "sanitized" array of results.

const resultsInBatch = await Promise.allSettled(
batch.map(async (page) => {
const res = await axios.get<SearchAPIResponse>(getSearchspringUrl(handle, page.toString()));
return sanitizeSearchResults(res.data.results);
})
);

buildProductCardFamilyMapโ€‹

This function builds the master style-fabric-type map, or type RollupMap, that is predicated on Searchspring results.

sanitizeSearchResultsโ€‹

This helper function is used in both fetchInBatches and fetchAllProductsInCollection to filter out unused data from Searchspring. After filtering out attributes we return all required datapoints to continue building out product card data:

Example sanitized Searchspring result:

{
handle: "kira-chiffon-dress-with-slit-olive",
name: "Kira Dress With Slit",
style: "Kira",
fabric: "Chiffon",
color: "Olive",
type: "Dress",
contentImageThumbId: "gid://shopify/MediaImage/27052003131583",
contentImageThumbUrl: "https://birdygrey.com/primaryImage.jpg",
contentImageHex: "#616652",
gid: "gid://shopify/Product/7490294939839",
imageUrl: "https://birdygrey.com/image.jpg"
}

Utility Functionsโ€‹

Coming soon.

Troubleshootingโ€‹

  • Check network tab for API call issues
  • Verify feature flags are correctly configured
  • Ensure Searchspring and Shopify API connections are stable