React HelmetでOGP対応

Gatsby + Netlify CMS StarterでOGP対応する方法。

featuedimage

前回の記事をツイッターでシェアした時に ogp 対応してないことに気づいたので、早速対応しました。

GraphQL にろくに触れたことがなく少し手間取ったのでシェアします。


まずは画像パスの確認

http://localhost:8000/___graphqlにアクセスし、どこから画像パスが取れるか確認してみました。


graphql


どうやら frontmatter.featuredimage.relativePath で取れるっぽいのでそれをblog-post.jsの pageQuery に記述します。

blog-post.js
export const pageQuery = graphql`
  query BlogPostByID($id: String!) {
    markdownRemark(id: { eq: $id }) {
      id
      html
      frontmatter {
        date(formatString: "MMMM DD, YYYY")
        title
        description
        tags
        featuredimage {
          relativePath
        }
      }
    }
  }
`;

これで BlogPostTemplate 内部でpost.frontmatter.featuredimage.relativePathで画像パスにアクセスできるようになりました。


Helmet のメタタグに諸々の OGP 情報を追加

blog-post.js->BlogPostコンポーネント-> Helmet にメタタグを記述します。

必要な OGP 情報は title, description, image なのでそれを meta タグに追加します。

画像パスは長くなってしまったので以下

const image = `https://yikeda.dev/img/${post.frontmatter.featuredimage.relativePath}`;

を定義し記述量が短くなるようにしました。


blog-post.js
const BlogPost = ({ data }) => {
  const { markdownRemark: post } = data;
  const image = `https://yikeda.dev/img/${post.frontmatter.featuredimage.relativePath}`;

  return (
    <Layout>
      <BlogPostTemplate
        content={post.html}
        contentComponent={HTMLContent}
        description={post.frontmatter.description}
        image={image}
        helmet={
          <Helmet
            titleTemplate='%s | Blog'
            title={post.frontmatter.title}
            meta={[
              { name: 'description', content: post.frontmatter.description },
              {
                property: 'og:title',
                content: post.frontmatter.title
              },
              {
                property: 'og:description',
                content: post.frontmatter.description
              },
              {
                property: 'og:image',
                content: image
              }
            ]}
          />
        }
        tags={post.frontmatter.tags}
        title={post.frontmatter.title}
      />
    </Layout>
  );
};

image を定義したのは OG メタタグだけでなく、BlogPost コンポーネントの Props に渡す際にも使うのでこのようにしました。


また、今まで全ての記事でアイキャッチイメージを使っているにも関わらずマークダウンの img タグを書いていたので、そこも修正。

BlogPostTemplateコンポーネントの Props で featuredimage を受け取り、全ての記事のトップでその記事の featuredimage を表示するように変更しました。

具体的には、p タグの description の下に img タグを追加しアイキャッチ画像を表示させるように変更。

blog-post.js
export const BlogPostTemplate = ({
  content,
  contentComponent,
  description,
  tags,
  title,
  featuredimage,
  helmet
}) => {
  const PostContent = contentComponent || Content;

  return (
    <section className='section'>
      {helmet || ''}
      <div className='container content'>
        <div className='columns'>
          <div className='column is-10 is-offset-1'>
            <h1 className='title is-size-2 has-text-weight-bold is-bold-light heading-primary'>
              {title}
            </h1>
            <p>{description}</p>
            <p>
              <img src={featuredimage} alt='featuedimage' />
            </p>
            <PostContent content={content} />
            {tags && tags.length ? (
              <div style={{ marginTop: `4rem` }}>
                <h4>Tags</h4>
                <ul className='taglist'>
                  {tags.map(tag => (
                    <li key={tag + `tag`}>
                      <Link to={`/tags/${kebabCase(tag)}/`}>{tag}</Link>
                    </li>
                  ))}
                </ul>
              </div>
            ) : null}
          </div>
        </div>
      </div>
    </section>
  );
};

これで Twitter や Slack などに貼り付けた時にいい感じに OGP 情報が表示されるようになりました。


ogp-example


めでたしめでたし。