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
After
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.
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.
// 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.
// 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.
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.
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.
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.
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}}
.
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.
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.
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.
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.
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:
Group | Field | Value |
---|---|---|
Resolutions | Max | 767px |
Gaps | Row gap | 16px |
Grid | Display | grid |
Grid | Grid template areas | "a" "b" "c" |
And for desktop set:
Group | Field | Value |
---|---|---|
Resolutions | Min | 768px |
Gaps | Column gap | 16px |
Grid | Display | grid |
Grid | Grid 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:
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.