Craft CMS と Gatsby をつかった静的ファイル生成:詳細ページの生成 #craftcms

これは Craft CMS Advent Calendar 2020 4日目の記事です。

Craft CMS の GraphQL と Gatsby をつかって詳細ページを生成してみる。

リンク元の index.js の調整

一覧ページ用に作った index.js をちょっと修正して、 article/{slug} にリンクされるように調整する。

src/pages/index.js

import React from "react"
import { useStaticQuery, graphql } from "gatsby"
import { Link } from "gatsby"

const RecentEntriesQuery = graphql`
  {
    allCraftTestTestEntry(limit: 10) {
      nodes {
        id
        title
        url
        slug
      }
    }
  }
`;

export default function Home() {
  const {allCraftTestTestEntry: {nodes}} = useStaticQuery(RecentEntriesQuery);
  return (
    <div>
        <h1>Hello world!</h1>
        <div className="flex flex-wrap -mx-4">
            {nodes.map(({id, title,url,slug}) => (
                <p><Link to={`/article/${slug}`}>{title}</Link></p>
            ))}
        </div>
    </div>
  )
}

Link コンポーネントのドキュメントはこちら。

Gatsby Link API | Gatsby
https://www.gatsbyjs.com/docs/...

クエリに slug を追加して、一覧へのリンクを Link コンポーネントを使うようにする。

gatsby-node.js を定義してページを生成

GraphQL のクエリで受け取った内容を元に gatsby-node.js を定義してページを生成する。

The gatsby-node.js API file | Gatsby
https://www.gatsbyjs.com/docs/...

gatsby-node.js

const path = require('path');

exports.createPages = ({ graphql, actions }) => {
    const {createPage} = actions
    return graphql(`
    {
        allCraftTestTestEntry(limit: 10) {
          nodes {
            id
            title
            url
            slug
            ... on Craft_test_test_Entry{
              testredactor
            }
          }
        }
    }
  `).then(result => {
        result.data.allCraftTestTestEntry.nodes.forEach(node => {
            createPage({
                path: `article/${node.slug}`,
                component: path.resolve(`./src/templates/post.js`),
                context: {
                    pagedata: node
                },
            })
        })
    })
}

この処理の中でトップページとかも生成してしまえばいいような気がする(ということに今更)
これはあとで試してみよう。

ひとまずトップページにあわせる感じで、10件取得してその10件のページを出力するようにする。
出力するパスは article/${node.slug} と指定する。
その際のテンプレート(コンポーネント)のファイルを src/templates/post.js に用意する。

src/templates/post.js

import React from "react"

const PostPage = ({ pageContext }) => {
    const { pagedata } = pageContext
    return (
        <div>
            <div className="content">
                <h1>{pagedata.title}</h1>
                <p>slug :  {pagedata.slug}</p>
                <p>id :  {pagedata.id}</p>
                <p>redactor</p>
                <pre>{pagedata.testredactor}</pre>
            </div>
        </div>
    );
};

export default PostPage;

gatsby-node.js の context の pagedata に渡した内容が pageContext で受け取れる。

Creating and Modifying Pages | Gatsby
https://www.gatsbyjs.com/docs/...

受け取った内容を pagedata.title とかで取り出す。
詳細ページの想定でエディタの内容に相当する pagedata.testredactor の内容も表示するようにする。

HTMLをそのまま使えないのでこれはあとで処理が必要。
画像のパスをどうするか?とかもあるにはあるが、画像自体はCMS側を参照するという前提にしておく。

これでひとまず詳細ページ用のデータは雑にとれた。

トップページ

20201203 1829

リンク先の詳細ページ

20201203 1831

見てくれは最後に頑張ってやろう(やらないパターンになりそう)。