sanity-plugin-seofields 1.0.6 → 1.0.7
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/README.md +6 -6
- package/dist/index.d.mts +70 -12
- package/dist/index.d.ts +70 -12
- package/dist/index.js +149 -36
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +149 -36
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/components/SeoPreview.tsx +31 -3
- package/src/plugin.ts +58 -4
- package/src/schemas/index.ts +17 -4
- package/src/schemas/types/openGraph/index.ts +89 -84
- package/src/schemas/types/twitter/index.ts +82 -65
- package/src/types.ts +3 -1
- package/src/utils/fieldsUtils.ts +72 -4
- package/src/utils/utils.ts +9 -0
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
[](https://badge.fury.io/js/sanity-plugin-seofields)
|
|
4
4
|
[](https://opensource.org/licenses/MIT)
|
|
5
5
|
|
|
6
|
-
A comprehensive Sanity Studio v3 plugin to manage SEO fields like meta titles, descriptions, Open Graph tags, and Twitter Cards for structured, search-optimized content.
|
|
6
|
+
A comprehensive Sanity Studio v3 plugin to manage SEO fields like meta titles, descriptions, Open Graph tags, and X (Formerly Twitter) Cards for structured, search-optimized content.
|
|
7
7
|
|
|
8
8
|
## ✨ Features
|
|
9
9
|
|
|
@@ -264,7 +264,7 @@ seofields({
|
|
|
264
264
|
```
|
|
265
265
|
|
|
266
266
|
This is particularly useful when you want to:
|
|
267
|
-
- Manage sitewide settings (like site name and
|
|
267
|
+
- Manage sitewide settings (like site name and X handle) in a dedicated Site Settings document
|
|
268
268
|
- Simplify the editing experience by hiding fields that aren't relevant for certain content types
|
|
269
269
|
- Create different SEO workflows for different content types
|
|
270
270
|
|
|
@@ -302,12 +302,12 @@ This is particularly useful when you want to:
|
|
|
302
302
|
- **Large Image**: Minimum 280x150px
|
|
303
303
|
- **Required**: Alt text for accessibility
|
|
304
304
|
|
|
305
|
-
#### Twitter Card Creator
|
|
305
|
+
#### X (Formerly Twitter) Card Creator
|
|
306
306
|
|
|
307
|
-
- **Purpose**: Attribution to content creator on Twitter
|
|
308
|
-
- **Format**:
|
|
307
|
+
- **Purpose**: Attribution to content creator on X (formerly Twitter)
|
|
308
|
+
- **Format**: X handle with @ symbol (e.g., @creator)
|
|
309
309
|
- **Usage**: Identifies the individual author of the content
|
|
310
|
-
- **Best Practice**: Use actual
|
|
310
|
+
- **Best Practice**: Use actual X handles for proper attribution
|
|
311
311
|
|
|
312
312
|
## 💻 TypeScript Usage
|
|
313
313
|
|
package/dist/index.d.mts
CHANGED
|
@@ -2,9 +2,15 @@ import {ObjectDefinition} from 'sanity'
|
|
|
2
2
|
import {Plugin as Plugin_2} from 'sanity'
|
|
3
3
|
import {PreviewConfig} from 'sanity'
|
|
4
4
|
|
|
5
|
-
export declare type AllFieldKeys = SeoFieldKeys |
|
|
5
|
+
export declare type AllFieldKeys = SeoFieldKeys | openGraphFieldKeys | twitterFieldKeys
|
|
6
6
|
|
|
7
7
|
export declare function allSchemas(config?: SeoFieldsPluginConfig): (
|
|
8
|
+
| ({
|
|
9
|
+
type: 'object'
|
|
10
|
+
name: 'twitter'
|
|
11
|
+
} & Omit<ObjectDefinition, 'preview'> & {
|
|
12
|
+
preview?: PreviewConfig<Record<string, string>, Record<never, any>> | undefined
|
|
13
|
+
})
|
|
8
14
|
| ({
|
|
9
15
|
type: 'object'
|
|
10
16
|
name: 'seoFields'
|
|
@@ -36,12 +42,6 @@ export declare function allSchemas(config?: SeoFieldsPluginConfig): (
|
|
|
36
42
|
} & Omit<ObjectDefinition, 'preview'> & {
|
|
37
43
|
preview?: PreviewConfig<Record<string, string>, Record<never, any>> | undefined
|
|
38
44
|
})
|
|
39
|
-
| ({
|
|
40
|
-
type: 'object'
|
|
41
|
-
name: 'twitter'
|
|
42
|
-
} & Omit<ObjectDefinition, 'preview'> & {
|
|
43
|
-
preview?: PreviewConfig<Record<string, string>, Record<never, any>> | undefined
|
|
44
|
-
})
|
|
45
45
|
| ({
|
|
46
46
|
type: 'object'
|
|
47
47
|
name: 'robots'
|
|
@@ -106,6 +106,16 @@ export declare const metaTagSchema: {
|
|
|
106
106
|
preview?: PreviewConfig<Record<string, string>, Record<never, any>> | undefined
|
|
107
107
|
}
|
|
108
108
|
|
|
109
|
+
export declare type openGraphFieldKeys =
|
|
110
|
+
| 'openGraphUrl'
|
|
111
|
+
| 'openGraphTitle'
|
|
112
|
+
| 'openGraphDescription'
|
|
113
|
+
| 'openGraphSiteName'
|
|
114
|
+
| 'openGraphType'
|
|
115
|
+
| 'openGraphImageType'
|
|
116
|
+
| 'openGraphImage'
|
|
117
|
+
| 'openGraphImageUrl'
|
|
118
|
+
|
|
109
119
|
export declare function openGraphSchema(config?: SeoFieldsPluginConfig): {
|
|
110
120
|
type: 'object'
|
|
111
121
|
name: 'openGraph'
|
|
@@ -120,7 +130,7 @@ export declare interface OpenGraphSettings {
|
|
|
120
130
|
siteName?: string
|
|
121
131
|
type?: 'website' | 'article' | 'profile' | 'book' | 'music' | 'video' | 'product'
|
|
122
132
|
imageType?: 'upload' | 'url'
|
|
123
|
-
image?:
|
|
133
|
+
image?: SanityImageWithAlt
|
|
124
134
|
imageUrl?: string
|
|
125
135
|
}
|
|
126
136
|
|
|
@@ -192,14 +202,52 @@ declare const seofields: Plugin_2<void | SeoFieldsPluginConfig>
|
|
|
192
202
|
export default seofields
|
|
193
203
|
|
|
194
204
|
export declare interface SeoFieldsPluginConfig {
|
|
195
|
-
|
|
205
|
+
/**
|
|
206
|
+
* Enable or configure the SEO preview feature.
|
|
207
|
+
* If set to `true`, the SEO preview will be enabled with default settings.
|
|
208
|
+
* If set to an object, you can provide a custom prefix function to modify the URL prefix in the preview.
|
|
209
|
+
* The prefix function receives the current document as an argument and should return a string.
|
|
210
|
+
* Example:
|
|
211
|
+
* ```
|
|
212
|
+
* seoPreview: {
|
|
213
|
+
* prefix: (doc) => `/${doc.slug?.current || 'untitled'}`
|
|
214
|
+
* }
|
|
215
|
+
* ```
|
|
216
|
+
*/
|
|
217
|
+
seoPreview?:
|
|
218
|
+
| boolean
|
|
219
|
+
| {
|
|
220
|
+
prefix?: (
|
|
221
|
+
doc: {
|
|
222
|
+
_type?: string
|
|
223
|
+
} & Record<string, unknown>,
|
|
224
|
+
) => string
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* A mapping of field keys to their configuration settings.
|
|
228
|
+
* This allows customization of field titles and descriptions.
|
|
229
|
+
* For example, to change the title of the 'title' field:
|
|
230
|
+
*/
|
|
196
231
|
fieldOverrides?: {
|
|
197
|
-
[key in
|
|
232
|
+
[key in AllFieldKeys]?: SeoFieldConfig
|
|
198
233
|
}
|
|
234
|
+
/**
|
|
235
|
+
* A mapping of document types to field visibility configurations.
|
|
236
|
+
* This allows you to specify which fields should be hidden for specific document types.
|
|
237
|
+
*/
|
|
199
238
|
fieldVisibility?: {
|
|
200
239
|
[postType: string]: FieldVisibilityConfig
|
|
201
240
|
}
|
|
241
|
+
/**
|
|
242
|
+
* A list of fields that should be hidden by default in all document types.
|
|
243
|
+
* This can be overridden by specific document type settings in `fieldVisibility`.
|
|
244
|
+
*/
|
|
202
245
|
defaultHiddenFields?: AllFieldKeys[]
|
|
246
|
+
/**
|
|
247
|
+
* The base URL of your website, used for generating full URLs in the SEO preview.
|
|
248
|
+
* Defaults to 'https://www.example.com' if not provided.
|
|
249
|
+
*/
|
|
250
|
+
baseUrl?: string
|
|
203
251
|
}
|
|
204
252
|
|
|
205
253
|
export declare function seoFieldsSchema(config?: SeoFieldsPluginConfig): {
|
|
@@ -232,17 +280,27 @@ export declare interface SeoValidationRules {
|
|
|
232
280
|
}
|
|
233
281
|
}
|
|
234
282
|
|
|
235
|
-
export declare type SitewideFieldKeys = 'openGraphSiteName' | 'twitterSite'
|
|
236
|
-
|
|
237
283
|
export declare interface TwitterCardSettings {
|
|
238
284
|
_type: 'twitter'
|
|
239
285
|
card?: 'summary' | 'summary_large_image' | 'app' | 'player'
|
|
240
286
|
site?: string
|
|
241
287
|
title?: string
|
|
242
288
|
description?: string
|
|
289
|
+
imageType?: 'upload' | 'url'
|
|
243
290
|
image?: SanityImageWithAlt
|
|
291
|
+
imageUrl?: string
|
|
244
292
|
}
|
|
245
293
|
|
|
294
|
+
export declare type twitterFieldKeys =
|
|
295
|
+
| 'twitterCard'
|
|
296
|
+
| 'twitterSite'
|
|
297
|
+
| 'twitterCreator'
|
|
298
|
+
| 'twitterTitle'
|
|
299
|
+
| 'twitterDescription'
|
|
300
|
+
| 'twitterImageType'
|
|
301
|
+
| 'twitterImage'
|
|
302
|
+
| 'twitterImageUrl'
|
|
303
|
+
|
|
246
304
|
export declare function twitterSchema(config?: SeoFieldsPluginConfig): {
|
|
247
305
|
type: 'object'
|
|
248
306
|
name: 'twitter'
|
package/dist/index.d.ts
CHANGED
|
@@ -2,9 +2,15 @@ import {ObjectDefinition} from 'sanity'
|
|
|
2
2
|
import {Plugin as Plugin_2} from 'sanity'
|
|
3
3
|
import {PreviewConfig} from 'sanity'
|
|
4
4
|
|
|
5
|
-
export declare type AllFieldKeys = SeoFieldKeys |
|
|
5
|
+
export declare type AllFieldKeys = SeoFieldKeys | openGraphFieldKeys | twitterFieldKeys
|
|
6
6
|
|
|
7
7
|
export declare function allSchemas(config?: SeoFieldsPluginConfig): (
|
|
8
|
+
| ({
|
|
9
|
+
type: 'object'
|
|
10
|
+
name: 'twitter'
|
|
11
|
+
} & Omit<ObjectDefinition, 'preview'> & {
|
|
12
|
+
preview?: PreviewConfig<Record<string, string>, Record<never, any>> | undefined
|
|
13
|
+
})
|
|
8
14
|
| ({
|
|
9
15
|
type: 'object'
|
|
10
16
|
name: 'seoFields'
|
|
@@ -36,12 +42,6 @@ export declare function allSchemas(config?: SeoFieldsPluginConfig): (
|
|
|
36
42
|
} & Omit<ObjectDefinition, 'preview'> & {
|
|
37
43
|
preview?: PreviewConfig<Record<string, string>, Record<never, any>> | undefined
|
|
38
44
|
})
|
|
39
|
-
| ({
|
|
40
|
-
type: 'object'
|
|
41
|
-
name: 'twitter'
|
|
42
|
-
} & Omit<ObjectDefinition, 'preview'> & {
|
|
43
|
-
preview?: PreviewConfig<Record<string, string>, Record<never, any>> | undefined
|
|
44
|
-
})
|
|
45
45
|
| ({
|
|
46
46
|
type: 'object'
|
|
47
47
|
name: 'robots'
|
|
@@ -106,6 +106,16 @@ export declare const metaTagSchema: {
|
|
|
106
106
|
preview?: PreviewConfig<Record<string, string>, Record<never, any>> | undefined
|
|
107
107
|
}
|
|
108
108
|
|
|
109
|
+
export declare type openGraphFieldKeys =
|
|
110
|
+
| 'openGraphUrl'
|
|
111
|
+
| 'openGraphTitle'
|
|
112
|
+
| 'openGraphDescription'
|
|
113
|
+
| 'openGraphSiteName'
|
|
114
|
+
| 'openGraphType'
|
|
115
|
+
| 'openGraphImageType'
|
|
116
|
+
| 'openGraphImage'
|
|
117
|
+
| 'openGraphImageUrl'
|
|
118
|
+
|
|
109
119
|
export declare function openGraphSchema(config?: SeoFieldsPluginConfig): {
|
|
110
120
|
type: 'object'
|
|
111
121
|
name: 'openGraph'
|
|
@@ -120,7 +130,7 @@ export declare interface OpenGraphSettings {
|
|
|
120
130
|
siteName?: string
|
|
121
131
|
type?: 'website' | 'article' | 'profile' | 'book' | 'music' | 'video' | 'product'
|
|
122
132
|
imageType?: 'upload' | 'url'
|
|
123
|
-
image?:
|
|
133
|
+
image?: SanityImageWithAlt
|
|
124
134
|
imageUrl?: string
|
|
125
135
|
}
|
|
126
136
|
|
|
@@ -192,14 +202,52 @@ declare const seofields: Plugin_2<void | SeoFieldsPluginConfig>
|
|
|
192
202
|
export default seofields
|
|
193
203
|
|
|
194
204
|
export declare interface SeoFieldsPluginConfig {
|
|
195
|
-
|
|
205
|
+
/**
|
|
206
|
+
* Enable or configure the SEO preview feature.
|
|
207
|
+
* If set to `true`, the SEO preview will be enabled with default settings.
|
|
208
|
+
* If set to an object, you can provide a custom prefix function to modify the URL prefix in the preview.
|
|
209
|
+
* The prefix function receives the current document as an argument and should return a string.
|
|
210
|
+
* Example:
|
|
211
|
+
* ```
|
|
212
|
+
* seoPreview: {
|
|
213
|
+
* prefix: (doc) => `/${doc.slug?.current || 'untitled'}`
|
|
214
|
+
* }
|
|
215
|
+
* ```
|
|
216
|
+
*/
|
|
217
|
+
seoPreview?:
|
|
218
|
+
| boolean
|
|
219
|
+
| {
|
|
220
|
+
prefix?: (
|
|
221
|
+
doc: {
|
|
222
|
+
_type?: string
|
|
223
|
+
} & Record<string, unknown>,
|
|
224
|
+
) => string
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* A mapping of field keys to their configuration settings.
|
|
228
|
+
* This allows customization of field titles and descriptions.
|
|
229
|
+
* For example, to change the title of the 'title' field:
|
|
230
|
+
*/
|
|
196
231
|
fieldOverrides?: {
|
|
197
|
-
[key in
|
|
232
|
+
[key in AllFieldKeys]?: SeoFieldConfig
|
|
198
233
|
}
|
|
234
|
+
/**
|
|
235
|
+
* A mapping of document types to field visibility configurations.
|
|
236
|
+
* This allows you to specify which fields should be hidden for specific document types.
|
|
237
|
+
*/
|
|
199
238
|
fieldVisibility?: {
|
|
200
239
|
[postType: string]: FieldVisibilityConfig
|
|
201
240
|
}
|
|
241
|
+
/**
|
|
242
|
+
* A list of fields that should be hidden by default in all document types.
|
|
243
|
+
* This can be overridden by specific document type settings in `fieldVisibility`.
|
|
244
|
+
*/
|
|
202
245
|
defaultHiddenFields?: AllFieldKeys[]
|
|
246
|
+
/**
|
|
247
|
+
* The base URL of your website, used for generating full URLs in the SEO preview.
|
|
248
|
+
* Defaults to 'https://www.example.com' if not provided.
|
|
249
|
+
*/
|
|
250
|
+
baseUrl?: string
|
|
203
251
|
}
|
|
204
252
|
|
|
205
253
|
export declare function seoFieldsSchema(config?: SeoFieldsPluginConfig): {
|
|
@@ -232,17 +280,27 @@ export declare interface SeoValidationRules {
|
|
|
232
280
|
}
|
|
233
281
|
}
|
|
234
282
|
|
|
235
|
-
export declare type SitewideFieldKeys = 'openGraphSiteName' | 'twitterSite'
|
|
236
|
-
|
|
237
283
|
export declare interface TwitterCardSettings {
|
|
238
284
|
_type: 'twitter'
|
|
239
285
|
card?: 'summary' | 'summary_large_image' | 'app' | 'player'
|
|
240
286
|
site?: string
|
|
241
287
|
title?: string
|
|
242
288
|
description?: string
|
|
289
|
+
imageType?: 'upload' | 'url'
|
|
243
290
|
image?: SanityImageWithAlt
|
|
291
|
+
imageUrl?: string
|
|
244
292
|
}
|
|
245
293
|
|
|
294
|
+
export declare type twitterFieldKeys =
|
|
295
|
+
| 'twitterCard'
|
|
296
|
+
| 'twitterSite'
|
|
297
|
+
| 'twitterCreator'
|
|
298
|
+
| 'twitterTitle'
|
|
299
|
+
| 'twitterDescription'
|
|
300
|
+
| 'twitterImageType'
|
|
301
|
+
| 'twitterImage'
|
|
302
|
+
| 'twitterImageUrl'
|
|
303
|
+
|
|
246
304
|
export declare function twitterSchema(config?: SeoFieldsPluginConfig): {
|
|
247
305
|
type: 'object'
|
|
248
306
|
name: 'twitter'
|
package/dist/index.js
CHANGED
|
@@ -227,13 +227,13 @@ const stopWords = ["the", "a", "an", "and", "or", "but"], hasMatchingKeyword = (
|
|
|
227
227
|
] }, item.text)) })
|
|
228
228
|
] });
|
|
229
229
|
}, SeoPreview = (props) => {
|
|
230
|
-
const { path } = props, parent = sanity.useFormValue([path[0]]) || {
|
|
230
|
+
const { path, schemaType } = props, { options } = schemaType, baseUrl = options?.baseUrl || "https://www.example.com", prefixFunction = options?.prefix, parent = sanity.useFormValue([path[0]]) || {
|
|
231
231
|
title: "",
|
|
232
232
|
description: "",
|
|
233
233
|
canonicalUrl: ""
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
|
|
234
|
+
}, rootDoc = sanity.useFormValue([]) || {
|
|
235
|
+
slug: { current: "" }
|
|
236
|
+
}, slug = rootDoc?.slug?.current || "", {
|
|
237
237
|
title,
|
|
238
238
|
description,
|
|
239
239
|
canonicalUrl: url
|
|
@@ -247,7 +247,22 @@ const stopWords = ["the", "a", "an", "and", "or", "but"], hasMatchingKeyword = (
|
|
|
247
247
|
fontFamily: "Arial, sans-serif"
|
|
248
248
|
},
|
|
249
249
|
children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, { space: 3, children: [
|
|
250
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: 1, style: { color: "#006621", fontSize: 12, lineHeight: 1.3, marginBottom: 3 }, children:
|
|
250
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: 1, style: { color: "#006621", fontSize: 12, lineHeight: 1.3, marginBottom: 3 }, children: (() => {
|
|
251
|
+
const base = (url || baseUrl)?.replace(/\/+$/, ""), slugStr = String(slug || "").replace(/^\/+/, ""), path2 = [String(prefixFunction ? prefixFunction(rootDoc) : "").replace(
|
|
252
|
+
/^\/+|\/+$/g,
|
|
253
|
+
""
|
|
254
|
+
), slugStr].filter(Boolean).join("/"), finalUrl = path2 ? `${base}/${path2}` : base;
|
|
255
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
256
|
+
"a",
|
|
257
|
+
{
|
|
258
|
+
href: finalUrl || "#",
|
|
259
|
+
target: "_blank",
|
|
260
|
+
rel: "noopener noreferrer",
|
|
261
|
+
style: { color: "inherit", textDecoration: "none" },
|
|
262
|
+
children: finalUrl || "https://www.example.com/page-url"
|
|
263
|
+
}
|
|
264
|
+
);
|
|
265
|
+
})() }),
|
|
251
266
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
252
267
|
ui.Text,
|
|
253
268
|
{
|
|
@@ -305,6 +320,70 @@ const stopWords = ["the", "a", "an", "and", "or", "but"], hasMatchingKeyword = (
|
|
|
305
320
|
metaAttributes: {
|
|
306
321
|
title: "Additional Meta Attributes",
|
|
307
322
|
description: "Add custom meta attributes to the head of the document for additional SEO and social media integration."
|
|
323
|
+
},
|
|
324
|
+
openGraphTitle: {
|
|
325
|
+
title: "Open Graph Title",
|
|
326
|
+
description: ""
|
|
327
|
+
},
|
|
328
|
+
openGraphUrl: {
|
|
329
|
+
title: "Open Graph URL",
|
|
330
|
+
description: "The canonical URL of the page. This should be the full URL including protocol (https://)."
|
|
331
|
+
},
|
|
332
|
+
openGraphDescription: {
|
|
333
|
+
title: "Open Graph Description",
|
|
334
|
+
description: ""
|
|
335
|
+
},
|
|
336
|
+
openGraphSiteName: {
|
|
337
|
+
title: "Open Graph Site Name",
|
|
338
|
+
description: "The name of your website. This is often the site title."
|
|
339
|
+
},
|
|
340
|
+
openGraphType: {
|
|
341
|
+
title: "Open Graph Type",
|
|
342
|
+
description: "Select the type of content for Open Graph."
|
|
343
|
+
},
|
|
344
|
+
openGraphImageType: {
|
|
345
|
+
title: "Image Type",
|
|
346
|
+
description: "Choose whether to upload an image or provide an image URL for Open Graph."
|
|
347
|
+
},
|
|
348
|
+
openGraphImage: {
|
|
349
|
+
title: "Open Graph Image",
|
|
350
|
+
description: "Recommended size: 1200x630px (minimum 600x315px). Max file size: 5MB. Aspect ratio 1.91:1."
|
|
351
|
+
},
|
|
352
|
+
openGraphImageUrl: {
|
|
353
|
+
title: "Open Graph Image URL",
|
|
354
|
+
description: "Enter the full URL of the image. Ensure the image is accessible and meets the recommended size of 1200x630px (minimum 600x315px)."
|
|
355
|
+
},
|
|
356
|
+
twitterCard: {
|
|
357
|
+
title: "Card Type",
|
|
358
|
+
description: ""
|
|
359
|
+
},
|
|
360
|
+
twitterSite: {
|
|
361
|
+
title: "Site X Handle",
|
|
362
|
+
description: "The X (formerly Twitter) handle of the website (e.g., @example)"
|
|
363
|
+
},
|
|
364
|
+
twitterCreator: {
|
|
365
|
+
title: "X Creator Handle",
|
|
366
|
+
description: "The X (formerly Twitter) handle of the content creator (e.g., @creator)"
|
|
367
|
+
},
|
|
368
|
+
twitterTitle: {
|
|
369
|
+
title: "X Title",
|
|
370
|
+
description: "The title of the content as it should appear on X (formerly Twitter)."
|
|
371
|
+
},
|
|
372
|
+
twitterDescription: {
|
|
373
|
+
title: "X Description",
|
|
374
|
+
description: "A brief description of the content for X (formerly Twitter)."
|
|
375
|
+
},
|
|
376
|
+
twitterImageType: {
|
|
377
|
+
title: "X Image Type",
|
|
378
|
+
description: "Choose whether to upload an image or provide an image URL for X (formerly Twitter)."
|
|
379
|
+
},
|
|
380
|
+
twitterImage: {
|
|
381
|
+
title: "X Image",
|
|
382
|
+
description: 'An image URL which should be at least 120x120px for "summary" card and 280x150px for "summary_large_image" card.'
|
|
383
|
+
},
|
|
384
|
+
twitterImageUrl: {
|
|
385
|
+
title: "X Image URL",
|
|
386
|
+
description: "Enter the full URL of the image for X (formerly Twitter). Ensure the image is accessible and meets the recommended size."
|
|
308
387
|
}
|
|
309
388
|
}, getFieldInfo = (fieldName, fieldOverrides) => {
|
|
310
389
|
const fieldInfo = fieldOverrides && fieldOverrides[fieldName] || DEFAULT_FIELD_INFO[fieldName];
|
|
@@ -312,7 +391,7 @@ const stopWords = ["the", "a", "an", "and", "or", "but"], hasMatchingKeyword = (
|
|
|
312
391
|
}, isFieldHidden = (fieldName, config, documentType) => !!(config.defaultHiddenFields?.includes(fieldName) || documentType && config.fieldVisibility?.[documentType]?.hiddenFields?.includes(fieldName)), getFieldHiddenFunction = (fieldName, config) => ({ document }) => {
|
|
313
392
|
const documentType = document?._type;
|
|
314
393
|
return isFieldHidden(fieldName, config, documentType);
|
|
315
|
-
};
|
|
394
|
+
}, isEmpty = (value) => value == null || typeof value == "string" && value.trim() === "" || Array.isArray(value) && value.length === 0 || typeof value == "object" && !Array.isArray(value) && Object.keys(value).length === 0;
|
|
316
395
|
function seoFieldsSchema(config = {}) {
|
|
317
396
|
return sanity.defineType({
|
|
318
397
|
name: "seoFields",
|
|
@@ -327,15 +406,23 @@ function seoFieldsSchema(config = {}) {
|
|
|
327
406
|
hidden: getFieldHiddenFunction("robots", config)
|
|
328
407
|
}),
|
|
329
408
|
// 👇 conditionally spread preview field
|
|
330
|
-
...config.seoPreview
|
|
409
|
+
...typeof config.seoPreview == "boolean" && config.seoPreview || typeof config.seoPreview == "object" && !isEmpty(config.seoPreview) ? [
|
|
331
410
|
sanity.defineField({
|
|
332
411
|
name: "preview",
|
|
333
412
|
title: "SEO Preview",
|
|
334
413
|
type: "string",
|
|
335
414
|
components: { input: SeoPreview },
|
|
415
|
+
options: {
|
|
416
|
+
baseUrl: config.baseUrl || "https://www.example.com",
|
|
417
|
+
...typeof config.seoPreview == "object" && config.seoPreview && config.seoPreview.prefix ? { prefix: config.seoPreview.prefix } : {}
|
|
418
|
+
},
|
|
419
|
+
// Use a readOnly field to prevent editing
|
|
420
|
+
// This field is just for preview purposes
|
|
421
|
+
initialValue: {},
|
|
422
|
+
// TypeScript workaround
|
|
336
423
|
readOnly: !0
|
|
337
424
|
})
|
|
338
|
-
],
|
|
425
|
+
] : [],
|
|
339
426
|
sanity.defineField({
|
|
340
427
|
name: "title",
|
|
341
428
|
...getFieldInfo("title", config.fieldOverrides),
|
|
@@ -522,14 +609,16 @@ function openGraph(config = {}) {
|
|
|
522
609
|
fields: [
|
|
523
610
|
sanity.defineField({
|
|
524
611
|
name: "url",
|
|
525
|
-
title: "Open Graph URL",
|
|
526
612
|
type: "url",
|
|
613
|
+
...getFieldInfo("openGraphUrl", config.fieldOverrides),
|
|
614
|
+
hidden: getFieldHiddenFunction("openGraphUrl", config),
|
|
527
615
|
description: "The canonical URL of the page. This should be the full URL including protocol (https://)."
|
|
528
616
|
}),
|
|
529
617
|
sanity.defineField({
|
|
530
618
|
name: "title",
|
|
531
|
-
|
|
619
|
+
...getFieldInfo("openGraphTitle", config.fieldOverrides),
|
|
532
620
|
type: "string",
|
|
621
|
+
hidden: getFieldHiddenFunction("openGraphTitle", config),
|
|
533
622
|
components: {
|
|
534
623
|
input: OgTitle
|
|
535
624
|
// Can also wrap with a string input + preview
|
|
@@ -537,9 +626,10 @@ function openGraph(config = {}) {
|
|
|
537
626
|
}),
|
|
538
627
|
sanity.defineField({
|
|
539
628
|
name: "description",
|
|
540
|
-
|
|
629
|
+
...getFieldInfo("openGraphDescription", config.fieldOverrides),
|
|
541
630
|
type: "text",
|
|
542
631
|
rows: 3,
|
|
632
|
+
hidden: getFieldHiddenFunction("openGraphDescription", config),
|
|
543
633
|
components: {
|
|
544
634
|
input: OgDescription
|
|
545
635
|
// Can also wrap with a text area + preview
|
|
@@ -547,14 +637,13 @@ function openGraph(config = {}) {
|
|
|
547
637
|
}),
|
|
548
638
|
sanity.defineField({
|
|
549
639
|
name: "siteName",
|
|
550
|
-
|
|
640
|
+
...getFieldInfo("openGraphSiteName", config.fieldOverrides),
|
|
551
641
|
type: "string",
|
|
552
|
-
description: "The name of your website. This is often the site title.",
|
|
553
642
|
hidden: getFieldHiddenFunction("openGraphSiteName", config)
|
|
554
643
|
}),
|
|
555
644
|
sanity.defineField({
|
|
556
645
|
name: "type",
|
|
557
|
-
|
|
646
|
+
...getFieldInfo("openGraphType", config.fieldOverrides),
|
|
558
647
|
type: "string",
|
|
559
648
|
options: {
|
|
560
649
|
list: [
|
|
@@ -568,13 +657,12 @@ function openGraph(config = {}) {
|
|
|
568
657
|
]
|
|
569
658
|
// layout: 'radio', // Display as radio buttons
|
|
570
659
|
},
|
|
571
|
-
|
|
572
|
-
|
|
660
|
+
hidden: getFieldHiddenFunction("openGraphType", config),
|
|
661
|
+
initialValue: "website"
|
|
573
662
|
}),
|
|
574
|
-
// upload image or ask for url
|
|
575
663
|
sanity.defineField({
|
|
576
664
|
name: "imageType",
|
|
577
|
-
|
|
665
|
+
...getFieldInfo("openGraphImageType", config.fieldOverrides),
|
|
578
666
|
type: "string",
|
|
579
667
|
options: {
|
|
580
668
|
list: [
|
|
@@ -582,24 +670,31 @@ function openGraph(config = {}) {
|
|
|
582
670
|
{ title: "Image URL", value: "url" }
|
|
583
671
|
]
|
|
584
672
|
},
|
|
673
|
+
hidden: getFieldHiddenFunction("openGraphImage", config),
|
|
585
674
|
initialValue: "upload"
|
|
586
675
|
}),
|
|
587
676
|
sanity.defineField({
|
|
588
677
|
name: "image",
|
|
589
|
-
|
|
678
|
+
...getFieldInfo("openGraphImage", config.fieldOverrides),
|
|
590
679
|
type: "image",
|
|
591
680
|
options: {
|
|
592
681
|
hotspot: !0
|
|
593
682
|
},
|
|
594
|
-
|
|
595
|
-
|
|
683
|
+
fields: [
|
|
684
|
+
sanity.defineField({
|
|
685
|
+
name: "alt",
|
|
686
|
+
title: "Image Alt Text",
|
|
687
|
+
type: "string",
|
|
688
|
+
description: "A description of the image for accessibility purposes."
|
|
689
|
+
})
|
|
690
|
+
],
|
|
691
|
+
hidden: ({ parent }) => parent?.imageType !== "upload"
|
|
596
692
|
}),
|
|
597
693
|
sanity.defineField({
|
|
598
694
|
name: "imageUrl",
|
|
599
|
-
|
|
695
|
+
...getFieldInfo("openGraphImageUrl", config.fieldOverrides),
|
|
600
696
|
type: "url",
|
|
601
|
-
hidden: ({ parent }) => parent?.imageType !== "url"
|
|
602
|
-
description: "Enter the full URL of the image. Ensure the image is accessible and meets the recommended size of 1200x630px (minimum 600x315px)."
|
|
697
|
+
hidden: ({ parent }) => parent?.imageType !== "url"
|
|
603
698
|
})
|
|
604
699
|
]
|
|
605
700
|
});
|
|
@@ -657,7 +752,7 @@ function twitter(config = {}) {
|
|
|
657
752
|
fields: [
|
|
658
753
|
sanity.defineField({
|
|
659
754
|
name: "card",
|
|
660
|
-
|
|
755
|
+
...getFieldInfo("twitterCard", config.fieldOverrides),
|
|
661
756
|
type: "string",
|
|
662
757
|
options: {
|
|
663
758
|
list: [
|
|
@@ -667,46 +762,58 @@ function twitter(config = {}) {
|
|
|
667
762
|
{ title: "Player", value: "player" }
|
|
668
763
|
]
|
|
669
764
|
},
|
|
765
|
+
hidden: getFieldHiddenFunction("twitterCard", config),
|
|
670
766
|
initialValue: "summary_large_image"
|
|
671
767
|
// good default
|
|
672
768
|
}),
|
|
673
769
|
sanity.defineField({
|
|
674
770
|
name: "site",
|
|
675
|
-
|
|
771
|
+
...getFieldInfo("twitterSite", config.fieldOverrides),
|
|
676
772
|
type: "string",
|
|
677
|
-
description: "The X (formerly Twitter) handle of the website (e.g., @example)",
|
|
678
773
|
hidden: getFieldHiddenFunction("twitterSite", config)
|
|
679
774
|
}),
|
|
680
775
|
sanity.defineField({
|
|
681
776
|
name: "creator",
|
|
682
|
-
title: "X Creator Handle",
|
|
683
777
|
type: "string",
|
|
684
|
-
|
|
778
|
+
...getFieldInfo("twitterCreator", config.fieldOverrides),
|
|
779
|
+
hidden: getFieldHiddenFunction("twitterCreator", config)
|
|
685
780
|
}),
|
|
686
781
|
sanity.defineField({
|
|
687
782
|
name: "title",
|
|
688
|
-
title: "X Title",
|
|
689
783
|
type: "string",
|
|
690
|
-
|
|
784
|
+
...getFieldInfo("twitterTitle", config.fieldOverrides),
|
|
785
|
+
hidden: getFieldHiddenFunction("twitterTitle", config),
|
|
691
786
|
components: {
|
|
692
787
|
input: TwitterTitle
|
|
693
788
|
}
|
|
694
789
|
}),
|
|
695
790
|
sanity.defineField({
|
|
696
791
|
name: "description",
|
|
697
|
-
title: "X Description",
|
|
698
792
|
type: "text",
|
|
699
793
|
rows: 3,
|
|
700
|
-
|
|
794
|
+
...getFieldInfo("twitterDescription", config.fieldOverrides),
|
|
795
|
+
hidden: getFieldHiddenFunction("twitterDescription", config),
|
|
701
796
|
components: {
|
|
702
797
|
input: TwitterDescription
|
|
703
798
|
}
|
|
704
799
|
}),
|
|
800
|
+
sanity.defineField({
|
|
801
|
+
name: "imageType",
|
|
802
|
+
...getFieldInfo("twitterImageType", config.fieldOverrides),
|
|
803
|
+
type: "string",
|
|
804
|
+
options: {
|
|
805
|
+
list: [
|
|
806
|
+
{ title: "Upload Image", value: "upload" },
|
|
807
|
+
{ title: "Image URL", value: "url" }
|
|
808
|
+
]
|
|
809
|
+
},
|
|
810
|
+
hidden: getFieldHiddenFunction("twitterImage", config),
|
|
811
|
+
initialValue: "upload"
|
|
812
|
+
}),
|
|
705
813
|
sanity.defineField({
|
|
706
814
|
name: "image",
|
|
707
|
-
|
|
815
|
+
...getFieldInfo("twitterImage", config.fieldOverrides),
|
|
708
816
|
type: "image",
|
|
709
|
-
description: 'An image URL which should be at least 120x120px for "summary" card and 280x150px for "summary_large_image" card.',
|
|
710
817
|
options: {
|
|
711
818
|
hotspot: !0
|
|
712
819
|
},
|
|
@@ -715,9 +822,15 @@ function twitter(config = {}) {
|
|
|
715
822
|
name: "alt",
|
|
716
823
|
title: "Image Alt Text",
|
|
717
824
|
type: "string",
|
|
718
|
-
description: "
|
|
825
|
+
description: "A description of the image for accessibility purposes."
|
|
719
826
|
})
|
|
720
827
|
]
|
|
828
|
+
}),
|
|
829
|
+
sanity.defineField({
|
|
830
|
+
name: "imageUrl",
|
|
831
|
+
...getFieldInfo("twitterImageUrl", config.fieldOverrides),
|
|
832
|
+
type: "url",
|
|
833
|
+
hidden: ({ parent }) => parent?.imageType !== "url"
|
|
721
834
|
})
|
|
722
835
|
]
|
|
723
836
|
});
|