#1 Gatsby + WordPress REST APIでブログを作ろう【導入+基本構成編】
どうも、サウナ大好きケンタロウ(@kentaro_koga)です
この記事では「GatsbyとWordPress REST APIを使ってのブログの作り方」を解説していきます。
Gatsbyてなに?髪の毛に塗るの?
Gatsbyは静的サイトジェネレーターでreactベースで作られています。
graphqlが簡単に使えるのでWordPressやContentfulなどのCMSからデータを引っ張ってこれます。
最終的にGatsbyが静的ページ(HTML / CSS / JS)を生成してくれるので、それを好きなサーバーに置くだけで完成です
すでに生成された静的ページなので読み込みが早く、SPAで、Preloadingもしてくれるのでページ遷移も早いです。
色々特徴はありますが、今回はブログの作り方の紹介なので割愛します。
ではこれからステップバイステップで解説していきます。
- Mac
- gatsby-starter-defaultを使用しての解説
- nodeインストール済み(記事執筆時の僕の環境はv10.15.3です)
- Gatsby version: 2.15.14
では参ります
gatsbyの準備
gatsbyがまだインストールされていない場合は以下のコードをターミナルで打ちます
npm install -g gatsby-cli
ちゃんとインストールされているかは以下のコードで確認できます
gatsby --version
これでgatsbyコマンドが使えるようになりました
次にサイトを作りたいディレクトリを作って、そのディレクトリまでcdコマンドで移動してgatsbyコマンドでサイトを作ります
gatsby new プロジェクト名
*gatsby new プロジェクト名 スターターのgithubのurl
でお好みのスターターを使えます
スターターとは最初に生成されるテンプレみたいなもので、何も指定しないとgatsby-starter-defaultになります
cdで作成されたプロジェクトのディレクトリに移動します
cd プロジェクト名
gatsby developをすると開発環境が構築されます
gatsby develop
local:8000に行くとこんな感じに表示されていると思います
これでgatsbyの準備は完了です
gatsbyのプラグインを追加
WordPress REST APIからデータを引っ張ってくるにはgatsbyが提供するプラグイン「gatsby-source-wordpress」を入れます。
npm install gatsby-source-wordpress
package.jsonに「gatsby-source-wordpress」が追加されているかと思います。
gatsby-config.jsにも追加します
module.exports = {
siteMetadata: {
title: `Gatsby Default Starter`,
description: `Kick off your next, great Gatsby project with this default starter. This barebones starter ships with the main Gatsby configuration files you might need.`,
author: `@gatsbyjs`,
},
plugins: [
`gatsby-plugin-react-helmet`,
{
resolve: `gatsby-source-filesystem`,
options: {
name: `images`,
path: `${__dirname}/src/images`,
},
},
`gatsby-transformer-sharp`,
`gatsby-plugin-sharp`,
{
resolve: `gatsby-plugin-manifest`,
options: {
name: `gatsby-starter-default`,
short_name: `starter`,
start_url: `/`,
background_color: `#663399`,
theme_color: `#663399`,
display: `minimal-ui`,
icon: `src/images/gatsby-icon.png`, // This path is relative to the root of the site.
},
},
{
resolve: "gatsby-source-wordpress",
options: {
baseUrl: “WordPressがインストールされている場所”,
protocol: "https",
hostingWPCOM: false,
useACF: false,
includedRoutes: [
"**/categories",
"**/posts",
"**/pages",
"**/media",
"**/tags",
"**/taxonomies",
"**/users",
],
},
},
// this (optional) plugin enables Progressive Web App + Offline functionality
// To learn more, visit: https://gatsby.dev/offline
// `gatsby-plugin-offline`,
],
}
“gatsby-source-wordpress”のところしか追加してませんので、とりあえず他はノータッチで大丈夫です
- baseUrlにWordPressをインストールしている場所を指定します
- WordPress.comを使用する場合はhostingWPCOMをtrueにします
- Advanced Custom Fieldsを使いたい時はuseACFをtrueに変更します
とりあえずはWordPressから記事を引っ張ってこれるようにします
*今回は自分が持っている仮ドメインにWordPressをインストールしています
Local by Flywheelを使ってWordPressの環境を作って開発の練習をしてもいいかと思います
http://localhost:8000/___graphqlでちゃんとデータが取れているか確認できます。
- allWordpressPost:全投稿記事
- allWordpressPage:全固定ページ
再生ボタンを押すと取得できたデータが表示されます
記事ページを作る
記事ページのtemplateを作ります。
srcディレクトリの中にtemplateディレクトリを作ります。
templateディレクトリの中にBlogPost.jsを作ります。
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>
<Img fluid={data.wordpressPost.featured_media.localFile.childImageSharp.fluid} />
<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: "MMMM DD, YYYY")
featured_media {
localFile {
childImageSharp {
fluid(maxWidth: 1000) {
...GatsbyImageSharpFluid
}
}
}
}
}
}
`
graphqlでのデータの取り方はhttp://localhost:8000/___graphqlを見るとだいたいわかります。
このテンプレートにgraphqlでWordPressから引っ張ってきたデータが入り、記事のページが生成されていきます。
*gatsby-imageというプラグインを使用してfeatured_mediaから画像を引っ張ってきています
詳しくは(https://www.gatsbyjs.org/tutorial/wordpress-image-tutorial/)に記載してありますが、英語なので今度基本的な部分を紹介しようかと思います
「gatsby-transformer-sharp」「gatsby-plugin-sharp」「gatsby-image」というプラグインが必要になりますが、今回使用しているデフォルトのスターターに最初から入っているので、このままで動きます(gatsby-config.jsで入っているので確認できます)
gatsby-node.jsでページを生成する設定をする
pathパッケージを使うとより簡単にページの生成が行えるのでインストールします
npm install path
gatsby-node.jsの設定をします。
const path = require(`path`)
exports.createPages = async ({ graphql, actions, reporter }) => {
const { createPage } = actions
const BlogPostTemplate = path.resolve("./src/templates/BlogPost.js")
const result = await graphql(`
{
allWordpressPost {
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,
},
})
})
}
これで先ほど作ったBlogPostTemplateコンポーネントを使用して、記事が生成されます。
BlogPost.jsやBlogPostTemplateの名前が違っているとうまく生成されないので注意です。
ちなみに仮のWordPress環境ではこのように3つの記事を投稿しています。
ちゃんと記事が生成されているかは存在しないページに行くとわかります。
hello-world・test1・helloの3つの記事がちゃんと取れていますね/test1などに飛ぶと先ほど作ったBlogPost.jsの中のBlogPostTemplateコンポーネントを元にページが生成されているのがわかります。
次に固定ページを作ります
templateディレクトリの中にPage.jsを作ります。
import React from "react"
import { graphql } from "gatsby"
import Layout from "../components/layout.js"
import SEO from "../components/seo"
const PageTemplate = ({ data }) => (
<Layout>
<SEO
title={data.wordpressPage.title}
description={data.wordpressPage.excerpt}
/>
<h1>{data.wordpressPage.title}</h1>
<div dangerouslySetInnerHTML={{ __html: data.wordpressPage.content }} />
</Layout>
)
export default PageTemplate
export const query = graphql`
query($id: Int!) {
wordpressPage(wordpress_id: { eq: $id }) {
title
excerpt
content
}
}
`
BlogPost.jsみたいな感じでこれが固定ページのテンプレートになります。
次にgatsby-node.jsにpageを生成するコードを追加していきます。
/**
* Implement Gatsby's Node APIs in this file.
*
* See: https://www.gatsbyjs.org/docs/node-apis/
*/
// You can delete this file if you're not using it
const path = require(`path`)
// const { createFilePath } = require(`gatsby-source-filesystem`)
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 result = await graphql(`
{
allWordpressPost {
edges {
node {
slug
wordpress_id
}
}
}
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,
},
})
})
}
簡単ですね
先ほどのBlogPostでやったことと同じなのですぐにできます。
仮のWordPress環境ではこんな感じで「Sample」「test」の2つページが公開されています。
再び存在しないページに飛ぶと、sampleページとtestページが生成されているのがわかります。
/testに飛ぶと先ほど作ったPage.jsを元に固定ページが生成されているのがわかります。
トップページに記事一覧を表示する
pages/index.jsを編集していきます。
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 }) => (
<Layout>
<SEO title="Home" keywords={[`gatsby`, `test`, `sample`]} />
<ul>
{data.allWordpressPost.edges.map(post => (
<li key={post.node.id}>
<Link to={`/${post.node.slug}`} >
<Img
fluid={post.node.featured_media.localFile.childImageSharp.fluid}
alt={post.node.title}
/>
<div>
<h3 dangerouslySetInnerHTML={{ __html: post.node.title }} />
<span>{post.node.date}</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 {
title
excerpt
slug
date(formatString: "MMMM DD, YYYY")
featured_media {
localFile {
childImageSharp {
fluid(maxWidth: 1000) {
...GatsbyImageSharpFluid
}
}
}
}
}
}
}
}
`
これで記事の一覧が表示されるかと思います。
*WordPress側でアイキャッチを設定していないと画像が取得できないのでエラーが出ます。(条件分岐する必要あり)
条件分岐の例:
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 }) => (
<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>
<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: "MMMM DD, YYYY")
featured_media {
localFile {
childImageSharp {
fluid(maxWidth: 1000) {
...GatsbyImageSharpFluid
}
}
}
}
}
}
}
}
`
上のように&&を使って条件分岐できます
サイトのメタデータを編集
gatsby-config.jsにサイトの基本情報を書くところがあります。
module.exports = {
siteMetadata: {
title: `Gatsby Default Starter`,
description: `Kick off your next, great Gatsby project with this default starter. This barebones starter ships with the main Gatsby configuration files you might need.`,
author: `@gatsbyjs`,
}
}
これらの情報もWordPressで設定しちゃいましょう
graphqlでwordpressSiteMetadataのnameとdescriptionを引っ張ってきます。
components/の中のheader.jsを編集していきます。
ここでコンポーネント内でqueryを使うために作られたStaticQueryに書き換えます。
import { StaticQuery, graphql, Link } from "gatsby"
import React from "react"
const Header = () => (
<StaticQuery
query={graphql`
query {
wordpressSiteMetadata {
name
}
}
`}
render={data => (
<header>
<div>
<h1>
<Link to="/">
{data.wordpressSiteMetadata.name}
</Link>
</h1>
</div>
</header>
)}
/>
)
export default Header
ヘッダーにメニューを追加する
今現在、WordPress REST APIでのデフォルトではメニューは利用できません。
WordPressに「WP API Menus」というプラグインを入れるとWordPressのREST APIからmenuを引っ張ってこれるようになります。
管理画面のプラグインから検索しても見つかりませんので、上のリンク先からプラグインをダウンロードして直接インストールしてください。
*以下の記事によると、管理画面のプラグイン検索で見つかる「WP-REST-API V2 Menus」は良くないみたいです
Complete guide to WordPress menu sourcing in Gatsby
理由がわからなかったので、こっちでも試してみましたが、固定ページのスラッグがちゃんと取れなかったのと、urlがちょっとおかしかったのでとりあえず「WP API Menus」の方を使います。
WordPressの外観/メニューからメニューを作成する
今回はheaderに表示するのでこんな感じで「headerNav」という名前のメニューを作りました
gatsby-config.jsに2行追加します
{
resolve: "gatsby-source-wordpress",
options: {
baseUrl: "taroken.mixh.jp/wp/gatsby/",
protocol: "https",
hostingWPCOM: false,
useACF: false,
verboseOutput: false,
includedRoutes: [
"**/categories",
"**/posts",
"**/pages",
"**/media",
"**/tags",
"**/taxonomies",
"**/users",
"**/*/*/menus", // <== メニューのエンドポイントを追加
"**/*/*/menu-locations", // <== メニューのエンドポイントを追加
],
},
},
これでgatsby developをしてgraphqlを見てみるとメニューのデータが引っ張ってこれているのがわかります
wordpressWpApiMenusMenusItemsのitemsから固定ページのスラッグやタイトルが取得できます
*WP-REST-API V2 Menusだとこのスラッグ(object_slug)が出てきませんでした(2019/09/15時点)
あとはcomponentsの中のheader.jsで引っ張ってくるだけです
import { StaticQuery, graphql, Link } from "gatsby"
import React from "react"
const Header = () => (
<StaticQuery
query={graphql`
query {
wordpressSiteMetadata {
name
}
wordpressWpApiMenusMenusItems(name: { eq: "headerNav" }) {
items {
title
object_slug
}
}
}
`}
render={data => (
<header>
<div>
<h1>
<Link to="/">
{data.wordpressSiteMetadata.name}
</Link>
</h1>
<ul>
{data.wordpressWpApiMenusMenusItems.items.map(item => (
<li key={item.object_slug}>
<Link to={`/${item.object_slug}`}>
{item.title}
</Link>
</li>
))}
</ul>
</div>
</header>
)}
/>
)
export default Header
こんな感じでheaderNavに追加してある固定ページのタイトルとリンクが取れました
これでベースの構成が完成です!
お疲れ様です!
とりあえずgatsby / WordPress REST APIで「記事の一覧」「記事ページ」「固定ページ」「メニューの取得」までできましたね
今後は以下を実装+解説していきますのでお楽しみに!
- ページネーションの実装
- カテゴリーページの実装
- 記事のprevious / nextボタンの実装
- ダークテーマの簡単実装
- Tweenmaxでアニメーションさせる
- ページ遷移
スタイリングは全くしていないので見た目はキモイですが、gatsby + WordPress REST APIのサイト制作の第一歩が出せたかと思います^ ^
ではまた次回〜〜^ ^
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なんでも気軽にどうぞ^ ^