Skip to content

Commit 0501ed3

Browse files
authored
feat(gatsby-source-wordpress): MediaItem.excludeFieldNames / auto exclude interface types that have no fields (#37062)
* allow MediaItem type to use excludeFieldNames option * make sure cached media item nodes always return the MediaItem node, not File nodes if those are cached * use get type settings helper instead of accessing settings on options * auto exclude interface types that have no fields due to an implementing type excluding all of it's fields * this should've been excluded before! Fixed now * update comment * use Map for caching instead of object properties * exclude MediaItem.template field in tests * remove debug code
1 parent 7544045 commit 0501ed3

File tree

12 files changed

+143
-56
lines changed

12 files changed

+143
-56
lines changed

integration-tests/gatsby-source-wordpress/__tests__/__snapshots__/index.js.snap

-9
Original file line numberDiff line numberDiff line change
@@ -1493,7 +1493,6 @@ Array [
14931493
Object {
14941494
"fields": Array [
14951495
"avatar",
1496-
"databaseId",
14971496
"id",
14981497
"name",
14991498
"url",
@@ -1544,7 +1543,6 @@ Array [
15441543
"modifiedGmt",
15451544
"slug",
15461545
"status",
1547-
"template",
15481546
"uri",
15491547
"nodeType",
15501548
"parent",
@@ -5783,7 +5781,6 @@ Array [
57835781
"sourceUrl",
57845782
"srcSet",
57855783
"status",
5786-
"template",
57875784
"title",
57885785
"uri",
57895786
"nodeType",
@@ -6301,12 +6298,6 @@ Array [
63016298
],
63026299
"name": "WpNodeWithRevisionsToContentNodeConnectionEdge",
63036300
},
6304-
Object {
6305-
"fields": Array [
6306-
"template",
6307-
],
6308-
"name": "WpNodeWithTemplate",
6309-
},
63106301
Object {
63116302
"fields": Array [
63126303
"title",

integration-tests/gatsby-source-wordpress/gatsby-config.js

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ require(`dotenv`).config({
55
console.log(`Sourcing data from ` + process.env.WPGRAPHQL_URL)
66

77
const mediaItemTypeSettings = {
8+
excludeFieldNames: [`template`],
89
localFile: {
910
excludeByMimeTypes: ["video/mp4"],
1011
/**

packages/gatsby-source-wordpress/docs/plugin-options.md

+21
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@
6363
- [type.\_\_all.beforeChangeNode](#type__allbeforechangenode)
6464
- [type.RootQuery](#typerootquery)
6565
- [type.MediaItem](#typemediaitem)
66+
- [type.MediaItem.excludeFieldNames](#typemediaitemexcludefieldnames)
6667
- [type.MediaItem.placeholderSizeName](#typemediaitemplaceholdersizename)
6768
- [type.MediaItem.createFileNodes](#typemediaitemcreatefilenodes)
6869
- [type.MediaItem.lazyNodes](#typemediaitemlazynodes)
@@ -1230,6 +1231,26 @@ A special type which is applied to any non-node root fields that are ingested an
12301231

12311232
**Field type**: `Object`
12321233

1234+
#### type.MediaItem.excludeFieldNames
1235+
1236+
Excludes fields on the MediaItem type by field name.
1237+
1238+
**Field type**: `Array`
1239+
1240+
```js
1241+
{
1242+
resolve: `gatsby-source-wordpress`,
1243+
options: {
1244+
type: {
1245+
MediaItem: {
1246+
excludeFieldNames: [`dateGmt`, `parent`],
1247+
},
1248+
},
1249+
},
1250+
}
1251+
1252+
```
1253+
12331254
#### type.MediaItem.placeholderSizeName
12341255

12351256
This option allows you to choose the placeholder size used in the new Gatsby image service (currently in ALPHA/BETA) for the small placeholder image. Please make this image size very small for better performance. 20px or smaller width is recommended. To use, create a new image size in WP and name it "gatsby-image-placeholder" (or the name that you pass to this option) and that new size will be used automatically for placeholder images in the Gatsby build.

packages/gatsby-source-wordpress/src/steps/create-schema-customization/build-types.js

+14-23
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
fieldOfTypeWasFetched,
77
getTypeSettingsByType,
88
filterTypeDefinition,
9+
getTypesThatImplementInterfaceType,
910
} from "./helpers"
1011

1112
const unionType = typeBuilderApi => {
@@ -47,38 +48,24 @@ const unionType = typeBuilderApi => {
4748
}
4849

4950
const interfaceType = typeBuilderApi => {
50-
const { type, schema, gatsbyNodeTypes, fieldAliases, fieldBlacklist } =
51-
typeBuilderApi
51+
const { type, schema } = typeBuilderApi
5252

5353
const state = store.getState()
54-
const { ingestibles, typeMap } = state.remoteSchema
54+
const { ingestibles } = state.remoteSchema
5555
const { nodeInterfaceTypes } = ingestibles
5656

57-
const allTypes = typeMap.values()
58-
59-
const implementingTypes = Array.from(allTypes)
60-
.filter(
61-
({ interfaces }) =>
62-
interfaces &&
63-
// find types that implement this interface type
64-
interfaces.find(singleInterface => singleInterface.name === type.name)
65-
)
66-
.map(type => typeMap.get(type.name))
67-
.filter(
68-
type =>
69-
type.kind !== `UNION` ||
70-
// if this is a union type, make sure the union type has one or more member types, otherwise schema customization will throw an error
71-
(!!type.possibleTypes && !!type.possibleTypes.length)
72-
)
57+
const implementingTypes = getTypesThatImplementInterfaceType(type)
7358

7459
const transformedFields = transformFields({
7560
parentInterfacesImplementingTypes: implementingTypes,
61+
parentType: type,
7662
fields: type.fields,
77-
gatsbyNodeTypes,
78-
fieldAliases,
79-
fieldBlacklist,
8063
})
8164

65+
if (!transformedFields) {
66+
return null
67+
}
68+
8269
let typeDef = {
8370
name: buildTypeName(type.name),
8471
fields: transformedFields,
@@ -144,7 +131,11 @@ const objectType = typeBuilderApi => {
144131
.filter(interfaceType => {
145132
const interfaceTypeSettings = getTypeSettingsByType(interfaceType)
146133

147-
return !interfaceTypeSettings.exclude && fieldOfTypeWasFetched(type)
134+
return (
135+
!interfaceTypeSettings.exclude &&
136+
fieldOfTypeWasFetched(type) &&
137+
fieldOfTypeWasFetched(interfaceType)
138+
)
148139
})
149140
.map(({ name }) => buildTypeName(name))
150141
}

packages/gatsby-source-wordpress/src/steps/create-schema-customization/helpers.js

+40-4
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,38 @@ export const fieldOfTypeWasFetched = type => {
5959
return typeWasFetched
6060
}
6161

62+
const implementingTypeCache = new Map()
63+
64+
export const getTypesThatImplementInterfaceType = type => {
65+
if (implementingTypeCache.has(type.name)) {
66+
return implementingTypeCache.get(type.name)
67+
}
68+
69+
const state = store.getState()
70+
const { typeMap } = state.remoteSchema
71+
72+
const allTypes = typeMap.values()
73+
74+
const implementingTypes = Array.from(allTypes)
75+
.filter(
76+
({ interfaces }) =>
77+
interfaces &&
78+
// find types that implement this interface type
79+
interfaces.find(singleInterface => singleInterface.name === type.name)
80+
)
81+
.map(type => typeMap.get(type.name))
82+
.filter(
83+
type =>
84+
type.kind !== `UNION` ||
85+
// if this is a union type, make sure the union type has one or more member types, otherwise schema customization will throw an error
86+
(!!type.possibleTypes && !!type.possibleTypes.length)
87+
)
88+
89+
implementingTypeCache.set(type.name, implementingTypes)
90+
91+
return implementingTypes
92+
}
93+
6294
const supportedScalars = [
6395
`Int`,
6496
`Float`,
@@ -84,7 +116,7 @@ export const typeIsASupportedScalar = type => {
84116
return supportedScalars.includes(findTypeName(type))
85117
}
86118

87-
const typeSettingCache = {}
119+
const typeSettingCache = new Map()
88120

89121
// retrieves plugin settings for the provided type
90122
export const getTypeSettingsByType = type => {
@@ -94,7 +126,11 @@ export const getTypeSettingsByType = type => {
94126

95127
const typeName = findTypeName(type)
96128

97-
const cachedTypeSettings = typeSettingCache[typeName]
129+
if (!typeName) {
130+
return {}
131+
}
132+
133+
const cachedTypeSettings = typeSettingCache.get(typeName)
98134

99135
if (cachedTypeSettings) {
100136
return cachedTypeSettings
@@ -116,12 +152,12 @@ export const getTypeSettingsByType = type => {
116152
if (typeSettings) {
117153
const mergedSettings = merge(__allTypeSetting, typeSettings)
118154

119-
typeSettingCache[typeName] = mergedSettings
155+
typeSettingCache.set(typeName, mergedSettings)
120156

121157
return mergedSettings
122158
}
123159

124-
typeSettingCache[typeName] = __allTypeSetting
160+
typeSettingCache.set(typeName, __allTypeSetting)
125161

126162
return __allTypeSetting
127163
}

packages/gatsby-source-wordpress/src/steps/create-schema-customization/index.js

+1-2
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,7 @@ const customizeSchema = async ({ actions, schema, store: gatsbyStore }) => {
6262
break
6363
case `SCALAR`:
6464
/**
65-
* custom scalar types aren't imlemented currently.
66-
* @todo make this hookable so sub-plugins or plugin options can add custom scalar support.
65+
* custom scalar types aren't supported.
6766
*/
6867
break
6968
}

packages/gatsby-source-wordpress/src/steps/create-schema-customization/transform-fields/index.js

+9-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { fieldTransformers } from "./field-transformers"
2+
import { getGatsbyNodeTypeNames } from "../../source-nodes/fetch-nodes/fetch-nodes"
23
import store from "~/store"
34

45
import {
@@ -88,19 +89,19 @@ const excludeField = ({
8889
* with proper node linking and type namespacing
8990
* also filters out unusable fields and types
9091
*/
91-
9292
export const transformFields = ({
9393
fields,
94-
fieldAliases,
95-
fieldBlacklist,
9694
parentType,
9795
parentInterfacesImplementingTypes,
98-
gatsbyNodeTypes,
9996
}) => {
10097
if (!fields || !fields.length) {
10198
return null
10299
}
103100

101+
const gatsbyNodeTypes = getGatsbyNodeTypeNames()
102+
103+
const { fieldAliases, fieldBlacklist } = store.getState().remoteSchema
104+
104105
const parentTypeSettings = getTypeSettingsByType(parentType)
105106

106107
const parentInterfacesImplementingTypeSettings =
@@ -197,5 +198,9 @@ export const transformFields = ({
197198
return fieldsObject
198199
}, {})
199200

201+
if (!Object.keys(transformedFields).length) {
202+
return null
203+
}
204+
200205
return transformedFields
201206
}

packages/gatsby-source-wordpress/src/steps/declare-plugin-options-schema.js

+14
Original file line numberDiff line numberDiff line change
@@ -765,6 +765,20 @@ When using this option, be sure to gitignore the wordpress-cache directory in th
765765
`),
766766
}),
767767
MediaItem: Joi.object({
768+
excludeFieldNames: Joi.array()
769+
.items(Joi.string())
770+
.allow(null)
771+
.allow(false)
772+
.description(`Excludes fields on the MediaItem type by field name.`)
773+
.meta({
774+
example: wrapOptions(`
775+
type: {
776+
MediaItem: {
777+
excludeFieldNames: [\`dateGmt\`, \`parent\`],
778+
},
779+
},
780+
`),
781+
}),
768782
placeholderSizeName: Joi.string()
769783
.default(`gatsby-image-placeholder`)
770784
.description(

packages/gatsby-source-wordpress/src/steps/ingest-remote-schema/build-queries-from-introspection/recursively-transform-fields.js

-3
Original file line numberDiff line numberDiff line change
@@ -542,11 +542,8 @@ const transformFields = ({
542542
?.filter(
543543
field =>
544544
!fieldIsExcludedOnParentType({
545-
pluginOptions,
546545
field,
547546
parentType,
548-
mainType,
549-
parentField,
550547
}) &&
551548
!fieldIsExcludedOnAll({
552549
pluginOptions,

packages/gatsby-source-wordpress/src/steps/ingest-remote-schema/identify-and-store-ingestable-types.js

+22-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
import store from "~/store"
22
import { typeIsExcluded } from "~/steps/ingest-remote-schema/is-excluded"
33
import { typeIsABuiltInScalar } from "../create-schema-customization/helpers"
4-
import { findTypeName } from "~/steps/create-schema-customization/helpers"
4+
import {
5+
findTypeName,
6+
getTypesThatImplementInterfaceType,
7+
} from "~/steps/create-schema-customization/helpers"
8+
import { transformFields } from "~/steps/create-schema-customization/transform-fields"
59
import { getPersistentCache } from "~/utils/cache"
610

711
const identifyAndStoreIngestableFieldsAndTypes = async () => {
@@ -46,6 +50,23 @@ const identifyAndStoreIngestableFieldsAndTypes = async () => {
4650
continue
4751
}
4852

53+
if (!interfaceType.fields) {
54+
continue
55+
}
56+
57+
const typesThatImplementInterface =
58+
getTypesThatImplementInterfaceType(interfaceType)
59+
60+
const shouldSkipInterfaceType = !transformFields({
61+
fields: interfaceType.fields,
62+
parentType: interfaceType,
63+
parentInterfacesImplementingTypes: typesThatImplementInterface,
64+
})
65+
66+
if (shouldSkipInterfaceType && interfaceType.name !== `Node`) {
67+
continue
68+
}
69+
4970
store.dispatch.remoteSchema.addFetchedType(interfaceType)
5071

5172
if (interfaceType.fields) {

packages/gatsby-source-wordpress/src/steps/ingest-remote-schema/is-excluded.js

+11-9
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
import store from "~/store"
2-
import { findTypeName } from "~/steps/create-schema-customization/helpers"
2+
import {
3+
findTypeName,
4+
getTypeSettingsByType,
5+
} from "~/steps/create-schema-customization/helpers"
36

47
const typeIsExcluded = ({ pluginOptions, typeName }) =>
58
pluginOptions &&
@@ -15,9 +18,7 @@ const fieldIsExcludedOnAll = ({ pluginOptions, field }) => {
1518
return !!allFieldSettings?.excludeFieldNames?.includes(field?.name)
1619
}
1720

18-
const fieldIsExcludedOnParentType = ({ pluginOptions, field, parentType }) => {
19-
const allTypeSettings = pluginOptions.type
20-
21+
const fieldIsExcludedOnParentType = ({ field, parentType }) => {
2122
const state = store.getState()
2223
const { typeMap } = state.remoteSchema
2324

@@ -27,15 +28,16 @@ const fieldIsExcludedOnParentType = ({ pluginOptions, field, parentType }) => {
2728
field => field.name === `nodes`
2829
)
2930

30-
const parentTypeNodesFieldTypeName = findTypeName(parentTypeNodesField?.type)
31+
const parentTypeNameSettings = getTypeSettingsByType(parentType)
32+
const parentTypeNodesFieldTypeNameSettings = getTypeSettingsByType(
33+
parentTypeNodesField?.type
34+
)
3135

3236
const fieldIsExcludedOnParentType =
3337
// if this field is excluded on either the parent type
34-
allTypeSettings[parentType?.name]?.excludeFieldNames?.includes(
35-
field?.name
36-
) ||
38+
parentTypeNameSettings?.excludeFieldNames?.includes(field?.name) ||
3739
// or the parent type has a "nodes" field and that type has this field excluded
38-
allTypeSettings[parentTypeNodesFieldTypeName]?.excludeFieldNames?.includes(
40+
parentTypeNodesFieldTypeNameSettings?.excludeFieldNames?.includes(
3941
field?.name
4042
)
4143

0 commit comments

Comments
 (0)