Content Types
Content Types empower developers to craft autonomous, reusable schemas. These can be employed by Content Managers to assemble dynamic web pages. This guide elucidates how to utilize the provided tool to create content-driven dynamic pages.
Expose Data in GraphQL
Initially, you must update your GraphQL Schema to mirror the ContentType definitions, which will be structured as a GraphQL union type.
type AcmeHomePage {
title: String
blocks: [AcmeHomePageBlock]
seo: Seo
}
type AcmeSeo {
title: String
description: String
}
union AcmeHomePageBlock = BlockTitleText | BlockTextImage
type BlockTitleText {
title: String
subtitle: String
align: String
}
type BlockTextImage {
title: String
picture: String
picturePosition: String
}
Crafting ContentTypes
To commence, create your initial ContentType for AcmeHomepage
, which will
be utilized to populate our homepage.
The constructor of the ContentType class accepts four arguments:
id
- The Content type id as displayed on the Contentful model detail screen.fcGraphQLType
- The GraphQL type defined in your schema.dataFormatter
- A function transforming Contentful data to fit your schema.
import { ContentType } from "@front-commerce/contentful";
import gql from "graphql-tag";
const formatContentfulData = (contentfulData) => {
return {
title: contentfulData.pageTitle,
slug: contentfulData.pageSlug,
};
};
class Homepage extends ContentType {
constructor() {
super("homepage", "AcmeHomepage", formatContentfulData);
}
get contentfulFragment() {
return gql`
fragment HomepageFragment on Homepage {
pageTitle
pageSlug
}
`;
}
}
export default Homepage;
Loading Data with the ContentfulLoader
With the ContentfulLoader, you can implement a contextEnhancer
in your
module to retrieve homepage data from Contentful.
Should you require a list of content items rather than a singular item, the
loadAllContentMatching
loader method is at your service. It accepts parameters similar to
loadFirstContentMatching
,
with added pagination arguments:
skip
- Number of items to bypass.limit
- Quantity of items to fetch.order
- Ordering criteria, accepted as a string or string[]. For more, see Contentful GraphQL API.
First, create the GraphqlModule
file:
import { createGraphQLModule } from "@front-commerce/core/graphql";
export default createGraphQLModule({
namespace: "Acme/MyModule",
dependencies: ["Contentful"],
loadRuntime: () => import("./runtime"),
});
Then we will create the GraphqlRuntime
file:
import Homepage from "./contentType/Homepage";
import { createGraphQLRuntime } from "@front-commerce/core/graphql";
export default createGraphQLRuntime({
resolvers: {
Query: {
loadHomepages: async (
parent,
args,
{ loaders: { ContentfulHomePage, Contentful } }
) => {
const response = await Contentful.loadAllContentMatching(
ContentfulHomePage,
undefined,
0,
5
);
return response.items.map(HomePage.dataFormatter);
},
},
},
contextEnhancer: ({ req, loaders }) => {
return {
ContentfulHomePage: new Homepage(),
};
},
});
Creating an Independent ContentType
Our present AcmeHomepage
is fairly basic. Enhance it by integrating an
independent ContentType, such as the seo
data for our homepage.
import { ContentType } from "@front-commerce/contentful";
import gql from "graphql-tag";
const formatContentfulData = (contentfulData) => {
return {
title: contentfulData.seoTitle,
description: contentfulData.seoDescription,
};
};
class Seo extends ContentType {
constructor() {
super("seo", "AcmeSeo", formatContentfulData);
}
get contentfulFragment() {
return gql`
fragment SeoFragment on Seo {
seoTitle
seoDescription
}
`;
}
}
export default Seo;
Seo
ContentType has its distinct formatter. We transfer it to the homepage
formatter and utilize it for formatting the seo data.
Integrating ContentTypes
with BlocksContentType
The BlocksContentType
is a unique ContentType that facilitates the creation of
a repository of ContentTypes. These can be harnessed to generate reusable
UI components.
Construct the AcmeHomePageBlock
ContentType, which embodies the collection of
ContentTypes constituting our union type.
import { BlocksContentType } from "@front-commerce/contentful";
const AcmeHomePageBlock = new BlocksContentType(
"homepage",
"PageContentBlocksItem",
[],
"HomePageBlock"
);
export default AcmeHomePageBlock;
Now, establish the BlockTextTitle
ContentType, intended for utilization by the
AcmeHomePageBlock
ContentType.
import { ContentType } from "@front-commerce/contentful";
import gql from "graphql-tag";
const formatContentfulData = (contentfulData) => {
return {
title: contentfulData.blockTitle,
subtitle: contentfulData.excerpt,
};
};
class BlockTextTitle extends ContentType {
constructor() {
super("blockTextTitle", "BlockTextTitle", formatContentfulData);
}
get contentfulFragment() {
return gql`
fragment BlockTextTitleFragment on BlockTextTitle {
blockTitle
excerpt
}
`;
}
}
The BlocksContentType
has a specialized formatter. We import it to the
homepage formatter for blocks data formatting.