Vue Storefront is now Alokai! Learn More
Creating CMS pages

Creating CMS pages

In the Quick start guide, you've created a simple CMS page using the readily-available Content Types provided by Alokai. Now it is time for you to dive deeper and learn how to create CMS pages almost from scratch.

In this guide, you will work with the Login page of the Alokai Storefront which - by default - only features a login form. Your task will be to enhance it with dynamic CMS-managed marketing content.

Before

initial login

After

updated login

In the process, you will:

  • prepare your Storefront page component for dynamic CMS content fetching & rendering,
  • create a Content Type for a page in your CMS,
  • create a page entry in your CMS and add a custom Picture component to it.

This guide assumes you have already followed this guide and created your custom Picture component.

Prepare the Storefront page

By default, the Login page in our Storefront only contains a simple authentication form. In this section, we will adjust its code so that it fetches dynamic data from the CMS and renders it in the desired location.

Code examples in these steps refer to the frontend part of your project: /apps/storefront-unified-nextjs/app/[locale].

1

Divide the Login Page into two sections

The page itself currently consists of a single section with the login form centered. Let's modify the layout to include two sections side by side.

(auth)/login/page.tsx
export async function LoginPage() {
  const t = useTranslations('LoginPage');
  const messages = useMessages();
    
  return (
    <div className="pb-10 md:pb-6">
      <div className="grid gap-10 md:grid-cols-2">        <section>          {/* Login Form, it remains unchanged */}
        </section>        <section>          {/* CMS Content will go here */}        </section>      </div>    </div>
  );
}

2

Fetch data from the CMS

Our login page will have just one slot for CMS content named components. To connect the page with the CMS, we need to wrap it with the connectCmsPage higher-order component. connectCmsPage requires a CMS page path, which will be just /login in our case. It will handle the CMS data fetching and pass it as a page prop into the LoginPage component.

(auth)/login/page.tsx
// Make sure to replace `<name>` with the actual name of your CMS module
import connectCmsPage, { PropsWithCmsPage } from '@sf-modules/cms-<name>/components/connect-cms-page';

interface LoginPage {
  components: any;
}

type LoginPageProps = PropsWithCmsPage<LoginPage>;

export async function LoginPage() { async function LoginPage({ page }: LoginPageProps) {   const t = useTranslations('LoginPage');
  const messages = useMessages();

  return (
    <div className="pb-10 md:pb-6">
      {/* ... */}
    </div>
  );
}

export default connectCmsPage(LoginPage, {    getCmsPagePath: () => '/login',  });  

So far we didn't create the Login page in the CMS, so the page prop will be null. We'll create the page in the CMS in the next steps.

3

Add RenderCmsContent component

To render the CMS content, we need to pass it to the RenderCmsContent component, which will render the corresponding frontend components. Let's add it to the LoginPage component.

(auth)/login/page.tsx
// Make sure to replace `<name>` with the actual name of your CMS module
import RenderCmsContent from '@sf-modules/cms-<name>/components/render-cms-content'; 
async function LoginPage({ page }: LoginPageProps) {

  return {
    ...
    <section>
      {/* CMS Content will go here */}      {page?.components && <RenderCmsContent item={page.components} />}    </section>
    ...
  );
}

4

Expand the Auth Layout container

The default Auth Layout container is too narrow to accommodate two sections side by side. Let's adjust the layout to make it wider.

(auth)/layout.tsx
import type { PropsWithChildren } from 'react';

import Footer from '@/components/navigations/footer';
import NavbarTop from '@/components/navigations/navbar-top';

interface AuthLayoutProps extends PropsWithChildren {}

export default async function AuthLayout({ children }: AuthLayoutProps) {
  return (
    <>
      <NavbarTop />
      <main>
        <div className="mx-auto max-w-[630px] px-4 pb-10 pt-4 md:px-0 md:pb-14 md:pt-9">        <div className="mx-auto max-w-screen-3-extra-large px-6 pb-10 pt-4 md:px-10 md:pb-14 md:pt-9">          {children}
        </div>
      </main>
      <Footer className="mb-[58px] md:mb-0" />
    </>
  );
}

This change will affect all pages using the Auth Layout. Make sure to test other pages to ensure they still look as expected.

Create CMS Content Type

With our Storefront ready to display CMS content on the Login page, the next task it to create a corresponding Content Type in the CMS.

1

Create a new Content Type

From to the Development dropdown choose Content Type schemas. Once a popup appears on the screen, choose "code from scratch". Set https://www.vuestorefront.io/login-page.json as schema id and set Content Type as the validation level. Hit the Create schema button to confirm.

Create Content Type Modal

You might consider making this Content Type more reusable, by naming it Single Slot Page which will allow you to use it in the future for other pages with a single slot for CMS content.

2

Complete the schema

Next step is to add the required fields to the Content Type schema. The schema will be similar to the schemas for the other page types. This time we need just a components field, which will be a reference to the components we want to use on the Login Page - in our case Grid and Picture components.

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "$id": "https://www.vuestorefront.io/login-page.json",
  "title": "Login Page",
  "description": "Content for Login Page",
  "allOf": [
    {
      "$ref": "http://bigcontent.io/cms/schema/v1/core#/definitions/content"
    }
  ],
  "type": "object",
  "properties": {
    "components": {
      "type": "array",
      "title": "Components",
      "description": "Components rendered in right section of the Login Page",
      "items": {
        "allOf": [
          {
            "$ref": "http://bigcontent.io/cms/schema/v1/core#/definitions/content-link"
          },
          {
            "properties": {
              "contentType": {
                "enum": [
                  "https://www.vuestorefront.io/grid.json",
                  "https://www.vuestorefront.io/picture.json"
                ]
              }
            }
          }
        ]
      }
    }
  },
  "propertyOrder": []
}

3

Register the Content Type

Once the schema is ready, you can choose from the Save dropdown Save and register as content type option.

Save schema

In the following screen set the Content type label to Login Page and set associated repository to Content. Optionally you can also add the icon and card for better recognition of the Content Type for final users.

Fill Content Type

Now we have to adjust the config on the middleware side to match the /login path with the login_page Content Type.

4

Add Visualization

To be able to preview the Picture Content Type, go to the Visualizations tab and create a new visualization. The Visualization URL should point to the /login page and include all the tokens in search parameters. For example: http://localhost:3000/login?hubName={{hub.name}}&contentItemId={{content.sys.id}}&deliveryKey={{delivery.key}}&snapshotId={{snapshot.id}}&vseDomain={{vse.domain}}&locales={{locales}}.

Localhost visualization

Once done, click the Save button to confirm.

Next.js has an issue with displaying authenticated pages in Visualizations. A workaround is to update the Next.js middleware.ts to catch error in getCustomer method.

apps/storefront-unified-nextjs/middleware.ts
async function getAuthRedirectPath(request: NextRequest) {
  const sdk = getSdk();
  const checkIsLoggedIn = () => sdk.unified.getCustomer().then(({ customer }) => !!customer);   const checkIsLoggedIn = () =>
    sdk.unified
      .getCustomer()
      .then(({ customer }) => !!customer)
      .catch(() => false);

  //...
}

Create CMS content

Now that we have a Content Type for the Login Page, we can create content for it. The content will be displayed on the Login Page in the CMS-managed section.

1

Add a main Picture component

First we'll create a caption for our main Picture component. Navigate to the Content page and click the Create content button in the top right corner. Choose Editorial from the list. Then fill the content and click Save. Additionally, you can add a margin top to the caption to make it look better. To do this, add a group entry in the Styles field.

Caption for main Picture

Caption margin

Then create a new Picture entry. Upload an image and choose the previously created Caption entry in the Caption field. Once done, save the entry.

Caption for main Picture

2

Add an icon

Below the main Picture, there is a grid of icons. To create a first icon, create a new Editorial entry for caption, and then a new Picture entry for the icon. Upload the icon image and choose the caption entry in the Caption field.

Adding an icon

Publish the icon entry and repeat the process for the remaining icons.

3

Place the icons in a grid

To display the icons in a grid, create a new Grid entry. To be able to add a Picture component into the Grid, you need to add a Picture Content Type as allowed in Grid schema. Go to Content type schemas page and find https://www.vuestorefront.io/grid.json schema. Then update the items property and choose Save and sync content type from the Save dropdown.

{
  "properties": {
    "items": {
      "type": "array",
      "items": {
        "type": "object",
        "allOf": [
          {
            "$ref": "http://bigcontent.io/cms/schema/v1/core#/definitions/content-link"
          },
          {
            "properties": {
              "contentType": {
                "enum": [
                  "https://www.vuestorefront.io/banner.json",
                  "https://www.vuestorefront.io/hero.json",
                  "https://www.vuestorefront.io/card.json",
                  "https://www.vuestorefront.io/category-card.json",
                  "https://www.vuestorefront.io/product-card.json",
                  "https://www.vuestorefront.io/editorial.json",
                  "https://www.vuestorefront.io/scrollable.json",
                  "https://www.vuestorefront.io/newsletter-box.json",
                  "https://www.vuestorefront.io/accordion.json",
                  "https://www.vuestorefront.io/gallery.json",
                  "https://www.vuestorefront.io/picture.json"                ]
              }
            }
          }
        ]
      }
    }
  }
}

After that, you can create a new Grid entry on the Content page. Add the icons to the grid by in the Items field.

In Styles field, add two styles. One for the mobile, to display the icons in a column. For mobile set:

GroupFieldValue
ResolutionsMax767px
GapsRow gap16px
GridDisplaygrid
GridGrid template areas"a" "b" "c"

And for desktop set:

GroupFieldValue
ResolutionsMin768px
GapsColumn gap16px
GridDisplaygrid
GridGrid template areas"a b c"

You can also add Margin -> Margin top to make some space between the main Picture and the icons grid. After that, save the grid entry and it should look like this:

Adding a grid

4

Create a Login Page entry

Finally, create a new Login Page entry. Add the main Picture and the grid of icons to the Components field, and save the entry.

Creating the Login Page entry

Read also

Congratulations! You’ve successfully integrated CMS content into your Login Page. With this knowledge, you can now enhance other pages in your Storefront to leverage the power of CMS.