Skip to content

Commit

Permalink
[gatsby-source-wordpress] Refactored featured_media map for deep nodes (
Browse files Browse the repository at this point in the history
#2648)

* Refactored featured_media map for deep nodes

* Featured medias coul be nested at any level
* The most certain way to have photos works with this version on the plugin is to either name the fiel featured_media or include the image as Post Object.
* Fixed bug where in some case the old featured_media field was not deleted.

* Update normalize.js.snap

* Integrated pieh 's changes

* Most of the credits goes to @pieh for a better solution that solved the same problems and widely improved code simplicity. #2646
* Made the Media lookup begin at JSON tree root instead of keeping this for ACF Field only. Changed constants names accordingly.
* Making thise more generic allorws Custom Post Types to benefit from this improvements and yet unseen objects shapes. 
* Incorporated fix on bug mentionned here #2646 (comment)
* May solve this #2587, this #2492, this #2328

* Update normalize.js.snap
  • Loading branch information
sebastienfi authored Oct 27, 2017
1 parent 8fca5d1 commit 92c89d3
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 64 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5790,6 +5790,7 @@ Array [
],
},
"acf": Object {
"dummy": true,
"linked_image___NODE": "950513a1-a720-5588-b262-9533aa598624",
},
"author___NODE": "ec1fb3e3-d897-5549-b5f6-72b358fbbe83",
Expand Down Expand Up @@ -5858,7 +5859,7 @@ Array [
"date": "2017-09-02T10:36:43.000Z",
"description": "<p class=\\"attachment\\"><a href='http://dev-gatbsyjswp.pantheonsite.io/wp-content/uploads/2017/09/pexels-photo-534327.jpeg'><img width=\\"300\\" height=\\"200\\" src=\\"http://dev-gatbsyjswp.pantheonsite.io/wp-content/uploads/2017/09/pexels-photo-534327-300x200.jpeg\\" class=\\"attachment-medium size-medium\\" alt=\\"\\" srcset=\\"http://dev-gatbsyjswp.pantheonsite.io/wp-content/uploads/2017/09/pexels-photo-534327-300x200.jpeg 300w, http://dev-gatbsyjswp.pantheonsite.io/wp-content/uploads/2017/09/pexels-photo-534327-768x512.jpeg 768w, http://dev-gatbsyjswp.pantheonsite.io/wp-content/uploads/2017/09/pexels-photo-534327-1024x683.jpeg 1024w\\" sizes=\\"(max-width: 300px) 100vw, 300px\\" /></a></p>
",
"guid": "http://dev-gatbsyjswp.pantheonsite.io/wp-content/uploads/2017/09/pexels-photo-534327.jpeg",
"guid___NODE": "61ef7ef2-032f-5c90-bba3-99d04c9a1f07",
"id": "61ef7ef2-032f-5c90-bba3-99d04c9a1f07",
"link": "http://dev-gatbsyjswp.pantheonsite.io/sample-post-1/pexels-photo-534327/",
"media_details": Object {
Expand Down Expand Up @@ -5970,7 +5971,7 @@ Array [
"date": "2017-09-02T10:35:16.000Z",
"description": "<p class=\\"attachment\\"><a href='http://dev-gatbsyjswp.pantheonsite.io/wp-content/uploads/2017/09/pexels-photo-534351.jpeg'><img width=\\"300\\" height=\\"200\\" src=\\"http://dev-gatbsyjswp.pantheonsite.io/wp-content/uploads/2017/09/pexels-photo-534351-300x200.jpeg\\" class=\\"attachment-medium size-medium\\" alt=\\"\\" srcset=\\"http://dev-gatbsyjswp.pantheonsite.io/wp-content/uploads/2017/09/pexels-photo-534351-300x200.jpeg 300w, http://dev-gatbsyjswp.pantheonsite.io/wp-content/uploads/2017/09/pexels-photo-534351-768x512.jpeg 768w, http://dev-gatbsyjswp.pantheonsite.io/wp-content/uploads/2017/09/pexels-photo-534351-1024x683.jpeg 1024w\\" sizes=\\"(max-width: 300px) 100vw, 300px\\" /></a></p>
",
"guid": "http://dev-gatbsyjswp.pantheonsite.io/wp-content/uploads/2017/09/pexels-photo-534351.jpeg",
"guid___NODE": "950513a1-a720-5588-b262-9533aa598624",
"id": "950513a1-a720-5588-b262-9533aa598624",
"link": "http://dev-gatbsyjswp.pantheonsite.io/gatsby-sample-home-page/pexels-photo-534351/",
"media_details": Object {
Expand Down Expand Up @@ -11337,6 +11338,7 @@ Array [
],
},
"acf": Object {
"dummy": true,
"linked_image___NODE": "950513a1-a720-5588-b262-9533aa598624",
},
"author___NODE": "ec1fb3e3-d897-5549-b5f6-72b358fbbe83",
Expand All @@ -11355,7 +11357,7 @@ Array [
"guid": "http://dev-gatbsyjswp.pantheonsite.io/?page_id=5",
"id": "340ceded-7db7-583c-9486-120758f5d967",
"internal": Object {
"contentDigest": "bf7491f5ede200a6f3ce8db4c28e3eca",
"contentDigest": "730b646cd1ae6cd070d74956e5041fd2",
"type": "wordpress__PAGE",
},
"link": "http://dev-gatbsyjswp.pantheonsite.io/",
Expand Down Expand Up @@ -11413,10 +11415,10 @@ Array [
"date": "2017-09-02T10:36:43.000Z",
"description": "<p class=\\"attachment\\"><a href='http://dev-gatbsyjswp.pantheonsite.io/wp-content/uploads/2017/09/pexels-photo-534327.jpeg'><img width=\\"300\\" height=\\"200\\" src=\\"http://dev-gatbsyjswp.pantheonsite.io/wp-content/uploads/2017/09/pexels-photo-534327-300x200.jpeg\\" class=\\"attachment-medium size-medium\\" alt=\\"\\" srcset=\\"http://dev-gatbsyjswp.pantheonsite.io/wp-content/uploads/2017/09/pexels-photo-534327-300x200.jpeg 300w, http://dev-gatbsyjswp.pantheonsite.io/wp-content/uploads/2017/09/pexels-photo-534327-768x512.jpeg 768w, http://dev-gatbsyjswp.pantheonsite.io/wp-content/uploads/2017/09/pexels-photo-534327-1024x683.jpeg 1024w\\" sizes=\\"(max-width: 300px) 100vw, 300px\\" /></a></p>
",
"guid": "http://dev-gatbsyjswp.pantheonsite.io/wp-content/uploads/2017/09/pexels-photo-534327.jpeg",
"guid___NODE": "61ef7ef2-032f-5c90-bba3-99d04c9a1f07",
"id": "61ef7ef2-032f-5c90-bba3-99d04c9a1f07",
"internal": Object {
"contentDigest": "345cd9205939fd066a98ad92bce14d60",
"contentDigest": "e34c3e03101d1305788a27f283e90c6b",
"type": "wordpress__wp_media",
},
"link": "http://dev-gatbsyjswp.pantheonsite.io/sample-post-1/pexels-photo-534327/",
Expand Down Expand Up @@ -11532,10 +11534,10 @@ Array [
"date": "2017-09-02T10:35:16.000Z",
"description": "<p class=\\"attachment\\"><a href='http://dev-gatbsyjswp.pantheonsite.io/wp-content/uploads/2017/09/pexels-photo-534351.jpeg'><img width=\\"300\\" height=\\"200\\" src=\\"http://dev-gatbsyjswp.pantheonsite.io/wp-content/uploads/2017/09/pexels-photo-534351-300x200.jpeg\\" class=\\"attachment-medium size-medium\\" alt=\\"\\" srcset=\\"http://dev-gatbsyjswp.pantheonsite.io/wp-content/uploads/2017/09/pexels-photo-534351-300x200.jpeg 300w, http://dev-gatbsyjswp.pantheonsite.io/wp-content/uploads/2017/09/pexels-photo-534351-768x512.jpeg 768w, http://dev-gatbsyjswp.pantheonsite.io/wp-content/uploads/2017/09/pexels-photo-534351-1024x683.jpeg 1024w\\" sizes=\\"(max-width: 300px) 100vw, 300px\\" /></a></p>
",
"guid": "http://dev-gatbsyjswp.pantheonsite.io/wp-content/uploads/2017/09/pexels-photo-534351.jpeg",
"guid___NODE": "950513a1-a720-5588-b262-9533aa598624",
"id": "950513a1-a720-5588-b262-9533aa598624",
"internal": Object {
"contentDigest": "60e31d4f0302cc6cae5c7021444ff564",
"contentDigest": "7bb20caef5bf65715b92b109cbfae7b9",
"type": "wordpress__wp_media",
},
"link": "http://dev-gatbsyjswp.pantheonsite.io/gatsby-sample-home-page/pexels-photo-534351/",
Expand Down
136 changes: 79 additions & 57 deletions packages/gatsby-source-wordpress/src/normalize.js
Original file line number Diff line number Diff line change
Expand Up @@ -239,20 +239,10 @@ exports.mapEntitiesToMedia = entities => {

return entities.map(e => {
// Map featured_media to its media node
let featuredMedia
if (e.featured_media) {
featuredMedia = media.find(m => m.wordpress_id === e.featured_media)
}

if (featuredMedia) {
e.featured_media___NODE = featuredMedia.id
}

// Always delete even if we can't find a featuredMedia as WordPress' API sets
// featured_media to 0 when there isn't one which is useless to us.
delete e.featured_media

const isPhoto = field =>
// Check if it's value of ACF Image field, that has 'Return value' set to
// 'Image Object' ( https://www.advancedcustomfields.com/resources/image/ )
const isPhotoObject = field =>
_.isObject(field) &&
field.wordpress_id &&
field.url &&
Expand All @@ -262,61 +252,93 @@ exports.mapEntitiesToMedia = entities => {
: false

const photoRegex = /\.(gif|jpg|jpeg|tiff|png)$/i
const isPhotoUrl = filename => photoRegex.test(filename)
const replacePhoto = field =>
media.find(m => m.wordpress_id === field.wordpress_id).id

const replaceFieldsInObject = object => {
_.each(object, (value, key) => {
if (_.isArray(value)) {
value.forEach(v => replaceFieldsInObject(v))
}
if (isPhoto(value)) {
object[`${key}___NODE`] = replacePhoto(value)
delete object[key]
const isPhotoUrl = filename =>
_.isString(filename) && photoRegex.test(filename)
const isPhotoUrlAlreadyProcessed = key => key == `source_url`
const isFeaturedMedia = (value, key) =>
(_.isNumber(value) || _.isBoolean(value)) && key === `featured_media`
// ACF Gallery and similarly shaped arrays
const isArrayOfPhotoObject = field =>
_.isArray(field) && field.length > 0 && isPhotoObject(field[0])
const getMediaItemID = mediaItem => (mediaItem ? mediaItem.id : null)

// Try to get media node from value:
// - special case - check if key is featured_media and value is photo ID
// - check if value is photo url
// - check if value is ACF Image Object
// - check if value is ACF Gallery
const getMediaFromValue = (value, key) => {
if (isFeaturedMedia(value, key)) {
return {
mediaNodeID: _.isNumber(value)
? getMediaItemID(media.find(m => m.wordpress_id === value))
: null,
deleteField: true,
}

// featured_media can be nested inside ACF fields
if (_.isObject(value) && value.featured_media) {
featuredMedia = media.find(
m => m.wordpress_id === value.featured_media
)
if (featuredMedia) {
value.featured_media___NODE = featuredMedia.id
}
delete value.featured_media
} else if (isPhotoUrl(value) && !isPhotoUrlAlreadyProcessed(key)) {
const mediaNodeID = getMediaItemID(
media.find(m => m.source_url === value)
)
return {
mediaNodeID,
deleteField: !!mediaNodeID,
}
if (_.isNumber(value) && key == `featured_media`) {
featuredMedia = media.find(m => m.wordpress_id === value)
if (featuredMedia) {
object[`${key}___NODE`] = featuredMedia.id
}
delete object[key]
} else if (isPhotoObject(value)) {
const mediaNodeID = getMediaItemID(
media.find(m => m.source_url === value.url)
)
return {
mediaNodeID,
deleteField: !!mediaNodeID,
}
if (_.isBoolean(value) && key == `featured_media`) {
delete object[key]
} else if (isArrayOfPhotoObject(value)) {
return {
mediaNodeID: value
.map(item => getMediaFromValue(item, key).mediaNodeID)
.filter(id => id !== null),
deleteField: true,
}
})
}
return {
mediaNodeID: null,
deleteField: false,
}
}

if (e.acf) {
_.each(e.acf, (value, key) => {
if (_.isString(value) && isPhotoUrl(value)) {
const me = media.find(m => m.source_url === value)
if (me) {
e.acf[`${key}___NODE`] = me.id
delete e.acf[key]
}
const replaceFieldsInObject = object => {
let deletedAllFields = true
_.each(object, (value, key) => {
const { mediaNodeID, deleteField } = getMediaFromValue(value, key)
if (mediaNodeID) {
object[`${key}___NODE`] = mediaNodeID
}
if (deleteField) {
delete object[key]
// We found photo node (even if it has no image),
// We can end processing this path
return
} else {
deletedAllFields = false
}

if (_.isArray(value) && value[0] && value[0].acf_fc_layout) {
e.acf[key] = e.acf[key].map(f => {
replaceFieldsInObject(f)
return f
})
if (_.isArray(value)) {
value.forEach(v => replaceFieldsInObject(v))
} else if (_.isObject(value)) {
replaceFieldsInObject(value)
}
})

// Deleting fields and replacing them with links to different nodes
// can cause build errors if object will have only linked properites:
// https://github.com/gatsbyjs/gatsby/blob/master/packages/gatsby/src/schema/infer-graphql-input-fields.js#L205
// Hacky workaround:
// Adding dummy field with concrete value (not link) fixes build
if (deletedAllFields && object && _.isObject(object)) {
object[`dummy`] = true
}
}
replaceFieldsInObject(e)

return e
})
}
Expand Down

0 comments on commit 92c89d3

Please sign in to comment.