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

Wordpress source normaliser plugin extension #3783

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions packages/gatsby-source-wordpress/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,12 @@ plugins: [
sourceUrl: "https://source-url.com",
replacementUrl: "https://replacement-url.com",
},
// Add plugins to modify WordPress entitys
plugins: [
{
resolve: `wordpress-normalizer-plugin`
},
]
},
},
];
Expand Down Expand Up @@ -467,6 +473,26 @@ To learn more about image processing check
* source code of [image processing example
site](https://github.com/gatsbyjs/gatsby/tree/master/examples/image-processing).

## WordPress Source Normalizer Plugins

Write custom plugins to modify WordPress entities during the build process.

The set method accepts two arguments, the normalizer and the priority in which this normalizer is set. Do not pass the priority if you wish your normalizer to be called last.

**index.js Example**

```javascript
exports.normalize = function (normalizer) {

function modify(entities, args) {
// Modify entities
return entities
}

return normalizer.set(modify, 140)
}
```

## Site's `gatsby-node.js` example

```javascript
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ describe(`Process WordPress data`, () => {
it(`creates Gatsby IDs for each entity`, () => {
const createNodeId = jest.fn()
createNodeId.mockReturnValue(`uuid-from-gatsby`)
entities = normalize.createGatsbyIds(createNodeId, entities)
entities = normalize.createGatsbyIds(entities, { createNodeId })
expect(entities).toMatchSnapshot()
})
it(`Creates map of types`, () => {
Expand Down
78 changes: 34 additions & 44 deletions packages/gatsby-source-wordpress/src/gatsby-node.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
const fetch = require(`./fetch`)
const normalize = require(`./normalize`)
const Normalizer = require(`./normalizer`)
const _ = require(`lodash`)

const typePrefix = `wordpress__`
const refactoredEntityTypes = {
Expand Down Expand Up @@ -28,6 +30,7 @@ exports.sourceNodes = async (
verboseOutput,
perPage = 100,
searchAndReplaceContentUrls = {},
plugins = [],
}
) => {
const { createNode } = boundActionCreators
Expand All @@ -50,57 +53,44 @@ exports.sourceNodes = async (
refactoredEntityTypes,
})

// Normalize data & create nodes

// Remove ACF key if it's not an object
entities = normalize.normalizeACF(entities)

// Creates entities from object collections of entities
entities = normalize.normalizeEntities(entities)

// Standardizes ids & cleans keys
entities = normalize.standardizeKeys(entities)

// Converts to use only GMT dates
entities = normalize.standardizeDates(entities)

// Lifts all "rendered" fields to top-level.
entities = normalize.liftRenderedField(entities)

// Exclude entities of unknown shape
entities = normalize.excludeUnknownEntities(entities)

// Creates Gatsby IDs for each entity
entities = normalize.createGatsbyIds(createNodeId, entities)

// Creates links between authors and user entities
entities = normalize.mapAuthorsToUsers(entities)

// Creates links between posts and tags/categories.
entities = normalize.mapPostsToTagsCategories(entities)

// Creates links between tags/categories and taxonomies.
entities = normalize.mapTagsCategoriesToTaxonomies(entities)

// Creates links from entities to media nodes
entities = normalize.mapEntitiesToMedia(entities)

// Downloads media files and removes "sizes" data as useless in Gatsby context.
entities = await normalize.downloadMediaFiles({
entities,
var normalizer = new Normalizer(entities, {
createNodeId,
store,
cache,
createNode,
_auth,
})

// Search and replace Content Urls
entities = normalize.searchReplaceContentUrls({
entities,
searchAndReplaceContentUrls,
})

// creates nodes for each entry
normalizer
.set(normalize.normalizeACF, 10)
.set(normalize.normalizeEntities, 20)
.set(normalize.standardizeKeys, 30)
.set(normalize.standardizeDates, 40)
.set(normalize.liftRenderedField, 50)
.set(normalize.excludeUnknownEntities, 60)
.set(normalize.createGatsbyIds, 70)
.set(normalize.mapAuthorsToUsers, 80)
.set(normalize.mapPostsToTagsCategories, 90)
.set(normalize.mapTagsCategoriesToTaxonomies, 100)
.set(normalize.mapEntitiesToMedia, 110)
.set(normalize.downloadMediaFiles, 120)
.set(normalize.searchReplaceContentUrls, 130)

for (let i = 0; i < plugins.length; i++) {
var requiredPlugin = require(plugins[i].resolve)

if (_.isFunction(requiredPlugin.normalize)) {
var pluginNormalizer = requiredPlugin.normalize(normalizer)
if (pluginNormalizer instanceof Normalizer) {
normalizer = pluginNormalizer
}
}

}

entities = await normalizer.normalize()

normalize.createNodesFromEntities({ entities, createNode })

return
Expand Down
37 changes: 14 additions & 23 deletions packages/gatsby-source-wordpress/src/normalize.js
Original file line number Diff line number Diff line change
Expand Up @@ -140,9 +140,9 @@ exports.liftRenderedField = entities =>
exports.excludeUnknownEntities = entities =>
entities.filter(e => e.wordpress_id) // Excluding entities without ID

exports.createGatsbyIds = (createNodeId, entities) =>
exports.createGatsbyIds = (entities, args) =>
entities.map(e => {
e.id = createNodeId(`${e.__type}-${e.wordpress_id.toString()}`)
e.id = args.createNodeId(`${e.__type}-${e.wordpress_id.toString()}`)
return e
})

Expand Down Expand Up @@ -223,21 +223,18 @@ exports.mapTagsCategoriesToTaxonomies = entities =>
return e
})

exports.searchReplaceContentUrls = function({
entities,
searchAndReplaceContentUrls,
}) {
exports.searchReplaceContentUrls = function(entities, args) {
if (
!_.isPlainObject(searchAndReplaceContentUrls) ||
!_.has(searchAndReplaceContentUrls, `sourceUrl`) ||
!_.has(searchAndReplaceContentUrls, `replacementUrl`) ||
typeof searchAndReplaceContentUrls.sourceUrl !== `string` ||
typeof searchAndReplaceContentUrls.replacementUrl !== `string`
!_.isPlainObject(args.searchAndReplaceContentUrls) ||
!_.has(args.searchAndReplaceContentUrls, `sourceUrl`) ||
!_.has(args.searchAndReplaceContentUrls, `replacementUrl`) ||
typeof args.searchAndReplaceContentUrls.sourceUrl !== `string` ||
typeof args.searchAndReplaceContentUrls.replacementUrl !== `string`
) {
return entities
}

const { sourceUrl, replacementUrl } = searchAndReplaceContentUrls
const { sourceUrl, replacementUrl } = args.searchAndReplaceContentUrls

const _blacklist = [`_links`, `__type`]

Expand Down Expand Up @@ -379,24 +376,18 @@ exports.mapEntitiesToMedia = entities => {
}

// Downloads media files and removes "sizes" data as useless in Gatsby context.
exports.downloadMediaFiles = async ({
entities,
store,
cache,
createNode,
_auth,
}) =>
exports.downloadMediaFiles = async (entities, args) =>
Promise.all(
entities.map(async e => {
let fileNode
if (e.__type === `wordpress__wp_media`) {
try {
fileNode = await createRemoteFileNode({
url: e.source_url,
store,
cache,
createNode,
auth: _auth,
store: args.store,
cache: args.cache,
createNode: args.createNode,
auth: args._auth,
})
} catch (e) {
// Ignore
Expand Down
65 changes: 65 additions & 0 deletions packages/gatsby-source-wordpress/src/normalizer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
const _ = require(`lodash`)

class Normalizer {

/**
* Normalizer Constructor
*
* @param {Array} entitys
* @param {Object} args
* @return {Object} this
*/
constructor(entitys, args) {
this.entitys = entitys
this.args = args
this.normalizers = []
this.queue = []
}

/**
* Set Normalizers
*
* @param {Function} normalizer
* @param {null|Number} priority
* @return {Object}
*/
set(normalizer, priority = null) {
let property = priority === null ? `queue` : `normalizers`

this[property].push({
normalizer,
priority,
})

return this
}

/**
* Normalize the entities
*
* @return {Array}
*/
async normalize() {
var normalizers = this.getNormalizers()
for (let i = 0; i < normalizers.length; i++) {
this.entitys = await normalizers[i].normalizer(this.entitys, this.args)
}

return this.entitys
}

/**
* Concat the queue and prioritised normalizers
*
* @return {Array}
*/
getNormalizers() {
return _.concat(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use Array.concat() instead of lodash eliminates the need for extra dependency call in this file.

this.normalizers.sort((a, b) => a.priority - b.priority),
this.queue
)
}

}

module.exports = Normalizer