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 article, you'll use content from a Contentful account with your Frontastic projectFrontastic project - The make-up of your commerce site (GitHub folder within customer repository, Frontastic studio access, and so on), you can have more than 1 project depending on your setup. by creating a blog.

Before we start, create a sandbox in your Frontastic studioFrontastic studio - The interface you use to manage, build, and edit all areas of your project and commerce sites. Previously known as `backstage`. and use this Frontastic sandboxFrontastic sandbox - A virtual machine hosted in the cloud that you can use for backend and some frontend development. They're provisioned from the developer area of the Frontastic studio. instance for local development.

Contentful dashboard

Open Contentful, then:

  1. Copy the Space ID and Access token from your Contentful dashboard and save them for later

  1. Create a Blog content model like below

  1. Publish the first Blog Post

Then, update your Frontastic configuration in <customer>_<project>/config/project.yml

...
configuration:
    contentful:
        spaceID: <space-id>
        accessToken: <access-token>
...

Create a blog data source

To fetch blogs from Contentful and pass the data to the components, you need to create a data sourcedata source - The data provided from an API to display products, content, or anything from an integration or extension. A data source filter is created and can be selected for a Frontastic component that will display the data source filter on your commerce site..

  1. Create a data sourcedata source - The data provided from an API to display products, content, or anything from an integration or extension. A data source filter is created and can be selected for a Frontastic component that will display the data source filter on your commerce site. schemaschema - The framework behind a Frontastic component and the fields that are available within the Frontastic studio.
{
    "customDataSourceType": "contentful/blog",
    "name": "Contentful blog",
    "category": "Documentation examples",
    "icon": "source",
    "schema": [
        {
            "name": "Settings",
            "fields": [
                {
                    "label": "Blog ID",
                    "field": "blogId",
                    "type": "string",
                    "translatable": false
                }
            ]
        }
    ]
}
  1. Upload the data sourcedata source - The data provided from an API to display products, content, or anything from an integration or extension. A data source filter is created and can be selected for a Frontastic component that will display the data source filter on your commerce site. schema to the Frontastic studioFrontastic studio - The interface you use to manage, build, and edit all areas of your project and commerce sites. Previously known as `backstage`.

  1. Install the contentful package by running yarn add contentful inside the <package>/backend folder.
  2. To get the blog data from Contentful Delivery API, implement a getBlogFromId function which takes theblogId and frontasticContext and returns the data fields from Contentful response data.

🚧

You must use require with the contentful package.

const contentful = require('contentful');

const SPACE_ID = 'a2bq7lmfe3nn';

async function getBlogFromId(blogId: string, frontasticContext: Context) {
  const { accessToken } = frontasticContext.project.configuration.contentful;
  try {
    const contentfulClient = contentful.createClient({ space: SPACE_ID, accessToken });
    const response = await contentfulClient.getEntry(blogId);
    return response.fields;
  } catch (e) {
    return e.message;
  }
}

📘

This examples uses the Contentful npm package, but you can also use their Content Delivery API.

  1. Implement the contentful/blog data sourcedata source - The data provided from an API to display products, content, or anything from an integration or extension. A data source filter is created and can be selected for a Frontastic component that will display the data source filter on your commerce site. extension inside the backend/index.ts
'contentful/blog': async (
      config: DataSourceConfiguration,
      context: DataSourceContext,
    ): Promise<DataSourceResult> => {
      const { blogId } = config.configuration;
      if (blogId) {
        const blogData = await getBlogFromId(blogId, context.frontasticContext);
        return {
          dataSourcePayload: blogData,
        };
      }
      return {
        dataSourcePayload: config.configuration,
      };
    },

Create a blog component

To display the blog content from the data received from the data sourcedata source - The data provided from an API to display products, content, or anything from an integration or extension. A data source filter is created and can be selected for a Frontastic component that will display the data source filter on your commerce site., you need to create a Frontastic componentFrontastic component - A customizable building block that's used together with other components to create a commerce site. Known as `tastic` for short in code..

  1. Create a schema.json for the Frontastic componentFrontastic component - A customizable building block that's used together with other components to create a commerce site. Known as `tastic` for short in code. in frontend/frontastic/tastics/contentful/blog/

    {
        "tasticType": "contentful/blog",
        "name": "Contentful blog",
        "icon": "list",
        "category": "Documentation examples",
        "schema": [
            {
                "name": "Configuration",
                "fields": [
                    {
                        "label": "Content",
                        "field": "content",
                        "type": "dataSource",
                        "dataSourceType": "contentful/blog",
                        "required": true
                    }
                ]
            }
        ]
    }
    
    
  2. Upload this component schemaschema - The framework behind a Frontastic component and the fields that are available within the Frontastic studio. to the Components section of the Frontastic studioFrontastic studio - The interface you use to manage, build, and edit all areas of your project and commerce sites. Previously known as `backstage`.

  1. Implement the React component in the /tastics/contentful/blog/index.tsx, to render the markdown content to html.
    You can access the Contentful content in your component in the data property, which is passed to the component at the time of Server Side Rendering by the contentful/blog data sourcedata source - The data provided from an API to display products, content, or anything from an integration or extension. A data source filter is created and can be selected for a Frontastic component that will display the data source filter on your commerce site..
import React from 'react';
import { fetcher } from 'frontastic';
import Markdown from 'components/frontastic-ui/content/markdown';

const ContentfulBlog = ({ data }) => {
  return (
    <Markdown
      text={data.content.dataSource.text}
    />
  );
};

export default ContentfulBlog;
{
    "_type": "Frontastic\\Catwalk\\FrontendBundle\\Domain\\Tastic\\Configuration",
    "mobile": true,
    "tablet": true,
    "desktop": true,
    "content": {
        "_type": "Frontastic\\Catwalk\\NextJsBundle\\Domain\\Api\\TasticFieldValue\\DataSourceReference",
        "dataSourceId": "__master",
        "dataSource": {
            "title": "First ever blog",
            "text": "An h1 header\n============\n\nParagraphs are separated by a blank line.\n\n2nd paragraph. *Italic*, **bold**, and `monospace`. \n\nAgain, text is indented 4 spaces. (Put a blank line between each\nterm and  its definition to spread things out more.)\n\nand images can be specified like so:\n\n![example image](https://images.unsplash.com/photo-1550747528-cdb45925b3f7?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=989&q=80 \"An exemplary image\")\n\nAn h2 header\n------------\n\nHere's a numbered list:\n\n 1. first item\n 2. second item\n 3. third item\n\n### An h3 header ###\n\nNow a nested list:\n\n 1. First, get these ingredients:\n\n      * carrots\n      * celery\n      * lentils\n\n 2. Boil some water.\n\n 3. Dump everything in the pot and follow\n    this algorithm:\n\nHere's a link to [a website](http://foo.bar), to a [local\ndoc](local-doc.html), and to a [section heading in the current\ndoc](#an-h2-header). Here's a footnote [^1].\n\nA horizontal rule follows.\n\n***\n"
        }
    }
}
  1. Register this component in the tastics/index.tsx file
import NotFound from './not-found';
import ContentfulBlog from './contentful/blog';

export const tastics = {
  default: NotFound,
  'contentful/blog': ContentfulBlog,
};

Create a blog page in the studio

  1. Open the Site builder in the Frontastic studioFrontastic studio - The interface you use to manage, build, and edit all areas of your project and commerce sites. Previously known as `backstage`. and create a new page folder called first-blog

  1. Expand the Data source section and click + Add data source filter

  1. Use the blog Entry Id from Contentful dashboard as the Blog ID field and click Save

  1. Create a new page version called first inside the first-blog page folder

  1. Add a layout elementlayout element - What needs to be added to a page before a Frontastic component can be added or a component group. Previously known as `cell`. to your page and then drag the Contentful blog component into it

  1. Select the First blog data sourcedata source - The data provided from an API to display products, content, or anything from an integration or extension. A data source filter is created and can be selected for a Frontastic component that will display the data source filter on your commerce site. filter created in the previous step in the component settings

You can click Preview to see your page already.

  1. Click Save

  2. Hover on the page version, click the more icon, and select Make default

You should see the page live on http://localhost:3000/doc-examples/first-blog

:tada: Yay! You've successfully built a blog page using the data from Contentful.

In a real world scenario, configuring each page with a different blog ID will get tedious and you'd want to render the blog content dynamically based on a URL path. For this, you can use Frontastic dynamic pagesdynamic pages - A type of page that creates the default layout of pages that use the same structure but with different data, for example, a Product Details Page, wishlist, cart, search, and so on. Previously known as `master pages`. to dynamically render a page based on the requested URL.

Let's extend this example to dynamically render a blog based on the page request URL.

Create the dynamic page in the studio

  1. Create a schemaschema - The framework behind a Frontastic component and the fields that are available within the Frontastic studio. for the blog dynamic pagedynamic page - A type of page that creates the default layout of pages that use the same structure but with different data, for example, a Product Details Page, wishlist, cart, search, and so on. Previously known as `master page`.

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

📘

Data source in dynamic pages

Providing dataSourceType in a dynamic page schema is an optimization for fetching the dataSourcePayload at the time of dynamic page resolution. In this example, the dynamic-page-handler is expected to send the dataSourcePayload for the contentful/blog data source, and at the time of Server Side Rendering it'll directly be passed to the components which specify contentful/blog as the data source. By doing so, we save a network request making the whole process faster.

  1. Upload this dynamic pagedynamic page - A type of page that creates the default layout of pages that use the same structure but with different data, for example, a Product Details Page, wishlist, cart, search, and so on. Previously known as `master page`. schemaschema - The framework behind a Frontastic component and the fields that are available within the Frontastic studio. to the Developer > Dynamic pages area in the Frontastic studioFrontastic studio - The interface you use to manage, build, and edit all areas of your project and commerce sites. Previously known as `backstage`.

  1. Go to the Dynamic pages area using the left-hand navigation, create a New page version called start under the Contentful blog dynamic page folder

  1. Add a layout elementlayout element - What needs to be added to a page before a Frontastic component can be added or a component group. Previously known as `cell`. to your page, then add the Contentful blog component, select the contentful/blog data source filter, and click Save

  1. Hover on the start page version in Draft, click the more icon, and select Make default

Implement the blog dynamic page

The dynamic pagedynamic page - A type of page that creates the default layout of pages that use the same structure but with different data, for example, a Product Details Page, wishlist, cart, search, and so on. Previously known as `master page`. should match the URL <your-site>/contentful/blog/<blogId>, fetch the content for the blogId from Contentful API, and render the markdown content on the page.

  1. Implement the dynamic-page-handler extension in backend/index.ts to fetch the content for blogId from Contentful. For this, you can re-use the getBlogFromId function to keep the dataSourcePayload consistent.
import {
  ActionContext,
  DataSourceConfiguration,
  DataSourceContext,
  DataSourceResult,
  DynamicPageSuccessResult,
  Request,
  Response,
} from '@frontastic/extension-types';
import axios from 'axios';

const contentful = require('contentful');

const SPACE_ID = 'a2bq7lmfe3nn';

async function getBlogFromId(blogId: string, frontasticContext: Context) {
  const { accessToken } = frontasticContext.project.configuration.contentful;
  try {
    const contentfulClient = contentful.createClient({ space: SPACE_ID, accessToken });
    const response = await contentfulClient.getEntry(blogId);
    return response.fields;
  } catch (e) {
    return e.message;
  }
}

export default {
  'dynamic-page-handler': async (request: Request): Promise<DynamicPageSuccessResult | null> => {
    const [_, blogId] = request.query.path.match(new RegExp('/contentful/blog/([^ /]+)'));
    if (blogId) {
      const blogData = await getBlogFromId(blogId, context.frontasticContext);
      return {
        dynamicPageType: 'contentful/blog',
        dataSourcePayload: blogData,
      };
    }
  },
  'data-sources': {
    'contentful/blog': async (config: DataSourceConfiguration, context: DataSourceContext): Promise<DataSourceResult> => {
      const { blogId } = config.configuration;
      if (blogId) {
        const blogData = await getBlogFromId(blogId, context.frontasticContext);
        return {
          dataSourcePayload: blogData,
        };
      }
    },
  }
};
  1. Open http://localhost:3000/contentful/blog/6EK4wrX5cyT8GKXEs2NxBJ in your browser, and you should see a page like shown in the image below

👍

It's an excellent example of how our extensions are implementation agnostic — developers can implement any logic they want, be it a REST API call or GraphQL query or even using some SDK. This gives developers the freedom to work around such problems and choose the solution that works for their project.


Did this page help you?