@tomosull/gridsome-source-wordpress 1.4.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +5 -0
- package/README.md +121 -0
- package/index.js +450 -0
- package/package.json +33 -0
package/CHANGELOG.md
ADDED
package/README.md
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
# gridsome-source-wordpress
|
|
2
|
+
|
|
3
|
+
> WordPress source for Gridsome with support for downloading images.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
- `yarn add gridsome-source-wordpress`
|
|
7
|
+
- `npm install gridsome-source-wordpress`
|
|
8
|
+
|
|
9
|
+
## Usage
|
|
10
|
+
|
|
11
|
+
Add `wp-images` to your `.gitignore`
|
|
12
|
+
|
|
13
|
+
```js
|
|
14
|
+
module.exports = {
|
|
15
|
+
plugins: [
|
|
16
|
+
{
|
|
17
|
+
use: 'gridsome-source-wordpress',
|
|
18
|
+
options: {
|
|
19
|
+
baseUrl: 'WEBSITE_URL', // required
|
|
20
|
+
apiBase: 'wp-json',
|
|
21
|
+
typeName: 'WordPress',
|
|
22
|
+
perPage: 100,
|
|
23
|
+
concurrent: 10,
|
|
24
|
+
routes: {
|
|
25
|
+
post: '/:year/:month/:day/:slug',
|
|
26
|
+
post_tag: '/tag/:slug'
|
|
27
|
+
},
|
|
28
|
+
splitPostsIntoFragments: true, // default false
|
|
29
|
+
downloadRemoteImagesFromPosts: true, // default false
|
|
30
|
+
downloadRemoteFeaturedImages: true, // default false
|
|
31
|
+
downloadACFImages: true, // default false
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
]
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Use with Advanced Custom Fields
|
|
39
|
+
|
|
40
|
+
Install the [ACF to REST API](https://github.com/airesvsg/acf-to-rest-api) plugin to make ACF fields available in the GraphQL schema.
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
`downloadACFImages: true` when downloading images, the result will like this object:
|
|
44
|
+
|
|
45
|
+
```
|
|
46
|
+
image: {
|
|
47
|
+
src: ...//GRIDSOME IMAGE OBJECT,
|
|
48
|
+
alt: 'Any description text',
|
|
49
|
+
title: 'Title text of the image'
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Usage: `<g-image :src="image.src" :alt="image.alt" />`
|
|
54
|
+
|
|
55
|
+
## Splitting Posts Into Fragments
|
|
56
|
+
|
|
57
|
+
`splitPostsIntoFragments: true` This will expose the following on posts that you can request via GraphQL:
|
|
58
|
+
|
|
59
|
+
**Query**
|
|
60
|
+
```
|
|
61
|
+
postFragments {
|
|
62
|
+
type
|
|
63
|
+
fragmentData {
|
|
64
|
+
image
|
|
65
|
+
alt
|
|
66
|
+
html
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Each fragment is either of type `img` or `html` so you can render like so:
|
|
72
|
+
|
|
73
|
+
**Render**
|
|
74
|
+
```
|
|
75
|
+
<template v-if="$page.wordPressPost.postFragments">
|
|
76
|
+
<template v-for="(fragment, i) in $page.wordPressPost.postFragments">
|
|
77
|
+
<!-- Fragment is a html block -->
|
|
78
|
+
<template v-if="fragment.type == 'html'">
|
|
79
|
+
<div :key="html-${i}" v-html="fragment.fragmentData.html" class="entry-content"></div>
|
|
80
|
+
</template>
|
|
81
|
+
|
|
82
|
+
<!-- Fragment is a image -->
|
|
83
|
+
<template v-if="fragment.type == 'img' && fragment.fragmentData.image">
|
|
84
|
+
<g-image :key="img-${i}" :src="fragment.fragmentData.image" :alt="fragment.fragmentData.alt"/>
|
|
85
|
+
</template>
|
|
86
|
+
</template>
|
|
87
|
+
</template>
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Caveats
|
|
91
|
+
|
|
92
|
+
**Folders not existing?**
|
|
93
|
+
|
|
94
|
+
Manually create the following directories in your project:
|
|
95
|
+
|
|
96
|
+
```
|
|
97
|
+
/
|
|
98
|
+
.temp/
|
|
99
|
+
downloads/
|
|
100
|
+
wp-images/
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
### Tips
|
|
105
|
+
|
|
106
|
+
**Exclude unnecessary data from ACF fields**
|
|
107
|
+
|
|
108
|
+
Gridsome needs the `Return format` set to `Post Object` for `Post Object` relations in order to resolve references automatically. But Gridsome only need the `post_type` and `id` to set up a working GraphQL reference. Use the filter below to exclude all other fields.
|
|
109
|
+
|
|
110
|
+
```php
|
|
111
|
+
add_filter( 'acf/format_value', function ( $value ) {
|
|
112
|
+
if ( $value instanceof WP_Post ) {
|
|
113
|
+
return [
|
|
114
|
+
'post_type' => $value->post_type,
|
|
115
|
+
'id' => $value->ID,
|
|
116
|
+
];
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return $value;
|
|
120
|
+
}, 100 );
|
|
121
|
+
```
|
package/index.js
ADDED
|
@@ -0,0 +1,450 @@
|
|
|
1
|
+
const pMap = require('p-map')
|
|
2
|
+
const axios = require('axios')
|
|
3
|
+
const fs = require('fs')
|
|
4
|
+
const https = require('https')
|
|
5
|
+
const path = require('path')
|
|
6
|
+
const camelCase = require('camelcase')
|
|
7
|
+
const { mapKeys, isPlainObject, trimEnd, map, find } = require('lodash')
|
|
8
|
+
|
|
9
|
+
const TYPE_AUTHOR = 'author'
|
|
10
|
+
const TYPE_ATTACHEMENT = 'attachment'
|
|
11
|
+
const TMPDIR = '.temp/downloads'
|
|
12
|
+
const DOWNLOAD_DIR = 'wp-images'
|
|
13
|
+
|
|
14
|
+
function mkdirSyncRecursive (absDirectory) {
|
|
15
|
+
const paths = absDirectory.replace(/\/$/, '').split('/')
|
|
16
|
+
paths.splice(0, 1)
|
|
17
|
+
|
|
18
|
+
let dirPath = '/'
|
|
19
|
+
paths.forEach(segment => {
|
|
20
|
+
dirPath += segment + '/'
|
|
21
|
+
if (!fs.existsSync(dirPath)) fs.mkdirSync(dirPath)
|
|
22
|
+
})
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
class WordPressSource {
|
|
26
|
+
static defaultOptions () {
|
|
27
|
+
return {
|
|
28
|
+
baseUrl: '',
|
|
29
|
+
apiBase: 'wp-json',
|
|
30
|
+
perPage: 100,
|
|
31
|
+
concurrent: 10,
|
|
32
|
+
routes: {
|
|
33
|
+
post: '/:slug',
|
|
34
|
+
post_tag: '/tag/:slug',
|
|
35
|
+
category: '/category/:slug',
|
|
36
|
+
author: '/author/:slug'
|
|
37
|
+
},
|
|
38
|
+
typeName: 'WordPress',
|
|
39
|
+
splitPostsIntoFragments: false,
|
|
40
|
+
downloadRemoteImagesFromPosts: false,
|
|
41
|
+
downloadRemoteFeaturedImages: false,
|
|
42
|
+
downloadACFImages: false
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
constructor (api, options) {
|
|
47
|
+
const opts = this.options = { ...WordPressSource.defaultOptions, ...options }
|
|
48
|
+
this.restBases = { posts: {}, taxonomies: {}}
|
|
49
|
+
|
|
50
|
+
if (!opts.typeName) {
|
|
51
|
+
throw new Error(`Missing typeName option.`)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (opts.perPage > 100 || opts.perPage < 1) {
|
|
55
|
+
throw new Error(`${opts.typeName}: perPage cannot be more than 100 or less than 1.`)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const baseUrl = trimEnd(opts.baseUrl, '/')
|
|
59
|
+
|
|
60
|
+
this.client = axios.create({
|
|
61
|
+
baseURL: `${baseUrl}/${opts.apiBase}`
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
this.routes = this.options.routes || {}
|
|
65
|
+
|
|
66
|
+
/* Create image directories */
|
|
67
|
+
mkdirSyncRecursive(path.resolve(DOWNLOAD_DIR))
|
|
68
|
+
mkdirSyncRecursive(path.resolve(TMPDIR))
|
|
69
|
+
this.tmpCount = 0
|
|
70
|
+
|
|
71
|
+
this.slugify = str => api.store.slugify(str).replace(/-([^-]*)$/, '.$1')
|
|
72
|
+
|
|
73
|
+
api.loadSource(async actions => {
|
|
74
|
+
this.store = actions
|
|
75
|
+
|
|
76
|
+
console.log(`Loading data from ${baseUrl}`)
|
|
77
|
+
|
|
78
|
+
await this.getPostTypes(actions)
|
|
79
|
+
await this.getUsers(actions)
|
|
80
|
+
await this.getTaxonomies(actions)
|
|
81
|
+
await this.getPosts(actions)
|
|
82
|
+
})
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
async getPostTypes (actions) {
|
|
86
|
+
const { data } = await this.fetch('wp/v2/types', {}, {})
|
|
87
|
+
const addCollection = actions.addCollection || actions.addContentType
|
|
88
|
+
|
|
89
|
+
for (const type in data) {
|
|
90
|
+
const options = data[type]
|
|
91
|
+
|
|
92
|
+
this.restBases.posts[type] = options.rest_base
|
|
93
|
+
|
|
94
|
+
addCollection({
|
|
95
|
+
typeName: this.createTypeName(type),
|
|
96
|
+
route: this.routes[type] || `/${type}/:slug`
|
|
97
|
+
})
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
async getUsers (actions) {
|
|
102
|
+
const { data } = await this.fetch('wp/v2/users')
|
|
103
|
+
const addCollection = actions.addCollection || actions.addContentType
|
|
104
|
+
|
|
105
|
+
const authors = addCollection({
|
|
106
|
+
typeName: this.createTypeName(TYPE_AUTHOR),
|
|
107
|
+
route: this.routes.author
|
|
108
|
+
})
|
|
109
|
+
|
|
110
|
+
for (const author of data) {
|
|
111
|
+
const fields = this.normalizeFields(author)
|
|
112
|
+
const avatars = mapKeys(author.avatar_urls, (v, key) => `avatar${key}`)
|
|
113
|
+
|
|
114
|
+
authors.addNode({
|
|
115
|
+
...fields,
|
|
116
|
+
id: author.id,
|
|
117
|
+
title: author.name,
|
|
118
|
+
avatars
|
|
119
|
+
})
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
async getTaxonomies (actions) {
|
|
124
|
+
const { data } = await this.fetch('wp/v2/taxonomies', {}, {})
|
|
125
|
+
const addCollection = actions.addCollection || actions.addContentType
|
|
126
|
+
|
|
127
|
+
for (const type in data) {
|
|
128
|
+
const options = data[type]
|
|
129
|
+
const taxonomy = addCollection({
|
|
130
|
+
typeName: this.createTypeName(type),
|
|
131
|
+
route: this.routes[type]
|
|
132
|
+
})
|
|
133
|
+
|
|
134
|
+
this.restBases.taxonomies[type] = options.rest_base
|
|
135
|
+
|
|
136
|
+
const terms = await this.fetchPaged(`wp/v2/${options.rest_base}`)
|
|
137
|
+
|
|
138
|
+
for (const term of terms) {
|
|
139
|
+
taxonomy.addNode({
|
|
140
|
+
id: term.id,
|
|
141
|
+
title: term.name,
|
|
142
|
+
slug: term.slug,
|
|
143
|
+
content: term.description,
|
|
144
|
+
count: term.count
|
|
145
|
+
})
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
extractImagesFromPostHtml (string) {
|
|
151
|
+
const regex = /<img[^>]* src=\"([^\"]*)\" alt=\"([^\"]*)\"[^>]*>/gm
|
|
152
|
+
|
|
153
|
+
const matches = []
|
|
154
|
+
let m
|
|
155
|
+
while ((m = regex.exec(string)) !== null) {
|
|
156
|
+
// This is necessary to avoid infinite loops with zero-width matches
|
|
157
|
+
if (m.index === regex.lastIndex) {
|
|
158
|
+
regex.lastIndex++
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// The result can be accessed through the `m`-variable.
|
|
162
|
+
m.forEach((match, groupIndex) => {
|
|
163
|
+
matches.push({
|
|
164
|
+
url: match[1],
|
|
165
|
+
alt: match[2]
|
|
166
|
+
})
|
|
167
|
+
})
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
return matches
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
async downloadImage (url, destPath, fileName) {
|
|
174
|
+
const imagePath = path.resolve(destPath, fileName)
|
|
175
|
+
|
|
176
|
+
try {
|
|
177
|
+
if (fs.existsSync(imagePath)) return
|
|
178
|
+
} catch (err) {
|
|
179
|
+
console.log(err)
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
const tmpPath = path.resolve(TMPDIR, `${++this.tmpCount}.tmp`)
|
|
183
|
+
|
|
184
|
+
return new Promise(function (resolve, reject) {
|
|
185
|
+
const file = fs.createWriteStream(tmpPath)
|
|
186
|
+
https.get(url, (response) => {
|
|
187
|
+
response.pipe(file)
|
|
188
|
+
file.on('finish', () => {
|
|
189
|
+
file.close()
|
|
190
|
+
fs.rename(tmpPath, imagePath, resolve)
|
|
191
|
+
})
|
|
192
|
+
}).on('error', (err) => {
|
|
193
|
+
console.error(err.message)
|
|
194
|
+
fs.unlinkSync(tmpPath) // Cleanup blank file
|
|
195
|
+
reject(err)
|
|
196
|
+
})
|
|
197
|
+
})
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
processPostFragments (post) {
|
|
201
|
+
const postImages = this.extractImagesFromPostHtml(post)
|
|
202
|
+
|
|
203
|
+
const regex = /<img[^>]* src=\"([^\"]*)\"[^>]*>/
|
|
204
|
+
const fragments = post.split(regex)
|
|
205
|
+
|
|
206
|
+
return map(fragments, (fragment, index) => {
|
|
207
|
+
const image = find(postImages, (image) => { return image.url === fragment })
|
|
208
|
+
if (image && this.options.downloadRemoteImagesFromPosts) {
|
|
209
|
+
const fileName = this.slugify(fragment.split('/').pop())
|
|
210
|
+
const imageData = {
|
|
211
|
+
type: 'img',
|
|
212
|
+
order: index + 1,
|
|
213
|
+
fragmentData: {
|
|
214
|
+
remoteUrl: fragment,
|
|
215
|
+
fileName: fileName,
|
|
216
|
+
image: path.resolve(DOWNLOAD_DIR, fileName),
|
|
217
|
+
alt: image.alt
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
this.downloadImage(
|
|
221
|
+
fragment,
|
|
222
|
+
DOWNLOAD_DIR,
|
|
223
|
+
fileName
|
|
224
|
+
)
|
|
225
|
+
return imageData
|
|
226
|
+
} else {
|
|
227
|
+
return {
|
|
228
|
+
type: 'html',
|
|
229
|
+
order: index + 1,
|
|
230
|
+
fragmentData: {
|
|
231
|
+
html: fragment
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
})
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
async getPosts (actions) {
|
|
239
|
+
const { createReference } = actions
|
|
240
|
+
const getCollection = actions.getCollection || actions.getContentType
|
|
241
|
+
|
|
242
|
+
const AUTHOR_TYPE_NAME = this.createTypeName(TYPE_AUTHOR)
|
|
243
|
+
const ATTACHEMENT_TYPE_NAME = this.createTypeName(TYPE_ATTACHEMENT)
|
|
244
|
+
|
|
245
|
+
for (const type in this.restBases.posts) {
|
|
246
|
+
const restBase = this.restBases.posts[type]
|
|
247
|
+
const typeName = this.createTypeName(type)
|
|
248
|
+
const posts = getCollection(typeName)
|
|
249
|
+
|
|
250
|
+
const data = await this.fetchPaged(`wp/v2/${restBase}?_embed`)
|
|
251
|
+
|
|
252
|
+
for (const post of data) {
|
|
253
|
+
const fields = this.normalizeFields(post)
|
|
254
|
+
fields.author = createReference(AUTHOR_TYPE_NAME, post.author || '0')
|
|
255
|
+
|
|
256
|
+
if (post.type !== TYPE_ATTACHEMENT) {
|
|
257
|
+
fields.featuredMedia = createReference(ATTACHEMENT_TYPE_NAME, post.featured_media)
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// add references if post has any taxonomy rest bases as properties
|
|
261
|
+
for (const type in this.restBases.taxonomies) {
|
|
262
|
+
const propName = this.restBases.taxonomies[type]
|
|
263
|
+
|
|
264
|
+
if (post.hasOwnProperty(propName)) {
|
|
265
|
+
const typeName = this.createTypeName(type)
|
|
266
|
+
const ref = createReference(typeName, post[propName])
|
|
267
|
+
const key = camelCase(propName)
|
|
268
|
+
|
|
269
|
+
fields[key] = ref
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
if (this.options.splitPostsIntoFragments && fields['content']) { fields.postFragments = this.processPostFragments(fields['content']) }
|
|
274
|
+
|
|
275
|
+
// download the featured image
|
|
276
|
+
if (this.options.downloadRemoteFeaturedImages && post._embedded && post._embedded['wp:featuredmedia']) {
|
|
277
|
+
try {
|
|
278
|
+
const featuredImageFileName = this.slugify(post._embedded['wp:featuredmedia']['0'].source_url.split('/').pop())
|
|
279
|
+
await this.downloadImage(
|
|
280
|
+
post._embedded['wp:featuredmedia']['0'].source_url,
|
|
281
|
+
DOWNLOAD_DIR,
|
|
282
|
+
featuredImageFileName
|
|
283
|
+
)
|
|
284
|
+
fields.featuredMediaImage = path.resolve(DOWNLOAD_DIR, featuredImageFileName)
|
|
285
|
+
} catch (err) {
|
|
286
|
+
console.log(err)
|
|
287
|
+
console.log('WARNING - No featured image for post ' + post.slug)
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
posts.addNode({
|
|
292
|
+
...fields,
|
|
293
|
+
id: post.id
|
|
294
|
+
})
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
async fetch (url, params = {}, fallbackData = []) {
|
|
300
|
+
let res
|
|
301
|
+
|
|
302
|
+
try {
|
|
303
|
+
res = await this.client.request({ url, params })
|
|
304
|
+
} catch ({ response, code, config }) {
|
|
305
|
+
if (!response && code) {
|
|
306
|
+
throw new Error(`${code} - ${config.url}`)
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
const { url } = response.config
|
|
310
|
+
const { status } = response.data.data
|
|
311
|
+
|
|
312
|
+
if ([401, 403, 404].includes(status)) {
|
|
313
|
+
console.warn(`Error: Status ${status} - ${url}`)
|
|
314
|
+
return { ...response, data: fallbackData }
|
|
315
|
+
} else {
|
|
316
|
+
throw new Error(`${status} - ${url}`)
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
return res
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
async fetchPaged (path) {
|
|
324
|
+
const { perPage, concurrent } = this.options
|
|
325
|
+
|
|
326
|
+
return new Promise(async (resolve, reject) => {
|
|
327
|
+
let res
|
|
328
|
+
|
|
329
|
+
try {
|
|
330
|
+
res = await this.fetch(path, { per_page: perPage })
|
|
331
|
+
} catch (err) {
|
|
332
|
+
return reject(err)
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
const totalItems = parseInt(res.headers['x-wp-total'], 10)
|
|
336
|
+
const totalPages = parseInt(res.headers['x-wp-totalpages'], 10)
|
|
337
|
+
|
|
338
|
+
try {
|
|
339
|
+
res.data = ensureArrayData(path, res.data)
|
|
340
|
+
} catch (err) {
|
|
341
|
+
return reject(err)
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
if (!totalItems || totalPages <= 1) {
|
|
345
|
+
return resolve(res.data)
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
const queue = []
|
|
349
|
+
|
|
350
|
+
for (let page = 2; page <= totalPages; page++) {
|
|
351
|
+
queue.push({ per_page: perPage, page })
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
await pMap(queue, async params => {
|
|
355
|
+
try {
|
|
356
|
+
const { data } = await this.fetch(path, params)
|
|
357
|
+
res.data.push(...ensureArrayData(path, data))
|
|
358
|
+
} catch (err) {
|
|
359
|
+
console.log(err.message)
|
|
360
|
+
}
|
|
361
|
+
}, { concurrency: concurrent })
|
|
362
|
+
|
|
363
|
+
resolve(res.data)
|
|
364
|
+
})
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
normalizeFields (fields, isACF) {
|
|
368
|
+
const res = {}
|
|
369
|
+
|
|
370
|
+
for (const key in fields) {
|
|
371
|
+
if (key.startsWith('_')) continue // skip links and embeds etc
|
|
372
|
+
res[camelCase(key)] = this.normalizeFieldValue(fields[key], isACF || key === 'acf')
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
return res
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
normalizeFieldValue (value, isACF) {
|
|
379
|
+
if (value === null) return null
|
|
380
|
+
if (value === undefined) return null
|
|
381
|
+
|
|
382
|
+
if (Array.isArray(value)) {
|
|
383
|
+
return value.map(v => this.normalizeFieldValue(v, isACF))
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
if (isPlainObject(value)) {
|
|
387
|
+
if (value.type === 'image' && value.filename && value.url && isACF && this.options.downloadACFImages) {
|
|
388
|
+
const filename = this.slugify(value.filename)
|
|
389
|
+
this.downloadImage(
|
|
390
|
+
value.url,
|
|
391
|
+
DOWNLOAD_DIR,
|
|
392
|
+
filename
|
|
393
|
+
)
|
|
394
|
+
return {
|
|
395
|
+
src: path.resolve(DOWNLOAD_DIR, filename),
|
|
396
|
+
title: value.title,
|
|
397
|
+
alt: value.alt
|
|
398
|
+
}
|
|
399
|
+
} else if (value.post_type && (value.ID || value.id)) {
|
|
400
|
+
const typeName = this.createTypeName(value.post_type)
|
|
401
|
+
const id = value.ID || value.id
|
|
402
|
+
|
|
403
|
+
return this.store.createReference(typeName, id)
|
|
404
|
+
} else if (value.filename && (value.ID || value.id)) {
|
|
405
|
+
const typeName = this.createTypeName(TYPE_ATTACHEMENT)
|
|
406
|
+
const id = value.ID || value.id
|
|
407
|
+
|
|
408
|
+
return this.store.createReference(typeName, id)
|
|
409
|
+
} else if (value.hasOwnProperty('rendered')) {
|
|
410
|
+
return value.rendered
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
return this.normalizeFields(value, isACF)
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
if (isACF && this.options.downloadACFImages && String(value).match(/^https:\/\/.*\/.*\.(jpg|png|svg|jpeg)($|\?)/i)) {
|
|
417
|
+
const filename = this.slugify(value.split('/').pop())
|
|
418
|
+
console.log(`Downloading ${filename}`)
|
|
419
|
+
this.downloadImage(
|
|
420
|
+
value,
|
|
421
|
+
DOWNLOAD_DIR,
|
|
422
|
+
filename
|
|
423
|
+
)
|
|
424
|
+
return path.resolve(DOWNLOAD_DIR, filename)
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
return value
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
createTypeName (name = '') {
|
|
431
|
+
return camelCase(`${this.options.typeName} ${name}`, { pascalCase: true })
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
function ensureArrayData (url, data) {
|
|
436
|
+
if (!Array.isArray(data)) {
|
|
437
|
+
try {
|
|
438
|
+
data = JSON.parse(data)
|
|
439
|
+
} catch (err) {
|
|
440
|
+
throw new Error(
|
|
441
|
+
`Failed to fetch ${url}\n` +
|
|
442
|
+
`Expected JSON response but received:\n` +
|
|
443
|
+
`${data.trim().substring(0, 150)}...\n`
|
|
444
|
+
)
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
return data
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
module.exports = WordPressSource
|
package/package.json
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": "1.4.13",
|
|
3
|
+
"name": "@tomosull/gridsome-source-wordpress",
|
|
4
|
+
"description": "Tomosull Fork of gridsome-source-wordpress 4.13 - WordPress source for Gridsome with image processing support. This fixes minor issues with the original plugin; namely 403 and image alt tags not loading.",
|
|
5
|
+
"homepage": "https://github.com/gridsome/gridsome/tree/master/packages/source-wordpress#readme",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git"
|
|
8
|
+
},
|
|
9
|
+
"main": "index.js",
|
|
10
|
+
"keywords": [
|
|
11
|
+
"tomosull",
|
|
12
|
+
"gridsome",
|
|
13
|
+
"wordpress"
|
|
14
|
+
],
|
|
15
|
+
"dependencies": {
|
|
16
|
+
"axios": "^0.19.0",
|
|
17
|
+
"camelcase": "^5.0.0",
|
|
18
|
+
"lodash": "^4.17.11",
|
|
19
|
+
"p-map": "^1.2.0"
|
|
20
|
+
},
|
|
21
|
+
"publishConfig": {
|
|
22
|
+
"access": "public"
|
|
23
|
+
},
|
|
24
|
+
"engines": {
|
|
25
|
+
"node": ">=8.3"
|
|
26
|
+
},
|
|
27
|
+
"devDependencies": {},
|
|
28
|
+
"scripts": {
|
|
29
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
30
|
+
},
|
|
31
|
+
"author": "Tom O'Sullivan",
|
|
32
|
+
"license": "ISC"
|
|
33
|
+
}
|