Creating a blog using Contentful

Contentful is a headless content management system that can be used to create, manage, and publish content on any digital channel.

In this tutorial, you'll create a blog with commercetools Frontend using content from a Contentful account.

Before you start, create a sandbox in the studio and use this sandbox instance for local development.

Initial configuration

To get started, update your project configuration and publish a blog post following these steps:

  1. From Contentful dashboard > Settings > API keys, copy the Space ID, Preview token, and Access token. Then, update your project configuration in <customer>_<project>/config/project.yml with these values.
---
configuration:
content:
engine: contentful
spaceId: <space-id>
accessToken: <access-token>
previewToken: <preview-token>
  1. From Contentful dashboard > Content model, create a "Blog Post" content model with the following fields:
  • title: Short text
  • text: Long text
  1. From Contentful dashboard > Content, create an entry of type "Blog Post" and add the content below. Then, publish the entry.
title: "First blog post",
text: "#First blog post
This is the first blog post with ![example image](https://images.unsplash.com/photo-1550747528-cdb45925b3f7?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=989&q=80) Dump everything in the pot and follow link to [a website](https://foo.bar), to a [local doc](local-doc.html)."

Create a blog data source

To fetch blog posts from Contentful and pass the data to the Frontend components, create a data source following these steps:

  1. In the studio, go to Developer > Data sources and click Create schema.

  2. In the customDataSourceType field, enter frontastic/content.

  3. Copy the schema below and paste it into the schema editor, then click Publish.

{
"name": "Single content",
"category": "Content",
"icon": "source",
"schema": [
{
"name": "Content selection",
"fields": [
{
"label": "Content ID",
"field": "contentId",
"type": "text",
"translatable": false
}
]
}
]
}
  1. In the backend/content-contentful/index.ts file, implement the frontastic/content data source extension as follows. The contentId set in the studio is used to fetch the blog data from Contentful.
'data-sources': {
'frontastic/content': async (
config: DataSourceConfiguration,
context: DataSourceContext
) => {
const contentApi = new ContentApi(
context.frontasticContext,
getLocale(context.request)
);
return {
dataSourcePayload: await contentApi.getContent(
config.configuration.contentId
),
};
},
},

Create a blog page

To create a blog page in the studio, you have to:

  1. Create a blog component.
  2. Create a blog page folder.
  3. Create a blog page version.

Create a blog component

To display the data received from the data source in the blog, create a Frontend component following these steps:

  1. In the studio, go to the Components and click Create schema.

  2. In the tasticType field, enter commercetools/ui/content/blog.

  3. Copy the schema below and paste it into the schema editor, then click Publish and download JSON.

{
"name": "commercetools UI content blog",
"category": "Content",
"icon": "favorite",
"schema": [
{
"name": "Configuration",
"fields": [
{
"label": "Data",
"field": "data",
"type": "dataSource",
"dataSourceType": "frontastic/content",
"translatable": true
}
]
}
]
}
  1. In the tastics/content/blog/index.tsx file, implement the React component to render the Markdown content to HTML as follows. This way, you can access the Contentful content in the Frontend component through the data property, which is passed to the component at the time of server-side rendering by the frontastic/content data source.
import React from 'react';
import Markdown from 'components/commercetools-ui/content/markdown';
const Blog = ({ data }) => {
const { text } = data.data?.dataSource?.attributes;
return <Markdown text={text?.content} />;
};
export default Blog;
  1. Register this Frontend component in the tastics/index.tsx file.
import NotFound from './not-found';
import ContentfulBlog from './content/blog';
export const tastics = {
default: NotFound,
// ... other Frontend components
'commercetools/ui/content/blog': Blog,
};

Create a blog page folder

  1. In the studio, go to Site builder then click New > Create page folder: the Page folder settings dialog opens.

  2. In the General settings section, enter Contentful in the Page name field.

  3. In the Data source section, click + Add data source filter and select Single Content: the Edit data source filter page opens.

  4. In the Content selection section, enter the blog "Entry ID" from Contentful in the Content ID field and click Save. Then, click Save in the Create page folder dialog.

Create a blog page version

  1. From the page folders list, select the Contentful page folder. Then, click New > Create page version: the Create page version dialog opens.

  2. In the Page version name field, enter First blog. From the Layout drop-down, select the desired layout. Then, click Save.

  3. Click + and add a layout element to a section of the page.

  4. From the Components list, select the commercetools UI content blog component and drag it into the layout element.

  5. In the Component settings > Configuration section, select the Single content data source filter.

Contentful blog page builder

  1. To see the preview of the page version, click Preview. Then, click Save and click the back arrow to go back to Site builder.

  2. From the page folders list, select the Contentful page folder. Then, expand the Draft section.

  3. Hover on the First blog page version, click the more icon, and select Make default.

  4. Open http://localhost:3000/contentful in your browser to see the page live.

Contentful blog output

You've successfully built a blog page using the data from Contentful.

However, in a real-world scenario, configuring each page with a different blog "Entry ID" will get tedious and you'd want to render the blog content dynamically based on a URL path. For this, you can use dynamic pages to dynamically render a page based on the requested URL.

In the following sections, you can see how to dynamically render a blog based on the page request URL.

Create a dynamic blog page

  1. In the studio, go to Developer > Dynamic pages and click Create schema.

  2. In the dynamicPageType field, enter contentful/blog.

  3. Copy the schema below and paste it into the schema editor, then click Publish.

{
"name": "Contentful blog",
"category": "Documentation examples",
"icon": "list",
"dataSourceType": "frontastic/content",
"isMultiple": true
}

Providing dataSourceType in a dynamic page schema optimizes the fetching of the dataSourcePayload at the time of dynamic page resolution. In the example below, the dynamic-page-handler sends the dataSourcePayload for the frontastic/content data source. During server-side rendering, the dataSourcePayload is passed directly to the components that specify frontastic/content as the data source. This saves a network request, making the whole process faster.

  1. In the left-hand navigation, click Dynamic pages. Then, select the Contentful blog dynamic page.

  2. Select Default page in the Page rules section. Then, click + New page version: the Create page version dialog opens.

  3. In the Page version name field, enter Blog. From the Layout drop-down, select the desired layout. Then, click Save.

  4. Click + and add a layout element to a section of the page.

  5. From the Components list, select the Contentful blog component and drag it into the layout element.

  6. In the Component settings > Configuration section, select the frontastic/content data source filter.

Page builder Contentful dynamic blog

  1. In the Draft section, hover on the Blog page version, click the more icon, and select Make default.

Implement a blog dynamic page

The blog dynamic page should match the URL <your-site>/contentful/blog/<contentId>, fetch the content for the blogId from Contentful API, and render the markdown content on the page.

  1. In the backend/content-contentful/index.ts file of your project, add the sample code below specifying your Contentful credentials. This way, you implement the dynamic-page-handler extension to fetch the content for contentId from Contentful.
import {
DataSourceConfiguration,
DataSourceContext,
DynamicPageContext,
DynamicPageSuccessResult,
ExtensionRegistry,
Request,
} from '@frontastic/extension-types';
import ContentApi from './apis/ContentApi';
import * as ContentActions from './actionControllers/ContentController';
import { getLocale } from './utils/Request';
export default {
actions: {
content: ContentActions,
},
'data-sources': {
'frontastic/content': async (
config: DataSourceConfiguration,
context: DataSourceContext
) => {
const contentApi = new ContentApi(
context.frontasticContext,
getLocale(context.request)
);
return {
dataSourcePayload: await contentApi.getContent(
config.configuration.contentId
),
};
},
},
'dynamic-page-handler': async (
request: Request,
context: DynamicPageContext
): Promise<DynamicPageSuccessResult | null> => {
const [_, blogId] = request.query.path.match(
new RegExp('/contentful/blog/([^ /]+)')
);
if (blogId) {
const contentApi = new ContentApi(
context.frontasticContext,
getLocale(request)
);
return {
dynamicPageType: 'contentful/blog',
dataSourcePayload: await contentApi.getContent(blogId),
};
}
return {
dynamicPageType: 'contentful/blog',
dataSourcePayload: {},
};
},
} as ExtensionRegistry;
  1. Open <http://localhost:3000/contentful/blog/<contentId> in your browser to see your blog content.