简体   繁体   English

带有 GatsbyJS 的 JSON-LD 架构用于丰富的片段

[英]JSON-LD schema with GatsbyJS for rich snippets

I have a basic blog setup with Gatsby and at the time of posting this question there lacks good documentation for SEO components .我有一个基本的 Gatsby 博客设置,在发布这个问题时,缺乏关于 SEO 组件的良好文档 There are examples of basic SEO components but what I am wanting is a little more in-depth.有一些基本 SEO 组件的示例,但我想要更深入一点。 Maybe, if a solution is reached here it could be contributed to the Gatsby docs for others to benefit.也许,如果在这里达成了解决方案,它可以贡献给 Gatsby 文档,让其他人受益。

On top of the usual title and description meta tags and the facebook/twitter open graph meta (which I have done already), I want to add structured data forrich snippets which will vary depending on what the blog post type is.除了通常的标题和描述元标记以及 facebook/twitter 开放图元(我已经完成)之外,我还想为丰富的片段添加结构化数据,这些数据将根据博客文章类型的不同而有所不同。 For example, I might have a regular post which would print Article schema, some posts might be How-to , in which case I'd like to print HowTo schema instead of Article.例如,我可能有一个常规帖子会打印Article架构,有些帖子可能是How-to ,在这种情况下,我想打印 HowTo 架构而不是 Article。 At some point I might write a post with would suit FAQ schema.在某些时候,我可能会写一篇适合常见问题解答模式的帖子。

I don't know if this is the best approach but here's what I'm thinking:我不知道这是否是最好的方法,但这是我的想法:

1. In frontmatter set the schema type I want to true, leave the rest false. 1. 在 frontmatter 中设置我想要的模式类型为 true,将 rest 保留为 false。

I am also thinking of storing the schema data in the frontmatter but as this data is quite complex and will vary from post type to post type (Article, HowTo etc.) I'm not sure if this is yet a good idea?我也在考虑将模式数据存储在 frontmatter 中,但由于这些数据非常复杂,并且会因帖子类型(文章、HowTo 等)而异。我不确定这是否是个好主意?

---
title: Hello World
description: How to say hello
article: false
how-to: true
faq: false
---

2. Test for true/false in the SEO component and print the correct schema. 2. 测试 SEO 组件中的真/假并打印正确的架构。

Below is my entire SEO component, which obviously doesn't work but you can hopefully see where my thinking is headed.下面是我的整个 SEO 组件,它显然不起作用,但你可以希望看到我的想法。 I have dissected and borrowed from the gatsby advanced starter component and the gatsby starter prismic component but neither do quite what I need.我已经剖析并借鉴了gatsby Advanced Starter 组件gatsby starter prismic 组件,但都没有完全满足我的需要。 Here's mine:这是我的:

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

const SEO = ({
  title,
  desc,
  banner,
  pathname,
  published,
  modified,
  article,
  webpage,
  node,
}) => {
  const { site } = useStaticQuery(query)

  const {
    buildTime,
    siteMetadata: {
      siteUrl,
      defaultTitle,
      defaultDescription,
      defaultBanner,
      headline,
      siteLanguage,
      ogLanguage,
      author,
      twitter,
      facebook,
    },
  } = site

  const seo = {
    title: title || defaultTitle,
    description: desc || defaultDescription,
    image: `${siteUrl}${banner || defaultBanner}`,
    url: `${siteUrl}${pathname || "/"}`,
    date_published: published,
    date_modified: modified,
  }

  // Default Website Schema
  const schemaOrgJSONLD = [
    {
      "@context": "http://schema.org",
      "@type": "WebSite",
      url: siteUrl,
      name: defaultTitle,
      alternateName: headline ? headline : "",
    },
  ]

  if (howto) {
    schemaOrgJSONLD.push({
      /* HowTo Schema here */
    })
  }
  
  if (faq) {
    schemaOrgJSONLD.push({
      /* FAQ Schema here */
    })
  }

  if (article) {
    schemaOrgJSONLD.push({
      /* Regular Article Schema */
      "@context": "http://schema.org",
      "@type": "Article",
      author: {
        "@type": "Person",
        name: author,
      },
      copyrightHolder: {
        "@type": "Person",
        name: author,
      },
      copyrightYear: "2019",
      creator: {
        "@type": "Person",
        name: author,
      },
      publisher: {
        "@type": "Organization",
        name: author,
        logo: {
          "@type": "ImageObject",
          url: `${siteUrl}${defaultBanner}`,
        },
      },
      datePublished: seo.date_published,
      dateModified: seo.date_modified,
      description: seo.description,
      headline: seo.title,
      inLanguage: siteLanguage,
      url: seo.url,
      name: seo.title,
      image: {
        "@type": "ImageObject",
        url: seo.image,
      },
      mainEntityOfPage: seo.url,
    })
  }

  return (
    <>
      <Helmet title={seo.title}>
        <html lang={siteLanguage} />
        <meta name="description" content={seo.description} />
        <meta name="image" content={seo.image} />
        {/* Schema.org tags */}
        <script type="application/ld+json">
          {JSON.stringify(schemaOrgJSONLD)}
        </script>
      </Helmet>
      <Facebook
        desc={seo.description}
        image={seo.image}
        title={seo.title}
        type={article ? "article" : "website"}
        url={seo.url}
        locale={ogLanguage}
        name={facebook}
      />
      <Twitter
        title={seo.title}
        image={seo.image}
        desc={seo.description}
        username={twitter}
      />
    </>
  )
}

export default SEO

SEO.propTypes = {
  title: PropTypes.string,
  desc: PropTypes.string,
  banner: PropTypes.string,
  pathname: PropTypes.string,
  published: PropTypes.string,
  modified: PropTypes.string,
  article: PropTypes.bool,
  webpage: PropTypes.bool,
  node: PropTypes.object,
}

SEO.defaultProps = {
  title: null,
  desc: null,
  banner: null,
  pathname: null,
  published: null,
  modified: null,
  article: false,
  webpage: false,
  node: null,
}

const query = graphql`
  query SEO {
    site {
      buildTime(formatString: "YYYY-MM-DD")
      siteMetadata {
        siteUrl
        defaultTitle: title
        defaultDescription: description
        defaultBanner: logo
        headline
        siteLanguage
        ogLanguage
        author
        logo
        twitter
        facebook
      }
    }
  }
`

The problems I can see are:我能看到的问题是:

  1. How to test for what schema type to use and print it如何测试要使用的模式类型并打印它
  2. Include breadcrumbs schema for all types包括所有类型的面包屑模式
  3. Print only a single schema JSON-LD script tag, avoiding any duplicate schema仅打印单个模式 JSON-LD 脚本标签,避免任何重复模式
  4. Is using frontmatter in markdown files suitable to store complex schema data在适合存储复杂模式数据的 markdown 文件中使用 frontmatter
  5. Retrieving frontmatter data for schema检索模式的前端数据

I settled on this solution.我选择了这个解决方案。

In frontmatter:在前端:

---
type: howto // Use either 'article' or 'howto'
---

Query for it with GraphQL like you would for your other data:使用 GraphQL 查询它,就像查询其他数据一样:

frontmatter {
 title
 published(formatString: "MMMM DD, YYYY")
 modified(formatString: "MMMM DD, YYYY")
 description
 type
}

Pass it to your SEO component:将其传递给您的 SEO 组件:

<SEO
 title={post.frontmatter.title}
 desc={post.frontmatter.description}
 published={post.frontmatter.published}
 modified={post.frontmatter.modified}
 type={post.frontmatter.type}
/>

In your SEO component, you can use it like this (do the same for all your types).在您的 SEO 组件中,您可以像这样使用它(对所有类型执行相同操作)。 You can setup your Posts and SEO component for as my types as you need, FAQ, Course etc:您可以根据需要将帖子和 SEO 组件设置为我的类型、常见问题解答、课程等:

const schemaType = type

if (schemaType === "howto") {
 schemaHowTo = {
  // Your howto schema here
 }
}

if (schemaType === "article") {
 schemaArticle = {
  // Your article schema here
 }
}

Finally, in React Helmet we have:最后,在 React Helmet 中,我们有:

<Helmet>
 {schemaType === "howto" && (
  <script type="application/ld+json">
   {JSON.stringify(schemaHowTo)}
  </script>
 )}
 {schemaType === "article" && (
  <script type="application/ld+json">
   {JSON.stringify(schemaArticle)}
  </script>
 )}
...
<Helmet>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM