• 最終更新日:

【WordPressとGatsby】headのtitleやmeta情報をページごとに設定する手順

【WordPressとGatsby】headのtitleやmeta情報をページごとに設定する手順

今回はWordPressとGatsbyを連携したサイトを、ページごとにheadのtitleやmeta情報を設定する方法を紹介します。

説明する環境は以下です。

  • macOS Catalina v10.15.5
  • Visual Studio Code v1.57.0
  • node.js v16.13.1
  • react v17.0.1
  • gatsby v4.11.2
  • react-helmet-async v1.3.0
  • gatsby-plugin-react-helmet-async v1.2.1
この記事の目次

headのtitleやmeta情報をページごとに設定する手順

WordPressで設定した各ページのデータを取得して、それぞれのページごとにheadのtitleやmeta情報を設定します。

WordPressとGatsbyを連携する基本的な流れは以下の記事で説明しています。今回のディレクトリ構成も以下の記事に沿っています。

必要なパッケージをインストールする

以下の2つのパッケージをインストールします。
少し前まではreact-helmetが主流でしたが、React v16.3以降では警告が表示されるようになったため、最近ではreact-helmet-asyncが使われています。

npm i react-helmet-async gatsby-plugin-react-helmet-async

インストールできならgatsby-config.jsに追記します。

module.exports = {
  plugins: [
    {
      resolve: `gatsby-source-wordpress`,
      options: {
        url: `http://hogehoge.wp/graphql`,
      },
    },
    `gatsby-plugin-image`,
    `gatsby-plugin-sharp`,
    `gatsby-transformer-sharp`,
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        name: `images`,
        path: `${__dirname}/src/images/`,
      },
    },

    `gatsby-plugin-sass`,
    `gatsby-plugin-react-helmet-async`,
  ],
}

headの中に設定する内容について

headの中で設定する情報は以下を想定しています。
ページごとに変更する必要があるものはWordPressからデータを取得して切り替えます。

<html lang="ja">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <meta name="format-detection" content="telephone=no" />
<!-- ページのタイトルや説明文、canical -->
  <title>ページのタイトル</title>
  <meta name="description" content="ページの説明" />
  <link rel="canonical" href="http://hogeghoge.com" />	
<!-- OGP -->
  <meta property="og:type" content="article" />
  <meta property="og:title" content="ページのタイトル" />
  <meta property="og:description" content="ページの説明" />
  <meta property="og:url" content="http://hogeghoge.com" />
  <meta property="og:image" content="http://hogeghoge.com/images/img.jpg" />
  <meta property="og:site_name" content="サイトの名前" />
  <meta property="og:locale" content="ja_JP" />
  <meta property="fb:app_id" content="8888888888888" />
<!-- Twitter Card -->
  <meta name="twitter:card" content="summary_large_image" />
  <meta name="twitter:creator" content="twitterのハッシュタグ" />
  <meta name="twitter:site" content="twitterのハッシュタグ" />
</head>

WordPressからデータを取得して、headに設定する

まずはcomponentsディレクトリの中にseo.jsを作成します。ここで作るコンポーネントを各ページごとに読み込ませて必要なデータを取得し、ページごとにmeta情報を設定します。

細かい説明は後回して、先にすべてのコードを書いていきます。

seo.jsに書くコードは以下です。

import React from "react"
import { useStaticQuery, graphql } from "gatsby"
import { Helmet, HelmetProvider } from "react-helmet-async"

export const Seo = props => {
  const {
    pageTitle,
    pageExcerpt,
    pagePath,
    pageType,
    ogpImg,
    ogpImgW,
    ogpImgH,
  } = props
  const {
    wp: {
      generalSettings: { title, description },
    },
    site: {
      siteMetadata: {
        defaultTitle,
        defaultDescription,
        defaultSiteUrl,
        facebookID,
        twitter,
        defaultLang,
        defaultLocale,
      },
    },
    file: { publicURL },
  } = useStaticQuery(graphql`
    query SeoQuery {
      wp {
        generalSettings {
          title
          description
        }
      }
      site {
        siteMetadata {
          defaultTitle
          defaultDescription
          defaultSiteUrl
          twitter
          defaultLang
          defaultLocale
        }
      }
      file(name: { eq: "img-ogp" }) {
        publicURL
      }
    }
  `)
  /*-- langの設定 --*/
  const lang = defaultLang || `ja`
  /*-- タイトルの設定 --*/
  const siteName = title || defaultTitle
  const metaTitle = pageTitle ? pageTitle : siteName
  /*-- 説明文の設定 --*/
  const siteDescription = description || defaultDescription
  const metaDescription = pageExcerpt
    ? `${pageExcerpt.replace(/<("[^"]*"|'[^']*'|[^'">])*>/g, "").slice(0, 120)}`
    : siteDescription
  /*-- ページURLの設定 --*/
  const siteUrl = defaultSiteUrl
  const metaUrl = pagePath ? `${siteUrl}${pagePath}` : `${siteUrl}`
  /*-- サイトのtypeの設定 --*/
  const metaType = pageType ? pageType : `website`
  /*-- OGP画像の設定 --*/
  const defaultOgp = publicURL
  const metaOgpImg = ogpImg ? `${siteUrl}${ogpImg}` : `${siteUrl}${defaultOgp}`
  const metaOgpImgW = ogpImgW || `1200`
  const metaOgpImgH = ogpImgH || `630`

  return (
    <HelmetProvider>
      <Helmet>
        <html lang={lang} />
        {/* ページのタイトルや説明文、canical */}
        <title>{metaTitle}</title>
        <meta name="description" content={metaDescription} />
        <link rel="canonical" href={metaUrl} />
        {/* OGP */}
        <meta property="og:type" content={metaType} />
        <meta property="og:title" content={metaTitle} />
        <meta property="og:description" content={metaDescription} />
        <meta property="og:url" content={metaUrl} />
        <meta property="og:image" content={metaOgpImg} />
        <meta property="og:image:width" content={metaOgpImgW} />
        <meta property="og:image:height" content={metaOgpImgH} />
        <meta property="og:site_name" content={siteName} />
        <meta property="og:locale" content={defaultLocale} />
        <meta property="fb:app_id" content={facebookID} />
        {/* twitter */}
        <meta name="twitter:card" content="summary_large_image" />
        <meta name="twitter:creator" content={twitter} />
        <meta name="twitter:site" content={twitter} />
      </Helmet>
    </HelmetProvider>
  )
}

次にgatsby-config.jsに以下の2〜10行目を追記します。

module.exports = {
  siteMetadata: {
    defaultTitle: "Gatsby側で設定したタイトル",
    defaultDescription: "Gatsby側で設定した説明分",
    defaultSiteUrl: "http://localhost:8000",
    facebookID: "8888888888",
    twitter: "@sample555",
    defaultLang: `ja`,
    defaultLocale: `ja_JP`,
  },
  plugins: [
    {
      resolve: `gatsby-source-wordpress`,
      options: {
        url: `http://hogehoge.wp/graphql`,
      },
    },
    `gatsby-plugin-image`,
    `gatsby-plugin-sharp`,
    `gatsby-transformer-sharp`,
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        name: `images`,
        path: `${__dirname}/src/images/`,
      },
    },

    `gatsby-plugin-sass`,
    `gatsby-plugin-react-helmet-async`,
  ],
}

投稿ページからOGP画像が取得できなかった場合に表示させるデフォルトのOGP画像を準備して、imagesディレクトリの中に配置しておきます。

今回は必ずimg-ogp.jpgという名前にしておきましょう。

先ほど作成したSeoコンポーネントを各ページに読み込ませていきます。
例として投稿ページ用の{WpPost.uri}.jsに読み込ませてみます。

import React from "react"
import { graphql } from "gatsby"

import "../@wordpress/block-library/build-style/style.css"
import "../@wordpress/block-library/build-style/theme.css"

import "../styles/p-WpPost.scss"

import { Header } from "../components/header"
import { Seo } from "../components/seo"

const Post = ({ data }) => {
  const { title, content, excerpt, uri, featuredImage } = data.wpPost
  return (
    <>
      <Seo
        pageTitle={title}
        pageExcerpt={excerpt}
        pagePath={uri}
        pageType="article"
        ogpImg={featuredImage?.node.localFile.publicURL}
        ogpImgW={featuredImage?.node.mediaDetails.width}
        ogpImgH={featuredImage?.node.mediaDetails.height}
      />
      <Header />
      <main>
        <h1 className="p-WpPost-heading">{title}</h1>
        <div dangerouslySetInnerHTML={{ __html: content }} />
      </main>
    </>
  )
}

export const query = graphql`
  query ($id: String!) {
    wpPost(id: { eq: $id }) {
      title
      content
      excerpt
      uri
      featuredImage {
        node {
          localFile {
            publicURL
          }
          mediaDetails {
            width
            height
          }
        }
      }
    }
  }
`
export default Post

seoコンポーネントには以下のデータを渡しています。

  • title … 記事のタイトル
  • excerpt … 記事の抜粋
  • uri … 記事のパス
  • article … ページのタイプ
  • featuredImage?.node.localFile.publicURL … サムネイル画像までのパス
  • featuredImage?.node.mediaDetails.width … サムネイル画像のwidth
  • featuredImage?.node.mediaDetails.height … サムネイル画像のheight

featureImageに?がついているのは、サムネイルが設定されてない場合はエラーになってしまうため、設定されているときのみ値を取得できるようにしています。

実際に投稿ページにアクセスしてheadの中が設定できているか確認してみます。

正しく反映できているのがわかります。

コードの解説

seo.jsを通して今回のコードを説明していきます。

以下の部分ではpropsで受け取ったプロパティを分割代入を使って取り出しています。

export const Seo = props => {
  const {
    pageTitle,
    pageExcerpt,
    pagePath,
    pageType,
    ogpImg,
    ogpImgW,
    ogpImgH,
  } = props

このseo.jsにあるpropsの中身は各ページから受け取っています。
{WpPost.uri}.jsでは以下の部分です。

const Post = ({ data }) => {
  const { title, content, excerpt, uri, featuredImage } = data.wpPost
  return (
    <>
      <Seo
        pageTitle={title}
        pageExcerpt={excerpt}
        pagePath={uri}
        pageType="article"
        ogpImg={featuredImage?.node.localFile.publicURL}
        ogpImgW={featuredImage?.node.mediaDetails.width}
        ogpImgH={featuredImage?.node.mediaDetails.height}
      />

以下のプロパティには、GraphQLで受け取ったWordPressの値が入っています。

  • pageTitle
  • pageExcerpt
  • pagePath
  • pageType
  • ogpImg
  • ogpImgW
  • ogpImgH

WordPressの値は{WpPost.uri}.jsの以下の部分で取得しています。

export const query = graphql`
  query ($id: String!) {
    wpPost(id: { eq: $id }) {
      title
      content
      excerpt
      uri
      featuredImage {
        node {
          localFile {
            publicURL
          }
          mediaDetails {
            width
            height
          }
        }
      }
    }
  }
`

次にseo.jsにある以下の部分について説明します。
GraphQLで受け取ったデータを(17〜37行目)、それぞれ分割代入で使える状態にしてあります(2〜16行目)。

const {
    wp: {
      generalSettings: { title, description },
    },
    site: {
      siteMetadata: {
        defaultTitle,
        defaultDescription,
        defaultSiteUrl,
        facebookID,
        twitter,
        defaultLang,
        defaultLocale,
      },
    },
    file: { publicURL },
  } = useStaticQuery(graphql`
    query SeoQuery {
      wp {
        generalSettings {
          title
          description
        }
      }
      site {
        siteMetadata {
          defaultTitle
          defaultDescription
          defaultSiteUrl
          twitter
          defaultLang
          defaultLocale
        }
      }
      file(name: { eq: "img-ogp" }) {
        publicURL
      }
}

wpのgeneralSettingsではWordPressで設定しているサイトのタイトルと説明文が取得できます。

wp {
  generalSettings {
    title
    description
  }
}

そして以下の部分ではgatsby-confing.jsに書き加えた内容をGraphQLを通じて取得しています。

site {
  siteMetadata {
  defaultTitle
  defaultDescription
  defaultSiteUrl
  twitter
  defaultLang
  defaultLocale
  }
}

gatsby-confing.jsに書き加えた内容とは以下の部分です。

module.exports = {
  siteMetadata: {
    defaultTitle: "Gatsby側で設定したタイトル",
    defaultDescription: "Gatsby側で設定した説明分",
    defaultSiteUrl: "http://localhost:8000",
    facebookID: "8888888888",
    twitter: "@sample555",
    defaultLang: `ja`,
    defaultLocale: `ja_JP`,
  },

実際にGraphQLで書き加えた内容が反映されているか見てみます。
以下のように反映されているのがわかります。

デフォルトのOGP画像のパスについては以下で取得しています。
このOGP画像は「img-ogp.jpg」としてimagesディレクトリに配置しました。そこでnameの部分で「img-ogp」という名前でフィルターをかけて画像のパスを取得しています。

file(name: { eq: "img-ogp" }) {
   publicURL
}

以下ではGraphQLから取得したデータをもとに、meta情報に設定する内容を変数にまとめています。投稿ページにデータがあればそのデータを使い、無ければサイトの基本情報を使うイメージです。

/*-- langの設定 --*/
const lang = defaultLang || `ja`
/*-- タイトルの設定 --*/
const siteName = title || defaultTitle
const metaTitle = pageTitle ? pageTitle : siteName
/*-- 説明文の設定 --*/
const siteDescription = description || defaultDescription
const metaDescription = pageExcerpt
    ? `${pageExcerpt.replace(/<("[^"]*"|'[^']*'|[^'">])*>/g, "").slice(0, 120)}`
    : siteDescription
/*-- ページURLの設定 --*/
const siteUrl = defaultSiteUrl
const metaUrl = pagePath ? `${siteUrl}${pagePath}` : `${siteUrl}`
/*-- サイトのtypeの設定 --*/
const metaType = pageType ? pageType : `website`
/*-- OGP画像の設定 --*/
const defaultOgp = publicURL
const metaOgpImg = ogpImg ? `${siteUrl}${ogpImg}` : `${siteUrl}${defaultOgp}`
const metaOgpImgW = ogpImgW || `1200`
const metaOgpImgH = ogpImgH || `630`

この変数にまとめたものを以下の部分で出力しています。

return (
    <HelmetProvider>
      <Helmet>
        <html lang={lang} />
        {/* ページのタイトルや説明文、canical */}
        <title>{metaTitle}</title>
        <meta name="description" content={metaDescription} />
        <link rel="canonical" href={metaUrl} />
        {/* OGP */}
        <meta property="og:type" content={metaType} />
        <meta property="og:title" content={metaTitle} />
        <meta property="og:description" content={metaDescription} />
        <meta property="og:url" content={metaUrl} />
        <meta property="og:image" content={metaOgpImg} />
        <meta property="og:image:width" content={metaOgpImgW} />
        <meta property="og:image:height" content={metaOgpImgH} />
        <meta property="og:site_name" content={siteName} />
        <meta property="og:locale" content={defaultLocale} />
        <meta property="fb:app_id" content={facebookID} />
        {/* twitter */}
        <meta name="twitter:card" content="summary_large_image" />
        <meta name="twitter:creator" content={twitter} />
        <meta name="twitter:site" content={twitter} />
      </Helmet>
    </HelmetProvider>
  )

headの中身を変更して出力するためにreact-helmet-asyncを使用しています。
react-helmet-asyncの使い方については以下の記事で説明したので参考にしてみてください。

トップページでheadの設定をする場合は?

seo.js側でheadの中のデフォルトの指定を書いているため、特別に変更する理由が無ければトップページはSeoコンポーネントを読み込むだけになります。

import React from "react"
import { graphql } from "gatsby"
import { GatsbyImage, StaticImage } from "gatsby-plugin-image"

import { Seo } from "../components/seo"

import "../styles/p-Home.scss"

const Home = ({ data }) => {
  return (
    <>
      <Seo />
      <div className="p-Home-main">
      {/* これ以降は省略 */}

トップページのheadを確認すると以下のようにseo.jsに書かれている指定が設定できているのがわかります。

ページネーションがある場合は?

ブログのようにトップページに記事一覧があって、ページネーションをつけて1ページ目と2ページ目のURLが変わる場合は以下のようにlocationを使ってpathnameを設定すれば良いでしょう。

import React from "react"
import { graphql } from "gatsby"
import { GatsbyImage, StaticImage } from "gatsby-plugin-image"

import { Seo } from "../components/seo"

import "../styles/p-Home.scss"

const Home = ({ data, location }) => {
  return (
    <>
      <Seo pagePath={location.pathname} />
      <div className="p-Home-main">
      {/* これ以降は省略 */}

まとめ

今回はWordPressとGatsbyを使ったサイトでheadのtitleやmeta情報をページごとに設定する手順について説明しました。

headの中の情報はSEO的にもとても重要になってくるので細かく設定することをオススメします。