How to fetch keywords from Gatsby MDX frontmatter for SEO component?

Viewed 349

Update: so this code worked for me. Notice that there's only quotes around the first and last letter of the array. My original choices had quotes around each word, so that's why gatsby didn't pick them up.

Here is the correct line of code that works

 keywords: ["website, tutorial, web design"]

Original question

So I have a blog post with frontmatter and I'm trying to add keywords to my blog post so I can pass that into my SEO component. However, I don't know the proper way to add the keywords because I keep getting errors in my terminal

So here's my example frontmatter

      ---
      keywords: ["website", "tutorial", "web design"]
      description: "Learn how to build a site."
      ---

I've also tried to copy the same style from my gatsby config file

      ---
      keywords: "website, tutorial, web design"
      description: "Learn how to build a site."
      ---

Yet it still won't work for me.

My description works fine for my SEO component, but I don't know how to pass in the keywords from my mdx blog frontmatter

        const description = mdx.frontmatter.description
        const keywords = mdx.frontmatter.keywords

        return (
          <Layout>
            <SEO
              title={post.frontmatter.title}
              description={description}
              keywords={keywords}
            />

I know the keywords work if I just say keywords="test keyword" and I pass that into my SEO component, it shows in my website, but I don't know how to map through my keywords from the MDX file to show up in my site

Here is my SEO Component

      import React from "react"
      import PropTypes from "prop-types"
      import { Helmet } from "react-helmet"
      import { useStaticQuery, graphql } from "gatsby"

      function SEO({ description, title, keywords, siteUrl, lang, meta }) {
        const { site } = useStaticQuery(
          graphql`
            query {
              site {
                siteMetadata {
                  description
                  keywords
                  title
                  siteUrl
                }
              }
            }
          `
        )

        const metaDescription = description || site.siteMetadata.description
        const defaultTitle = site.siteMetadata.title
        const metaUrl = siteUrl || site.siteMetadata.siteUrl
        const metaKeywords = keywords || site.siteMetadata.keywords

        return (
          <Helmet
            htmlAttributes={{
              lang,
            }}
            title={title}
            titleTemplate={defaultTitle ? `%s | ${defaultTitle}` : null}
            meta={[
              {
                property: `og:title`,
                content: title,
              },
              {
                property: `og:siteurl`,
                content: metaUrl,
              },
              {
                name: `keywords`,
                content: metaKeywords,
              },
              {
                property: `og:description`,
                content: metaDescription,
              },
              {
                property: `og:type`,
                content: `website`,
              },
            ].concat(meta)}
          />
        )
      }

      SEO.defaultProps = {
        lang: `en`,
        meta: [],
        description: ``,
      }

      SEO.propTypes = {
        description: PropTypes.string,
        lang: PropTypes.string,
        meta: PropTypes.arrayOf(PropTypes.object),
        title: PropTypes.string.isRequired,
      }

      export default SEO

Then in my blogPost.js from my template folder code

        const Template = ({ data }) => {
          const post = data.mdx
          const { mdx } = data
          const alt = mdx.frontmatter.alt
          const title = mdx.frontmatter.title
          const date = mdx.frontmatter.date
          const author = mdx.frontmatter.author
          const description = mdx.frontmatter.description
          const keywords = mdx.frontmatter.keywords

          return (
            <Layout>
              <SEO title={post.frontmatter.title} description={description} keywords={keywords} />

Then frontmatter from mdx file is same as above

1 Answers

You must adapt your SEO component to receive keywords. It should look like:

import React from "react"
import PropTypes from "prop-types"
import { Helmet } from "react-helmet"
import { useStaticQuery, graphql } from "gatsby"

function SEO({ description, lang, meta, image: metaImage, title, keywords }) {
  const { site } = useStaticQuery(
    graphql`
      query {
        site {
          siteMetadata {
            title
            description
            author
            keywords
            siteUrl
          }
        }
      }
    `
  )
  const metaDescription = description || site.siteMetadata.description
  const image =
    metaImage && metaImage.src
      ? `${site.siteMetadata.siteUrl}${metaImage.src}`
      : null

  const keywords= keywords || site.siteMetadata.keywords // here you get your props or your metadata

  return (
    <Helmet
      htmlAttributes={{
        lang,
      }}
      title={title}
      titleTemplate={`%s | ${site.siteMetadata.title}`}
      meta={[
        {
          name: `description`,
          content: metaDescription,
        },
        {
          name: "keywords",
          content: keywords.join(","),
        },
        {
          property: `og:title`,
          content: title,
        },
        {
          property: `og:description`,
          content: metaDescription,
        },
        {
          property: `og:type`,
          content: `website`,
        },
        {
          name: `twitter:creator`,
          content: site.siteMetadata.author,
        },
        {
          name: `twitter:title`,
          content: title,
        },
        {
          name: `twitter:description`,
          content: metaDescription,
        },
      ]
        .concat(
          metaImage
            ? [
                {
                  property: "og:image",
                  content: image,
                },
                {
                  property: "og:image:width",
                  content: metaImage.width,
                },
                {
                  property: "og:image:height",
                  content: metaImage.height,
                },
                {
                  name: "twitter:card",
                  content: "summary_large_image",
                },
              ]
            : [
                {
                  name: "twitter:card",
                  content: "summary",
                },
              ]
        )
        .concat(meta)}
    />
  )
}

Besides the dummy content, get the following statement:

  const keywords= keywords || site.siteMetadata.keywords 

It will get your props keywords or your siteMetadata. Plus:

    {
      name: "keywords",
      content: keywords.join(","),
    },

So, your data should look like the first approach you've tried:

  ---
  keywords: ["website, tutorial, web design"]
  description: "Learn how to build a site."
  ---
Related