Gatsby: [gatsby-source-wordpress] ACF Flexible content in Flexible content returns duplicates

Created on 8 Oct 2018  路  5Comments  路  Source: gatsbyjs/gatsby

Description

Flexible content in Flexible Content returns an array with only the first unique row times the amount of rows. So all the rows after row 1 are duplicates of row 1 (even if every row are different field types).

Only one level Flexible Content works just fine.

Steps to reproduce

Add another ACF Flexible Content field inside the parent Flexible Content field.

Expected result

All rows to be unique.

Actual result

Rows are duplicates of the first row.

The WordPress Rest API:

...
"acf": {
  "builder": [
    {
      "acf_fc_layout": "grid",
      "grid": [
        {
          "acf_fc_layout": "text",
          "text": "<p>Text 1</p>\n",
        },
        {
          "acf_fc_layout": "text",
          "text": "<p>Another row, Text 2</p>\n",
        },
        {
          "acf_fc_layout": "text",
          "text": "<p>Another row, Text 3</p>\n",
        }
      ],
    }
  ],
},
...

GraphiQL query:

{
  allWordpressPage(filter: { slug: { eq: "test"} }) {
    edges {
      node {
        id
        title
        slug
        acf {
          builder_page {
           __typename
            ...on WordPressAcf_grid {
          id
              grid {
                id
                text
              }
            }
          }
        }
      }
    }
  }
}

GraphiQL response:

{
  "data": {
    "allWordpressPage": {
      "edges": [
        {
          "node": {
            "id": "270e0b30-05f3-5c06-87bc-fa47a0b9ed03",
            "title": "Test",
            "slug": "test",
            "acf": {
              "builder_page": [
                {
                  "__typename": "WordPressAcf_grid",
                  "id": "270e0b30-05f3-5c06-87bc-fa47a0b9ed030builderWordPressAcf_grid",
                  "grid": [
                    {
                      "id": "270e0b30-05f3-5c06-87bc-fa47a0b9ed030builderWordPressAcf_gridgrid",
                      "text": "<p>Text 1</p>\n"
                    },
                    {
                      "id": "270e0b30-05f3-5c06-87bc-fa47a0b9ed030builderWordPressAcf_gridgrid",
                      "text": "<p>Text 1</p>\n"
                    },
                    {
                      "id": "270e0b30-05f3-5c06-87bc-fa47a0b9ed030builderWordPressAcf_gridgrid",
                      "text": "<p>Text 1</p>\n"
                    }
                  ]
                }
              ]
            }
          }
        }
      ]
    }
  }
}

Environment

 System:
    OS: macOS 10.14
    CPU: x64 Intel(R) Core(TM) i7-4980HQ CPU @ 2.80GHz
    Shell: 3.2.57 - /bin/bash
  Binaries:
    Node: 8.11.1 - /usr/local/bin/node
    Yarn: 1.6.0 - /usr/local/bin/yarn
    npm: 6.4.1 - /usr/local/bin/npm
  Browsers:
    Chrome: 69.0.3497.100
    Firefox: 61.0.2
    Safari: 12.0
  npmPackages:
    gatsby: ^2.0.0 => 2.0.18
    gatsby-image: ^2.0.0-rc.4 => 2.0.0-rc.4
    gatsby-plugin-google-fonts: 0.0.4 => 0.0.4
    gatsby-plugin-manifest: ^2.0.2 => 2.0.4
    gatsby-plugin-offline: ^2.0.5 => 2.0.5
    gatsby-plugin-react-helmet: ^3.0.0 => 3.0.0
    gatsby-plugin-sharp: ^2.0.0-rc.7 => 2.0.0-rc.7
    gatsby-plugin-stylus: next => 2.0.0-rc.1
    gatsby-source-filesystem: ^2.0.1 => 2.0.1
    gatsby-source-wordpress: ^3.0.1 => 3.0.1
    gatsby-transformer-sharp: ^2.1.1-rc.3 => 2.1.1-rc.3
  npmGlobalPackages:
    gatsby-cli: 2.4.2
bug

All 5 comments

@jordyvg Can you create reproduction repo? If this happens there is probably bug somewhere here https://github.com/gatsbyjs/gatsby/blob/2d2e29b97a1e9a5dc49cd9763a8ab9f468e695e6/packages/gatsby-source-wordpress/src/normalize.js#L510-L552 and id is getting reused for all nested children (which will overwrite them)

@pieh Thank you, the reused id is the problem, acfChildNode returns the following:

{ acf_fc_layout: 'text',
  text: '<p>Text 1</p>\n',
  id: '37faeda9-a006-5368-afff-c5d7b13d79940builderWordPressAcf_gridgrid',
  parent: '37faeda9-a006-5368-afff-c5d7b13d79940',
  children: [],
  internal:
   { type: 'WordPressAcf_gridgrid',
     contentDigest: '6a30381167e7ae819989db8bd01e0057' } }
{ acf_fc_layout: 'text',
  text: '<p>Text 2</p>\n',
  id: '37faeda9-a006-5368-afff-c5d7b13d79940builderWordPressAcf_gridgrid',
  parent: '37faeda9-a006-5368-afff-c5d7b13d79940',
  children: [],
  internal:
   { type: 'WordPressAcf_gridgrid',
     contentDigest: '3d439974f00abc1181b39fff7d6ba2fa' } }
{ acf_fc_layout: 'text',
  text: '<p>Text 3</p>\n',
  id: '37faeda9-a006-5368-afff-c5d7b13d79940builderWordPressAcf_gridgrid',
  parent: '37faeda9-a006-5368-afff-c5d7b13d79940',
  children: [],
  internal:
   { type: 'WordPressAcf_gridgrid',
     contentDigest: '18a1117cefaf94226c53b5993c22df0d' } }

It is probably not the best way to do it, but an unique id will fix the issue:

const acfChildNode = { 
  ...obj, 
  id: _.random(10000) + '-'' + entityId + topLevelIndex + type, 
  parent: entityId, 
  children: [], 
  internal: { type, contentDigest: digest(JSON.stringify(obj)) }, 
} 

The code above returns:

{ acf_fc_layout: 'text',
  text: '<p>Text 1</p>\n',
  id: '695-37faeda9-a006-5368-afff-c5d7b13d79940builderWordPressAcf_gridgrid',
  parent: '37faeda9-a006-5368-afff-c5d7b13d79940',
  children: [],
  internal:
   { type: 'WordPressAcf_gridgrid',
     contentDigest: '6a30381167e7ae819989db8bd01e0057' } }
{ acf_fc_layout: 'text',
  text: '<p>Text 2</p>\n',
  id: '3937-37faeda9-a006-5368-afff-c5d7b13d79940builderWordPressAcf_gridgrid',
  parent: '37faeda9-a006-5368-afff-c5d7b13d79940',
  children: [],
  internal:
   { type: 'WordPressAcf_gridgrid',
     contentDigest: '3d439974f00abc1181b39fff7d6ba2fa' } }
{ acf_fc_layout: 'text',
  text: '<p>Text 3</p>\n',
  id: '8187-37faeda9-a006-5368-afff-c5d7b13d79940builderWordPressAcf_gridgrid',
  parent: '37faeda9-a006-5368-afff-c5d7b13d79940',
  children: [],
  internal:
   { type: 'WordPressAcf_gridgrid',
     contentDigest: '18a1117cefaf94226c53b5993c22df0d' } }

GraphiQL response:

{
  "data": {
    "allWordpressPage": {
      "edges": [
        {
          "node": {
            "id": "270e0b30-05f3-5c06-87bc-fa47a0b9ed03",
            "title": "Test",
            "slug": "test",
            "acf": {
              "builder_page": [
                {
                  "__typename": "WordPressAcf_grid",
                  "id": "4682-270e0b30-05f3-5c06-87bc-fa47a0b9ed030builderWordPressAcf_grid",
                  "grid": [
                    {
                      "acf_fc_layout": "text",
                      "id": "9390-270e0b30-05f3-5c06-87bc-fa47a0b9ed030builderWordPressAcf_gridgrid",
                      "text": "<p>Text 1</p>\n",
                    },
                    {
                      "acf_fc_layout": "text",
                      "id": "6791-270e0b30-05f3-5c06-87bc-fa47a0b9ed030builderWordPressAcf_gridgrid",
                      "text": "<p>Text 2</p>\n",
                    },
                    {
                      "acf_fc_layout": "text",
                      "id": "3104-270e0b30-05f3-5c06-87bc-fa47a0b9ed030builderWordPressAcf_gridgrid",
                      "text": "<p>Text 3</p>\n",
                    }
                  ],
                }
              ]
            }
          }
        }
      ]
    }
  }
}

It is probably not the best way to do it, but an unique id will fix the issue:

const acfChildNode = { 
  ...obj, 
  id: _.random(10000) + '-'' + entityId + topLevelIndex + type, 
  parent: entityId, 
  children: [], 
  internal: { type, contentDigest: digest(JSON.stringify(obj)) }, 
} 

Yeah, if possible we should avoid using _.random. I think in the code I linked above, when we mapping over flexible content items we would need to use index and pass it over to prepareACFChildNodes - maybe something like this?

_.each(obj, (value, key) => { 
     if (_.isArray(value) && value[0] && value[0].acf_fc_layout) { 
       obj[`${key}___NODE`] = value.map( 
-         v => 
+         (v, itemIndex) => 
           prepareACFChildNodes( 
             v, 
-             entityId, 
+             `${entityId}_${itemIndex}`, 
             topLevelIndex, 
             type + key, 
             children, 
             childrenNodes 
           ).id 
       ) 
       delete obj[key] 
     } 
   }) 

Yeah, if possible we should avoid using _.random. I think in the code I linked above, when we mapping over flexible content items we would need to use index and pass it over to prepareACFChildNodes - maybe something like this?

_.each(obj, (value, key) => { 
     if (_.isArray(value) && value[0] && value[0].acf_fc_layout) { 
       obj[`${key}___NODE`] = value.map( 
-         v => 
+         (v, itemIndex) => 
           prepareACFChildNodes( 
             v, 
-             entityId, 
+             `${entityId}_${itemIndex}`, 
             topLevelIndex, 
             type + key, 
             children, 
             childrenNodes 
           ).id 
       ) 
       delete obj[key] 
     } 
   }) 

Works, seems fine to me.

@jordyvg would you be interested in opening PR with that change?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

theduke picture theduke  路  3Comments

Oppenheimer1 picture Oppenheimer1  路  3Comments

andykais picture andykais  路  3Comments

kalinchernev picture kalinchernev  路  3Comments

brandonmp picture brandonmp  路  3Comments