Contentful 懶人包

學 Next 時使用的一種工具,還蠻不錯用的。

What is this?

Contentful 是一種 CMS(Content Management System),而且是「Headless」的 CMS。建議先參考這個影片理解一下 Headless 跟一般的 CMS 差別在哪?我覺得解釋的很清楚。

簡單來說它就是一種「介面」,讓你可以在上面管理內容,實際用起來會像這樣:

example

當我們在 Contentful 建立好內容後,會透過 API(AKA Contentful SDK)來把內容串接到前端上。

因為是 Headless,代表前端的部分是可以自由發揮的,你可以拿來串接到任何你想要的框架上,例如 React.js 或 Next.js。

總而言之,Contentful 是一套不錯用的 CMS,所以才會寫這篇來紀錄。

基本概念與功能

Space

可以想成是 Collection 的概念,就是「拿來放所有東西的地方」。免費帳戶只會有一個,要有多個的話必須付費才行。

雖然說免費帳戶只有一個,不過只是要拿來練習的話算是綽綽有餘了。

Content Model

用來定義內容的「欄位」,你可以在這邊定義:

  1. 內容該有哪些欄位?
  2. 欄位的種類是文字?還是圖片?等等
  3. 欄位的規則?(必填、Regex、檔案種類等等)

例如說我有一個食譜的內容,那就會有這樣的 Model:

content-model

Content

這邊就是「編輯內容」的地方,編輯的欄位會依照「Content Model」的設定來讓我們填寫:

content

Media

除了文字以外,你也可以把本機的「多媒體」內容,例如圖片,上傳到 Contenful 上。

media

上傳以後就可以在編輯的時候直接拿來用,這樣就不用再另外找第三方服務來幫你把圖片轉成 url 了,例如 Imgur

API 串接

這邊會以 Next 為例。

讀取

懶人包:

  • createClient 來跟 Contentful 連線
  • getEntries 抓取某個 content
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import { createClient } from 'contentful'

export async function getStaticProps() {
const client = createClient({
space: process.env.CONTENTFUL_SPACE_ID,
accessToken: process.env.CONTENTFUL_ACCESS_TOKEN
})
const response = await client.getEntries({
content_type: 'recipe'
})

return {
props: {
recipes: response.items
}
}
}

export default function Recipes({ recipes }) {
console.log('props', recipes)

return <div className='recipe-list'>Recipe List</div>
}

讀取(搭配 query)

當你想要抓取「單筆」資料時可能就會需要用到 query,可以用 'fields.<property>' 的方式來指定:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import { createClient } from 'contentful'

export async function getStaticProps() {
const client = createClient({
space: process.env.CONTENTFUL_SPACE_ID,
accessToken: process.env.CONTENTFUL_ACCESS_TOKEN
})
const response = await client.getEntries({
content_type: 'recipe',
// 找出相同 slug 的食譜
'fields.slug': params.slug
})

return {
props: {
recipes: response.items
}
}
}

export default function Recipes({ recipes }) {
console.log('props', recipes)

return <div className='recipe-list'>Recipe List</div>
}

渲染 Rich Text

如果內容包含「rich-text」的話會發現拿到的內容會長這樣:

rich-text

這樣就不知道要怎麼輸出了對吧?

不過 contentful 早就幫你準備好了,只要用它提供的 @contentful/rich-text-react-renderer 來處理就行了。

附上官網範例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import { documentToReactComponents } from '@contentful/rich-text-react-renderer'

const document = {
nodeType: 'document',
data: {},
content: [
{
nodeType: 'paragraph',
data: {},
content: [
{
nodeType: 'text',
value: 'Hello world!',
marks: [],
data: {}
}
]
}
]
}

documentToReactComponents(document) // -> <p>Hello world!</p>

這樣子可以輸出正確 HTML 格式的內容了。

Ant Design-客製化 Select Next.js-fallback
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×