#3 Gatsby + WordPress REST APIでブログを作ろう【カテゴリーページ編】
今回はGatsby連載の#3「カテゴリーページの作り方」編です^ ^
- Step1:WordPress側で記事にカテゴリーを追加
- Step2:記事のカテゴリーを全部取得する
- Step3:カテゴリーページのテンプレートを作る
- Step4:gatsby-node.jsをカテゴリーページを生成するように編集する
- Step5:全てのカテゴリーの一覧を表示させるカテゴリーインデックスページを作成
- Step6:それぞれの記事にカテゴリーを表示
Step1:WordPress側で記事にカテゴリーを追加
WordPressで使用したいカテゴリーを追加してテストでいくつかサンプル記事を準備しておきます
何も設定していないと「Uncategorized」or「未分類」になります
Step2:記事のカテゴリーを全部取得する
graphqlの画面でallWordpressCategoryで全てのカテゴリーがちゃんと取ってこれているか確認します
ちゃんと取れていますね^ ^
gatsby developをしたままですと更新されてないかと思いますので、一旦止めてgatsby developし直してください
*allWordpressPostの中にあるcategories{name}ではうまくいかなかったです
Step3:カテゴリーページのテンプレートを作る
templateの中にCategories.jsを作ります
これがカテゴリーページのテンプレートになります
import React from "react"
import { Link, graphql } from "gatsby"
import Img from "gatsby-image"
import Layout from "../components/layout"
import SEO from "../components/seo"
const Categories = ({ data, pageContext }) => {
const { category } = pageContext
return (
<Layout>
<SEO title={category} keywords={category} />
<div>
<h2>{category}</h2>
{data.allWordpressPost.edges.map(post => (
<div key={post.node.id} className={"post"}>
<Link to={`/${post.node.slug}`} >
{post.node.featured_media &&
<div>
<Img
fluid={post.node.featured_media.localFile.childImageSharp.fluid}
alt={post.node.title}
/>
</div>
}
<h3>{post.node.title}</h3>
</Link>
<div className={"post-content"} dangerouslySetInnerHTML={{__html: post.node.excerpt}} />
{post.node.date}
</div>
))}
</div>
</Layout>
)
}
export default Categories
export const query = graphql`
query ($category: String!) {
allWordpressPost(filter: {categories: {elemMatch: {name: {eq: $category}}}}) {
edges {
node {
id
excerpt
title
slug
featured_media {
localFile {
childImageSharp {
fluid(maxWidth: 1000) {
...GatsbyImageSharpFluid
}
}
}
}
date(formatString: "MMMM DD, YYYY")
}
}
}
}
`
pageContextについては後ほどgatsby-node.jsの箇所で解説します
queryでは$category : String!で例えば”test”カテゴリが渡ってきて、そのカテゴリにマッチする記事を全部表示するようにフィルターにかけています
graphqlのページで見てみるとある程度わかるかと思いますが、query($category: String!)と書いてもちゃんと動いてくれないので、実際に書いてgatsby developをして確認するしか無いです
まだgatsby-node.jsを編集していないので、何もおきません
Step4:gatsby-node.jsをカテゴリーページを生成するように編集する
まずlodashを使いたいのでnpmかyarnでlodashをインストールします
npm install --save lodash
or
yarn add lodash
gatsby-node.jsに追記していきます
const path = require(`path`)
const _ = require(`lodash`) //<-lodashをrequire
const createPaginatedPages = require('gatsby-paginate')
exports.createPages = async ({ graphql, actions, reporter }) => {
const { createPage } = actions
const BlogPostTemplate = path.resolve("./src/templates/BlogPost.js")
const PageTemplate = path.resolve("./src/templates/Page.js")
const CatTemplate = path.resolve("./src/templates/Categories.js") //<-カテゴリーページのテンプレート
const result = await graphql(`
{
allWordpressPost {
edges {
node {
id
title
date(formatString: "MMMM DD, YYYY")
excerpt
slug
wordpress_id
categories {
name
}
featured_media {
localFile {
childImageSharp {
fluid(maxWidth: 1000) {
src
srcSet
aspectRatio
sizes
base64
}
}
}
}
}
}
}
allWordpressPage {
edges {
node {
slug
wordpress_id
}
}
}
allWordpressCategory {
edges {
node {
name
}
}
}
}
`)
if (result.errors) {
reporter.panicOnBuild(`Error while running GraphQL query.`)
return
}
const BlogPosts = result.data.allWordpressPost.edges
BlogPosts.forEach(post => {
createPage({
path: `/${post.node.slug}`,
component: BlogPostTemplate,
context: {
id: post.node.wordpress_id,
},
})
})
const Pages = result.data.allWordpressPage.edges
Pages.forEach(page => {
createPage({
path: `/${page.node.slug}`,
component: PageTemplate,
context: {
id: page.node.wordpress_id,
},
})
})
createPaginatedPages({
edges: BlogPosts,
createPage: createPage,
pageTemplate: 'src/templates/Pagination.js',
pageLength: 5,
pathPrefix: 'posts',
})
// 全カテゴリーの名前を取得しcatsの中に入れる
const BlogCategories = result.data.allWordpressCategory.edges
let cats = []
_.each(BlogCategories, edge => {
if (_.get(edge, "node.name")) {
cats = cats.concat(edge.node.name)
}
})
// 被ったカテゴリーを排除
cats = _.uniq(cats)
// 取ってきたカテゴリー毎にテンプレート(Categories.js)を使ってページを生成する
cats.forEach(category => {
createPage({
path: `/categories/${_.kebabCase(category)}/`,
component: CatTemplate,
context: {
category: category, //<-これがpageContextとしてCategories.jsに渡る、queryで($category: String!)が使えるようになる
},
})
})
}
コメントで少し解説していますが、やっていることは超簡単に言うと「全カテゴリーを取得してそのカテゴリー毎にページをテンプレート(Categories.js)を使用して生成している」ということです
allWordpressPostとallWordpressPageと別にallWordpressCategoryを追加して全カテゴリーのデータを引っ張ってきています
categories/test/に行くとちゃんと”test”カテゴリーの記事が表示されるかと思います
allWordpressPost内のcategories{name}で引っ張ってきて同じことをしようとしたのですが、うまくいかなかったのでやめましたw
*追記:allWordpressPost内のcategories{name}からでもいけました!!w
~~categories.nameで取ろうとしていたのをcategories[0].nameに変えるとちゃんと取れるようになりました
consoleで引っ張ってきているデータをみると、categories.nameではなく、categories[0]の中にnameがあるのがわかります
なので書き換えてみましたw
const path = require(`path`)
const _ = require(`lodash`)
const createPaginatedPages = require('gatsby-paginate')
exports.createPages = async ({ graphql, actions, reporter }) => {
const { createPage } = actions
const BlogPostTemplate = path.resolve("./src/templates/BlogPost.js")
const PageTemplate = path.resolve("./src/templates/Page.js")
const CatTemplate = path.resolve("./src/templates/Categories.js")
const result = await graphql(`
{
allWordpressPost {
edges {
node {
id
title
date(formatString: "YYYY.MM.DD")
excerpt
slug
wordpress_id
categories {
name
}
featured_media {
localFile {
childImageSharp {
fluid(maxWidth: 1000) {
src
srcSet
aspectRatio
sizes
base64
}
}
}
}
}
}
}
allWordpressPage {
edges {
node {
slug
wordpress_id
}
}
}
}
`)
if (result.errors) {
reporter.panicOnBuild(`Error while running GraphQL query.`)
return
}
const BlogPosts = result.data.allWordpressPost.edges
BlogPosts.forEach(post => {
createPage({
path: `/${post.node.slug}`,
component: BlogPostTemplate,
context: {
id: post.node.wordpress_id,
},
})
})
const Pages = result.data.allWordpressPage.edges
Pages.forEach(page => {
createPage({
path: `/${page.node.slug}`,
component: PageTemplate,
context: {
id: page.node.wordpress_id,
},
})
})
createPaginatedPages({
edges: BlogPosts,
createPage: createPage,
pageTemplate: 'src/templates/Pagination.js',
pageLength: 5,
pathPrefix: 'posts',
})
const BlogCategories = result.data.allWordpressPost.edges
let cats = []
_.each(BlogCategories, edge => {
if (_.get(edge, "node.categories[0].name")) {
cats = cats.concat(edge.node.categories[0].name)
}
})
cats = _.uniq(cats)
cats.forEach(category => {
createPage({
path: `/categories/${_.kebabCase(category)}/`,
component: CatTemplate,
context: {
category: category,
},
})
})
}
これでもちゃんと表示されました!!
“uncategorized”もいけてます
gatsby buildコマンドをするとpublicディレクトリの中にcategoriesフォルダが生成されてその中に全カテゴリーが入っているのがわかるかと思います
これでカテゴリーページの作り方の基礎はわかったかと思います^ ^
ステップ5:全てのカテゴリーの一覧を表示させるカテゴリーインデックスページを作成
必要かどうかはさておき、categoriesにアクセスされた時に表示するカテゴリーの一覧ページを作ります
pagesディレクトリの中にcategories.jsを作るだけです
import React from "react"
import { graphql, Link } from "gatsby"
import Layout from "../components/layout"
import SEO from "../components/seo"
const CategoriesIndex = ({ data }) => (
<Layout>
<SEO title="Categories" keywords="カテゴリー一覧ページ" />
<ul>
{data.allWordpressCategory.edges.map(post => (
<li key={post.node.id}>
<Link to={`/categories/${post.node.slug}`} >
{post.node.name}
</Link>
</li>
))}
</ul>
</Layout>
)
export default CategoriesIndex
export const query = graphql`
query {
allWordpressCategory {
edges {
node {
id
slug
name
}
}
}
}
`
超シンプルですね
こんな感じでちゃんとカテゴリーが表示されているかと思います^ ^
Step6:それぞれの記事にカテゴリーを表示
いくつか例を挙げておきます
やっていることはqueryにcategories{name}を追加して、~~categories[0].nameで表示しているだけなのですんなり表示できるかと思います
import React from "react"
import { graphql, Link } from "gatsby"
import Img from "gatsby-image"
import Layout from "../components/layout"
import SEO from "../components/seo"
const IndexPage = ({ data }) => {
return(
<Layout>
<SEO title="Home" keywords={[`gatsby`, `test`, `sample`]} />
<ul>
{data.allWordpressPost.edges.map(post => (
<li key={post.node.id}>
<Link to={`/${post.node.slug}`} >
{post.node.featured_media && (
<div>
<Img
fluid={post.node.featured_media.localFile.childImageSharp.fluid}
alt={post.node.title}
/>
</div>
)}
<div>
<h3 dangerouslySetInnerHTML={{ __html: post.node.title }} />
<span>{post.node.date}</span>
<span>{post.node.categories[0].name}</span>
<div dangerouslySetInnerHTML={{ __html: post.node.excerpt }} />
</div>
</Link>
</li>
))}
</ul>
</Layout>
)
}
export default IndexPage
export const query = graphql`
query {
allWordpressPost(sort: {order: DESC, fields: date}) {
edges {
node {
id
title
excerpt
slug
date(formatString: "YYYY.MM.DD")
categories {
name
}
featured_media {
localFile {
childImageSharp {
fluid(maxWidth: 1000) {
...GatsbyImageSharpFluid
}
}
}
}
}
}
}
}
`
これでトップページの記事の日付の横にカテゴリー名が表示されるかと思います
わかりにくいかもですが、日付の横にカテゴリー名の”test”と”uncategorized”が表示されました
記事ページにも表示させてみます
import React from "react"
import { graphql } from "gatsby"
import Img from "gatsby-image"
import Layout from "../components/layout"
import SEO from "../components/seo"
const BlogPostTemplate = ({ data }) => (
<Layout>
<SEO
title={data.wordpressPost.title}
description={data.wordpressPost.excerpt}
/>
<h1>{data.wordpressPost.title}</h1>
<span>{data.wordpressPost.date}</span>
<span>{data.wordpressPost.categories[0].name}</span>
{data.wordpressPost.featured_media && (
<div>
<Img fluid={data.wordpressPost.featured_media.localFile.childImageSharp.fluid} />
</div>
)}
<div
dangerouslySetInnerHTML={{ __html: data.wordpressPost.content }}
/>
</Layout>
)
export default BlogPostTemplate
export const query = graphql`
query($id: Int!) {
wordpressPost(wordpress_id: { eq: $id }) {
title
content
excerpt
date(formatString: "YYYY.MM.DD")
categories {
name
slug
}
featured_media {
localFile {
childImageSharp {
fluid(maxWidth: 1000) {
...GatsbyImageSharpFluid
}
}
}
}
}
}
`
これでこんな感じに表示されたかと思います
簡単ですね^ ^
お疲れ様でした!
これでカテゴリーページ編は終わりです
データを引っ張ってくる方法がわかりさえすれば、Gatsbyは非常に便利ですし簡単ですよね^ ^
次回は記事ページの「breadcrumbs」を追加していきます^ ^
では〜〜
Share if you like
Recent Posts最新記事
- 2022.07.282023.01.01雑記
久しぶりの投稿、何を書いたらいいかわからない
- 2020.05.27写真
最近撮っているiPhoneの写真たち
- 2020.03.26写真
スペイン・バルセロナのトマティーナ祭りツアーの旅の記録【+スナップ写真】
- 2020.03.112020.03.14ライフスタイル
NotionとGoogleカレンダーでタスク管理してみたら便利だった話
- 2020.02.102020.06.13お知らせ
FUJIFILMのグループ展示で写真を出展します
- 2020.01.112020.01.12お知らせ
2019年の振り返りと2020年の抱負
Commentなんでも気軽にどうぞ^ ^