はじめに
今回やること
Gatsby.jsで作成中のブログに、内容を表すタグ(カテゴリ)を設定できるようにします。 ※タグとカテゴリは、厳密には意味が異なるようなのでここではタグに統一します。
タグ一覧ページを作成します。
また、
- ナビゲーションバーからタグごとの記事ページにリンク追加
も実施します。
※前回の記事では、タグごとに「そのタグがついている記事一覧」を表示できるようにしました。
機能の前提
- 1つの記事に対し、複数のタグをつけることを可能とします。
- タグは記事内の
frontmatter
で配列として設定することにします。 - タグは日本語も可能としますが、「そのタグがついている記事一覧」のURLは半角英数字とします。
- 「そのタグがついている記事一覧」のURLは、タグの内容と1:1で紐づけ、JSONで管理します。
- タグ自体の一覧を表示できるようにします。
タグ一覧ページを作成する
今回は、自動でページを作成する必要はありません。
固定ページとしてタグ一覧ページを作成します。
import React from "react"
import _ from "lodash"
import { useStaticQuery, graphql } from "gatsby"
import Layout from "../components/layout"
import Seo from "../components/seo"
import { ListItem, UnorderedList } from "@chakra-ui/react"
import { Link } from "gatsby"
import Search from "../components/organisms/search"
import Profile from "../components/organisms/profile"
import MainHeaderBar from "../components/atom/main-header-bar"
import { AllTagDefinition } from "../params/all-tag-difinition"
import { Helmet } from "react-helmet"
const Tags = ({ location }) => {
const data = useStaticQuery(
graphql`
{
site {
siteMetadata {
title
}
}
tagsGroup: allMdx {
group(field: frontmatter___tags) {
fieldValue
totalCount
}
}
}
`
)
const siteTitle = data.site.siteMetadata?.title || `Title`
const tags = data.tagsGroup.group
return (
<Layout
location={location}
title={siteTitle}
>
<Seo title="タグ一覧"></Seo>
<Helmet>
<meta name="robots" content="noindex" />
</Helmet>
<MainHeaderBar as="h1">タグ一覧</MainHeaderBar>
<UnorderedList listStyleType="none">
{tags.map((tag) => {
// タグの英名を取得する(gatsby-node.jsと同じ処理である必要があります)
const tagDefinition = AllTagDefinition.filter(
(item) => item.name === tag.fieldValue
)
const tagSlug =
tagDefinition.length === 0 ? tag.fieldValue : tagDefinition[0].slug // 定義に無かった場合(filterした結果が空配列)は日本語のままslugにする。
return (
<Link to={`/tags/${_.kebabCase(tagSlug)}`}>
<ListItem
p={1}
borderBottom="1px"
borderColor="orange.100"
mb={1}
>{`${tag.fieldValue} (${tag.totalCount})`}</ListItem>
</Link>
)
})}
</UnorderedList>
</Layout>
)
}
export default Tags
GraphQLでタグ一覧を取得する
前回の記事と同じようにタグ一覧を取得します。
固定ページなので、ページクエリではなくuseStaticQuery
を利用可能です。
import { useStaticQuery, graphql } from "gatsby"
const data = useStaticQuery(
graphql`
{
site {
siteMetadata {
title
}
}
tagsGroup: allMdx {
group(field: frontmatter___tags) {
fieldValue
totalCount
}
}
}
`
)
const tags = data.tagsGroup.group
noindex設定をする
諸説あると思いますが、タグ一覧ページはGoogleにインデックスされても仕方ないのでnoindex
設定をしておきます。
import { Helmet } from "react-helmet"
<Helmet>
<meta name="robots" content="noindex" />
</Helmet>
タグ一覧をリスト表示する
タグ一覧をリスト表示します。
<Link>
の先には、タグごとの記事一覧ページへのリンクを貼ります。
このURL(tagSlug
)導出ロジックは前回と同じにしておく必要があります。
import { Link } from "gatsby"
import { AllTagDefinition } from "../params/all-tag-difinition"
{tags.map((tag) => {
// タグの英名を取得する(gatsby-node.jsと同じ処理である必要があります)
const tagDefinition = AllTagDefinition.filter(
(item) => item.name === tag.fieldValue
)
const tagSlug =
tagDefinition.length === 0 ? tag.fieldValue : tagDefinition[0].slug // 定義に無かった場合(filterした結果が空配列)は日本語のままslugにする。
return (
<Link to={`/tags/${_.kebabCase(tagSlug)}`}>
<ListItem
>{`${tag.fieldValue} (${tag.totalCount})`}</ListItem>
</Link>
)
})}
ナビゲーションバーからタグごとの記事ページにリンク追加
ナビゲーションバーは以下のようなコンポーネントで定義しています。
※長くなるので見た目の装飾部分は省略します。
import * as React from "react"
import { Link } from "gatsby"
import { Box, HStack, Text } from "@chakra-ui/react"
import NavBarTags from "../../params/nav-bar-tags"
const Nav = () => {
const navItem = [
...NavBarTags,
{ name: "このブログについて", slug: "about" },
]
return (
<Box>
<Box maxW="1201px" mx="auto">
{/* ↑幅は、layout.jsの外側のフレームの大きさと合わせている。 */}
<HStack>
{navItem.map((item, index) => (
<Link to={`/${item.slug}`}>
<Box>
<Text>
{item.name}
</Text>
</Box>
</Link>
))}
</HStack>
</Box>
</Box>
)
}
export default Nav
ナビゲーションバーに設定する値の設定
まず、navItem
で、ナビゲーションバーに表示するアイテムの 名前 と リンク先URL を設定します。
import NavBarTags from "../../params/nav-bar-tags"
const navItem = [
{ name: "Home", slug: "" },
...NavBarTags,
{ name: "このブログについて", slug: "about" },
]
ここで、NavBarTags
は別ファイルで管理しています。
注意点として2点あります。
all-tag-difinition
で管理している、タグに対する記事一覧ページのURL設定と合わせる必要があります。- ただし、
slug
はtags/slug
とする必要があります。たとえば「プログラミング」のslug
は、all-tag-difinition
では
{
name: "プログラミング",
slug: "programming",
},
と設定しましたが、nav-bar-tags
では
{
name: "プログラミング",
slug: "tags/programming",
},
とする必要があります。
単純に、<Link to=>
に設定するURLを記事一覧ページと合わせる都合でこのようになってしまいました。
// 必ずall-tag-difinition.jsから抜粋すること。
// さらに、slugには `tags/`を追加すること。
const NavBarTags = [
{
name: "プログラミング",
slug: "tags/programming",
},
{
name: "息抜き",
slug: "tags/break-life",
},
]
export default NavBarTags
map
関数でリストを描画する
取得したnavItem
を横に並べていきます。
ここで<Link to=>
の中身は{`/${item.slug}`}
とします。
item.slug
の前に/
を入れているのがポイントです。
{navItem.map((item, index) => (
<Link to={`/${item.slug}`}>
<Box>
<Text>
{item.name}
</Text>
</Box>
</Link>
))}
## ハマったポイント
各リンクのリンク先URLは注意が必要です。
<Link>
コンポーネントは、/
があるか、無いかで絶対パスか相対パスかが決まります。
例えば<Link to="tags">
とした場合は、今いるページに対してtags
を追加したURLに飛んでしまいます。
そのため/
を忘れると、ナビゲーションバーをクリックしたページによって行き先が変わってしまうことになります。
このように設定できるよう、各ページのリンク先URLを設定しました。
まとめ
Gatsby.jsのブログに対し、タグを設定し、タグ一覧ページを作成することができました。