published on : 2019.11.19modified on : 2019.11.22Web制作

#5 Gatsby + WordPress REST APIでブログを作ろう【関連記事編】

#4ではパンくずのプラグインを紹介しました

次は記事ページに関連記事を表示させてみましょう

    実装するもの
  • 同じカテゴリーが1つ以上含まれる関連記事を5つまで表示する

では参ります

gatsby-node.jsの編集

gatsby-node.jsで関連記事を表示するための設定をしていきます

コメントで解説しています

gatsby-node.js
// sortByDateAscending
  const sortByDateAscending = (a, b) => {
    const aPubDate = (new Date(a.publishedOn)).getTime()
    const bPubDate = (new Date(b.publishedOn)).getTime()

    if(aPubDate > bPubDate) {
      return 1
    }
    if(aPubDate < bPubDate) {
      return -1
    }
    return 0
  }

// Related Posts
  const getRelatedPosts = (currentPost, posts) => {
    const MINIMUN_CATEGORIES_IN_COMMON = 1 // いくつカテゴリーが共通すれば関連記事として表示するか

    // 1つでもカテゴリが共通する
    const hasAtLeastOneCategoryInCommon = ({ node }) => {
      // 今表示されている記事はfalse
      if(currentPost.id === node.id) {
        return false
      }
      // _.intersectionByでカテゴリが共通する記事を取る(今表示されている投稿と、全記事のカテゴリの中で共通のもの全て取る)
      const commonCategories = _.intersectionBy(currentPost.categories, node.categories, (categories)=> categories.name)
      // 共通カテゴリが1つ以上のものを返す
      return commonCategories.length >= MINIMUN_CATEGORIES_IN_COMMON
    }
    // postsの中から1つでもカテゴリが共通するものをフィルターにかける
    const filteredResults = posts.filter(hasAtLeastOneCategoryInCommon)

    // 共通カテゴリが5つ以上だったら、Ascendingで並べた配列の0番目から5番目までのみ返す
    if(filteredResults.length > 5) {
      return filteredResults.sort(sortByDateAscending).slice(0, 5)
    }
    // 5つ以下の場合はそのままフィルターにかけたものを返す
    return filteredResults
  }

  const BlogPosts = result.data.allWordpressPost.edges
  BlogPosts.forEach(post => {
    createPage({
      path: `/${post.node.slug}`,
      component: BlogPostTemplate,
      context: {
        id: post.node.wordpress_id,
        // BlogPostsにデータを渡す
        relatedPosts: getRelatedPosts(post.node, result.data.allWordpressPost.edges),
      },
    })
  })

参考動画はこちら

*動画は英語でContentfulを使って実装しているので、そのままやってもうまくいきませんので注意してください

BlogPosts.jsを編集

pageContextで渡ってきたデータを取得できます

BlogPosts.js
import React from "react"
import { graphql } from "gatsby"
import Img from "gatsby-image"
import Layout from "../components/layout"
import SEO from "../components/seo"
import RelatedPosts from "../components/relatedPosts"

const BlogPostTemplate = ({ location, data, pageContext }) => {
  const { relatedPosts } = pageContext
  return (
    <Layout location={location} crumbLabel={data.wordpressPost.title}>
      <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 }}
      />

      {relatedPosts.length && <RelatedPosts posts={relatedPosts} />}
    </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
            }
          }
        }
      }
    }
  }
`

参考にした動画ではpathContextを使用していますが、非推奨になっているのでpageContextを使いましょう

関連記事が”あれば”RelatedPostsコンポーネントを表示するように条件分岐しています

relatedPosts.jsを作る

components内にrelatedPosts.jsを作りRelatedPostsコンポーネントを作ります

relatedPosts.js
import { Link } from "gatsby"
import React from "react"
import Img from "gatsby-image"

const RelatedPosts = ({ posts }) => (
  <div className="yo">
    <h2>Related Posts</h2>
    <ul>
    {posts.map(({node}) =>
      <li key={node.id}>
        <Link to={`/${node.slug}/`}>
          {node.featured_media &&
            <Img fluid={node.featured_media.localFile.childImageSharp.fluid} />
          }
          <span>{node.date}</span>
          <span>{node.categories[0].name}</span>
          <h4>{node.title}</h4>
        </Link>
      </li>
    )}
    </ul>
  </div>
)

export default RelatedPosts

単純に渡ってきたpostsを使いmapしているだけなので簡単ですね^ ^

gatsby developをしてちゃんと表示されているか確認します

わかりにくいかもですが、ちゃんと表示されています

他のカテゴリに行くと、、、

ちゃんと表示されました^ ^

gatsby-node.jsの設定が難しいかもしれませんが、何度か見直して理解すればオッケーです

ただ、この実装方法の場合、全記事から共通のカテゴリがないか見るのでちょっとコストがかかりすぎていますね

メディアサイトとか記事数がめちゃくちゃある場合は良くないかもしれません。。。

もっと良い実装方法をご存知の方は是非教えてくださいーー!m(_ _)m

では次は「Netlifyにデプロイ」です

お楽しみにーー^ ^

Share if you like

Commentなんでも気軽にどうぞ^ ^

Author
Web Designer

Kentaro Koga

福岡を拠点のクリエイターチーム「Fump」として活動をしています。

写真や動画の撮影やモノ作りが好きで、趣味は旅・カメラ・テニス・筋トレ・サウナ・レザークラフトです。

twitterアイコンinstagramアイコンfacebookアイコン