如何为Gatsby创建一个GraphQL模式

16
我们正在从WordPress后端引入一些文章,其中一些文章有图片(在一个ACF字段中),而另一些则没有。问题是Gatsby基于它收到的第一个节点来推断模式。如果它接收到一个没有图片的节点,则模式就是错误的。 Gatsby的GraphQL模式从哪里来? 使用Gatsby时,我们使用插件从不同的源获取数据。然后,我们使用该数据自动推断出GraphQL模式。
我们如何指定一个始终包括图片的GraphQL/Gatsby模式,并在空白时将“null”作为默认值?
{
  allWordpressWpTestimonial {
    edges {
      node {
        id
        title
        acf {
          photo_fields {
            photo {
              id
              localFile {
                childImageSharp {
                  sizes {
                    src
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}

在上面的例子中,有时候'photo'不存在会导致一切崩溃...
Gatsby配置:
const innertext = require('innertext')
const url = require('url')

module.exports = {
  siteMetadata: {
    title: 'Test',
    googleMapsAPIKey: 'xxxxxx',
    adminBaseUrl: '123.123.123',
    adminProtocol: 'http',
  },
  pathPrefix: '/web/beta',
  plugins: [
    'gatsby-plugin-react-next',
    'gatsby-plugin-react-helmet',
    'gatsby-plugin-sharp',
    'gatsby-plugin-svgr',
    {
      resolve: 'gatsby-plugin-google-analytics',
      options: {
        trackingId: 'GOOGLE_ANALYTICS_TRACKING_ID',
      },
    },
    {
      resolve: 'gatsby-plugin-bugherd',
      options: {
        key: 'xxxxxx',
        showInProduction: true,
      },
    },
    {
      resolve: '@andrew-codes/gatsby-plugin-elasticlunr-search',
      options: {
        fields: ['title', 'url', 'textContent', 'urlSearchable'],
        resolvers: {
          wordpress__PAGE: {
            title: node => node.title,
            textContent: node => innertext(node.content),
            url: node => url.parse(node.link).path,
            urlSearchable: node =>
              url
                .parse(node.link)
                .path.split('/')
                .join(' '),
          },
          wordpress__POST: {
            title: node => node.title,
            textContent: node => innertext(node.content),
            url: node => `/news/${node.slug}`,
            urlSearchable: node =>
              url
                .parse(node.link)
                .path.split('/')
                .join(' '),
          },
          wordpress__wp_industry: {
            title: node => node.title,
            textContent: node => innertext(node.content),
            url: node => `/business/industries/${node.slug}`,
            urlSearchable: node =>
              url
                .parse(node.link)
                .path.split('/')
                .join(' '),
          },
        },
      },
    },
    {
      resolve: 'gatsby-source-wordpress',
      options: {
        baseUrl: 'xxxxxx',
        protocol: 'http',
        hostingWPCOM: false,
        useACF: true,
        auth: {
          htaccess_user: 'admin',
          htaccess_pass: 'xxxxxx',
          htaccess_sendImmediately: false,
        },
        verboseOutput: false,
      },
    },
    'gatsby-transformer-sharp',
  ],
}

你使用哪个插件从WordPress中提取源代码?你能分享一下你的Gatsby配置文件吗? - SirPeople
gatsby-source-wordpress,将会在gatsby配置中进行更新。 - Ashbury
2个回答

16

这篇文章发布已经有一段时间了,但是自从2.2版本Gatsby添加了一个新的API,这将使定制架构变得更加容易。这不是关于wordpress的例子,而是使用gatsby的gatsby-transformer-remark,但我确定它也适用。

我有很多像这样的.md文件:

---
title: "Screen title"
image: "./hero-image.png"  <--- sometimes it's an empty string, ""
category: "Cat"
---

...content...
如果 Gatsby 首先访问带有空图像的 .md,它会错误地将该字段推断为 String,即使它应该是 File。使用新的 API,我可以在 gatsby-node.js 中告诉 Gatsby 关于图像字段的信息。
exports.sourceNodes = ({ actions, schema }) => {
  const { createTypes } = actions
  createTypes(`
    type MarkdownRemarkFrontmatter {
      image: File
    }

    type MarkdownRemark implements Node {
      frontmatter: MarkdownRemarkFrontmatter
    }
  `)
}

这将保证image字段始终为文件类型,否则它将为null

一些注意事项:

  • MarkdownRemark这样的根节点必须实现Node
  • 一个节点可以实现多个接口
  • 您必须“逐层下降”到相关字段。在此示例中,我必须声明MarkdownRemarkFrontmatter类型,然后将其传递给MarkdownRemark节点中的frontmatter字段。
  • 如果未指定,则Gatsby将推断其余字段。在上面的示例中,由于我没有在MarkdownRemarkFrontmatter中指定category字段,因此它将像以前一样由Gatsby推断。
  • 查找这些类型(MarkdownRemarkMarkdownRemarkFrontmatter)最有帮助的方法是在graphiql中查找(默认为localhost:8000/___graphql

我正在努力让这个与WordPress和ACF一起工作。每个节点都有一个ACF对象,其中包含一个重复器对象,其中包含一个Link数组,其中包含3个字符串(标题、URL、目标)。我尝试创建一系列函数来挖掘所有的方式到3个字符串,但这对我不起作用。{ allWordpressPost { edges { node { title acf { project_students partners { partner_link { title url target } } } } } } } - amcc

0

首先,你是否在使用 Gatsby-plugin-sharp、Gatsby-transform-sharp 和 Gatsby-source-WordPress 插件?

我的网站使用了 Gatsby-source-Wordpress 插件以及 sharp 库和 Bluebird 来返回承诺等功能。 在你的 Post.js 或 Page.js 中定义 ImageURL。源 URL 在加载到我的媒体库时生成,但会被转移到 S3 存储桶中,因为我的 WordPress 网站是“以编程方式”构建的。 源 URL 通常由您自己定义,并且可以在构建帖子或页面模板时选择 ACF 字段类型。

export const pageQuery = graphql`
  query homePageQuery {
    site {
      siteMetadata {
        title
        subtitle
        description
      }
    }

    allWordpressPost(sort: { fields: [date] }) {
      edges {
        node {
          title
          excerpt
          slug
          type
          _image{
            source_url
          }
          categories {
            slug
            name
          }
        }
      }
    }
  } 

对于每种帖子类型,按照确切的顺序查询数据是必需的,否则GraphQL将无法正确返回方案,从而产生错误。 虽然听起来很简单和重复,但有时候必须有两个不同的GraphQL方案和两个post.js示例post1.js和post2.js文件来定义不同的帖子类别。 1.查询返回图像URL。 2.查询返回没有图像。等于null或不存在。 这是GraphQL的缺点,它期望接收X,当Y发生时,它会变得不开心并失败。

当您接收到图像时,您也可以尝试使用sharp进行转换,使其成为href=并在接收时将其从https转换为大小。但在您的情况下,将其设置为null的方案。 我们为一个从旧WordPress网站返回的员工自传页面执行了此操作。

/**
     * Transform internal absolute link to relative.
     * 
     * @param {string} string The HTML to run link replacemnt on
     */
    linkReplace(string) {
        // console.log(string)
        const formatted = string.replace(
            /(href="https?:\/\/dev-your-image-api\.pantheonsite\.io\/)/g,
            `href="/`
        )

        return formatted
    }

    render() {
        const post = { ...this.props.data.wordpressPost }
        const headshot = { ...this.props.data.file.childImageSharp.resolutions }
        const { percentScrolled } = { ...this.state }
        const contentFormatted = this.linkReplace(post.content)

        return (
            <div ref={el => (this.post = el)}>
                <div className={styles.progressBarWrapper}>
                    <div
                        style={{ width: `${percentScrolled}%` }}
                        className={styles.progressBar}
                    />
                </div>

                <div className={styles.post}>
                    <h1
                        className={styles.title}
                        dangerouslySetInnerHTML={{ __html: post.title }}
                    />

                    <div
                        className={styles.content}
                        dangerouslySetInnerHTML={{ __html: contentFormatted }}
                    />

                    <Bio headshot={headshot} horizontal={true} />
                </div>
            </div>
        )
    }
}

Post.propTypes = {
    data: PropTypes.object.isRequired,
}

export default Post

export const postQuery = graphql`
    query currentPostQuery($id: String!) {
        wordpressPost(id: { eq: $id }) {
            wordpress_id
            title
            content
            slug
        }
        file(relativePath: { eq: "your-image-headshot.jpg" }) {
            childImageSharp {
                resolutions(width: 300, height: 300) {
                    ...GatsbyImageSharpResolutions
                }
            }
        }
    }

`

希望这有所帮助,随时给我留言。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接