Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gastby-source-wordpress, ACF Flexible content, schemaCustomization issue #16809

Closed
tol-is opened this issue Aug 20, 2019 · 4 comments
Closed

gastby-source-wordpress, ACF Flexible content, schemaCustomization issue #16809

tol-is opened this issue Aug 20, 2019 · 4 comments

Comments

@tol-is
Copy link

@tol-is tol-is commented Aug 20, 2019

Hi, I'm trying to hook into the createSchemaCustomization and create some custom types for an some acf flexible content data. The reason is some node types will not exist at any given time. So i can't rely on the data to infer the types.

Something is not working for me and I'm not sure if I'm missing something or if this is a bug.

The query i'm trying to run
  fragment typeOne on WordPressAcf_typeOne {
  flexText
}

fragment typeTwo on WordPressAcf_typeTwo {
  flexInt
}

fragment typeThree on WordPressAcf_typeThree {
  flexUrl
}

query MyQuery {
  wordpressWpHelp(wordpress_id: {eq: 659}) {
    id
    acf {
      flexContent_help {
        ...typeOne
        ...typeTwo
        ...typeThree
      }
    }
  }
}

Half of it seems to be working well, meaning I can declare a node field and a type that don't exist in the cms, using the @dontInfer directive, and in graphiql I can successfully see both

const typeDefs = `

    type WordPressAcf_typeOne implements Node @dontInfer {
      id: ID!
      flexText: String
    }

    type WordPressAcf_typeTwo implements Node @dontInfer {
      id: ID!
      flexInt: String
      # flexPotato is a made up key, doesn't come from anywhere
      flexPotato: Int
    }
    # typeThree doesn't exist in the cms
    type WordPressAcf_typeThree implements Node @dontInfer {
      id: ID!
      flexUrl: String
      flexTomato: String
    }
  `
  createTypes(typeDefs)
}

The problem

As soon as I'm trying to customize the schema for the node containing the flexible content union I get an error Error: Schema must contain uniquely named types but contains multiple types named "wordpress__wp_helpAcf".

  const typeDefs = `
    union AcfFlexContentUnion =
      WordPressAcf_typeOne
    | WordPressAcf_typeTwo
    | WordPressAcf_typeThree
   
    # customize union type of acf flexible content node
    type wordpress__wp_helpAcf implements Node @dontInfer {
      flexContent_help : [AcfFlexContentUnion]
    }

    type WordPressAcf_typeOne implements Node @dontInfer {
      id: ID!
    }

    type WordPressAcf_typeTwo implements Node @dontInfer {
      id: ID!
    }
    # typeThree doesn't exist in wordpress data (layout not applied in cms)
    type WordPressAcf_typeThree implements Node @dontInfer {
      id: ID!
    }

Another attempt

I also tried to customize the schema from one level up, and its not complaining anymore but now the flexContent_help value returns null.

const typeDefs = `

    union AcfFlexContentUnion =
      WordPressAcf_typeOne
    | WordPressAcf_typeTwo
    | WordPressAcf_typeThree

    type wordpress__wp_help implements Node  {
      id: ID!
      acf: wordpress__wp_helpAcf
    }

    type wordpress__wp_helpAcf implements Node @dontInfer  {
      flexContent_help : [AcfFlexContentUnion]
    }

Reproduction

I prepared a repository to reproduce the issue with all three attempts in gastby-node.js
https://github.com/tol-is/gastby-wordpress-help

@tol-is tol-is changed the title Gastby source wordpress schema customization gastby-source-wordpress, customize ACF Flexible content, union node Aug 21, 2019
@tol-is tol-is changed the title gastby-source-wordpress, customize ACF Flexible content, union node gastby-source-wordpress, ACF Flexible content, schemaCustomization issue Aug 21, 2019
@stefanprobst

This comment has been minimized.

Copy link
Contributor

@stefanprobst stefanprobst commented Aug 21, 2019

@tol-is i don't have experience with the wordpress plugin, and i find those types with underscores and upper/lowercase wordpress/wordPress/WordPress names super confusing -- but if i understand the issue, you can create a union field linking to nodes with different content types like this (the sourceNodes part is just so we have nodes to query):

exports.sourceNodes = ({ actions }) => {
  const nodes = [
    {
      id: `help`,
      internal: {
        type: `Help`,
        contentDigest: `help`,
      },
      contents: [`union1`, `union2`],
    },
    {
      id: `union1`,
      internal: {
        type: `IntContent`,
        contentDigest: `union1`,
      },
      int: 1,
    },
    {
      id: `union2`,
      internal: {
        type: `StringContent`,
        contentDigest: `union2`,
      },
      str: `One`,
    },
  ]
  nodes.forEach(node => actions.createNode(node))
}

exports.createSchemaCustomization = ({ actions }) => {
  actions.createTypes(`
    type Help implements Node @dontInfer {
      contents: [Content] @link
    }
    type IntContent implements Node @dontInfer {
      int: Int
    }
    type StringContent implements Node @dontInfer {
      str: String
    }
    union Content = IntContent | StringContent
  `)
}

The dontInfer directive is not strictly necessary, the important part is that createTypes will not create foreign-key relations out of the box. To resolve the ids on the contents field to nodes of type Content, we can use the @link directive.

Query:
unions

@tol-is

This comment has been minimized.

Copy link
Author

@tol-is tol-is commented Aug 21, 2019

thanks @stefanprobst, I really appreciate your time.

My code was very close to your directions, though I didn't know about the @link directive. To be honest I don't quite understand it yet but I've tried everything I could think of and a dozen shots in the dark and i can't find my way through.

The schema declaration seems to work fine for some node types, but as soon as touch the specific node that contains the content union, it's complaining.

Screenshot 2019-08-21 21 29 12

There's a lot going on under the hood in gastby-source-wordpress, so I can't really tell if what I'm trying to do needs a different approach, it's a bug or just not possible.

Also updated the demo repo (just in case)
https://github.com/tol-is/gastby-wordpress-help/blob/master/gatsby-node.js

@stefanprobst

This comment has been minimized.

Copy link
Contributor

@stefanprobst stefanprobst commented Aug 22, 2019

so this is working:

exports.createSchemaCustomization = ({ actions }) => {
  const { createTypes } = actions
  const typeDefs = `

    union AcfFlexContentUnion =
      WordPressAcf_typeOne
    | WordPressAcf_typeTwo
    | WordPressAcf_typePotato

    type wordpress__wp_help implements Node {
      acf: wordpress__wp_helpAcf
    }

    type wordpress__wp_helpAcf {
      flexContent_help: [AcfFlexContentUnion] @link(from: "flexContent_help___NODE")
    }

    type WordPressAcf_typeOne implements Node {
      flexText: String
    }

    type WordPressAcf_typeTwo implements Node {
      flexInt: String
    }

    type WordPressAcf_typePotato implements Node {
      flexTomato: String
    }
  `
  createTypes(typeDefs)
}

Three things to note:

  • we need to start defining types from the top-level type which in this case is wordpress__wp_help
  • the wordpress__wp_helpAcf does not implement the Node interface -- this is only for nodes with a unique id (created by the plugin with createNode) -- although this is quite confusing in the wordpress case
  • we need an extra from argument on the link directive. this is because the mechanism with which plugins created foreign-key relations before the introduction of the schema customization APIs was with a field naming convention: every field with a ___NODE suffix will be treated as such. since the suffix is then stripped from the field name, the user never sees this. when providing type definitions for types created by plugins that use this naming convention to create foreign-key relations, this makes things unfortunately a bit non-obvious: the link directive will use the field value to resolve to the full node, but since the actual field value does live on a field with the ___NODE suffix, we need to point the link directive to the field where the actual field value can be found
@tol-is

This comment has been minimized.

Copy link
Author

@tol-is tol-is commented Aug 22, 2019

Indeed that's working!

@stefanprobst you're a legend and a hero!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
2 participants
You can’t perform that action at this time.