Vue Storefront is now Alokai! Learn More
Resolving CMS pages

Resolving CMS pages

In many cases, a Storefront page directly corresponds to a CMS page. For instance, the Login page in the Storefront maps to a single CMS page entry. However, for pages like Product Listing or Product Details, where multiple instances exist, the mapping becomes more complex.

While some CMS platforms handle these mappings automatically, others do not. API Clients of our CMS integrations provide the tools to address these gaps, ensuring granular page-to-content mapping in more complex scenarios such as:

  • mapping a group of Storefront pages to a common CMS page,
  • mapping a group of Storefront pages to a common CMS page with specific exceptions, where some pages in that group are mapped to their own dedicated CMS pages,
  • defining a fallback CMS page for all CMS-only and CMS-enhanced Storefront pages that do not have a corresponding CMS page.

The mechanism differs in each of our CMS integrations. Specific platform variations will be highlighted by the following guides.

In our Amplience integration, you can define two callbacks responsible for matching Storefront paths with CMS content entries:

  • resolvePages()
  • resolveFallbackPage()

They can be defined in the unified configuration of the integration's API Client. Both can be asynchronous, which is useful if you want to maintain the mappings in the CMS, allowing content editors to manage them.

Page fetching flow

When the integration's getPage() method is called, it tries to fetch a page entry from Amplience in the following steps:

1

Fetching the exact page

First, the getPage() method always tries to fetch a page exactly matching the Storefront path. For example, when users visit the /about Storefront path, getPage() searches for a page entry with the exact same Path field value.

2

Fetching the resolved page

When the exact match strategy fails, getPage() will attempt to fetch a page based on the object returned by resolvePages(). The callback receives the integration's API Client context and request params as arguments. It has to return a map between Storefront page paths (or patterns) and objects containing the necessary data to fetch the appropriate CMS page entry.

apps/storefront-middleware/sf-modules/cms-amplience/config.ts
export const config = {
  configuration: {
    unified: {
      resolvePages: (context, params) => ({
        "category/shoes": {
          path: "category",
        },
      })
    },
  },
};

Based on the path received as one of the arguments, getPage() selects a single key from the map and uses its associated value (object) to request a page.

3

Fetching the fallback page

If the page resolution strategy fails, getPage() attempts to fetch a page based on the object returned by resolveFallbackPage(). The callback receives the same arguments as resolvePages() but has to return a single object containing the necessary data to fetch the fallback CMS page entry. Obviously, the fallback page entry has to exist in the CMS. If it does not, the getPage() request fails.

apps/storefront-middleware/sf-modules/cms-amplience/config.ts
export const config = {
  configuration: {
    unified: {
      resolveFallbackPage: (context, params) => ({
        path: "fallback-page"
      }),
    }
  }
}

One-to-One path mapping

Suppose you've a CMS entry for a Product Listing page and set its Path to category. Now you want it to be fetched whenever users visit the category/shoes path in the Storefront. For this you need to define a one-to-one relationship:

apps/storefront-middleware/sf-modules/cms-amplience/config.ts
export const config = {
  configuration: {
    unified: {
      resolvePages: (context, params) => ({
        "category/shoes": {
          path: "category",
        },
      })
    },
  },
};

It is a valid example, but also a redundant one. You could simply set your CMS page's Path to category/shoes and the getPage() method would resolve it automatically in the exact page match step. You could reuse the category path also for other pages, like category/shirts, category/pants, but a more flexible approach would be to use Many-to-One path mapping.

Many-to-One path mapping

Suppose you've got the same CMS entry for a Product Listing page with Path set to category. Now you want it to be fetched whenever users visit a certain group of paths in the Storefront. For this, you need to define a many-to-one relationship using a pattern (/category/*slug) instead of a specific path:

apps/storefront-middleware/sf-modules/cms-amplience/config.ts
export const config = {
  configuration: {
    unified: {
      resolvePages: (context, params) => ({
        "category/*slug": {
          path: "category",
        },
      })
    }
  }
}

Internally, we use the path-to-regexp library to resolve Storefront paths and patterns. Refer to its documentation to explore available notation options.

If some Storefront paths fall into the category/*slug pattern but you would like to fetch different CMS page entries for them, you can still leverage the exact page match strategy. For example, if you define a CMS page entry with Path equal to /category/shoes, the Storefront will fetch it whenever users visit the /category/shoes path. The category/*slug mapping will be ignored.

Mappings order

When defining multiple mappings, ensure that the most specific paths appear first, followed by more general patterns. This prevents more general patterns from overshadowing specific ones.

Correct Example ✅

apps/storefront-middleware/sf-modules/cms-amplience/config.ts
export const config = {
  configuration: {
    unified: {
      resolvePages: (context, params) => ({
        "category/shoes/nike": {
          path: "category/shoes"
        },
        "category/*slug": {
          path: "category",
        },
      })
    }
  }
}

Incorrect Example ❌

apps/storefront-middleware/sf-modules/cms-amplience/config.ts
export const config = {
  configuration: {
    unified: {
      resolvePages: (context, params) => ({
        "category/*slug": {
          path: "category",
        },
        /** This path will never be matched */
        "category/shoes/nike": {
          path: "category/shoes"
        },
      })
    }
  }
}

Read also

Now you know how to introduce complex relationships between your Storefront paths and CMS page entries. Read the other guides to learn even more about building amazing things with our CMS integrations.