sanity-plugin-seofields 1.0.8 → 1.0.10
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 +92 -171
- package/dist/index.d.mts +15 -189
- package/dist/index.d.ts +15 -189
- package/dist/index.js +230 -249
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +231 -250
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/components/SeoPreview.tsx +20 -19
- package/src/components/meta/MetaDescription.tsx +8 -17
- package/src/components/meta/MetaTitle.tsx +8 -17
- package/src/components/openGraph/OgDescription.tsx +6 -4
- package/src/components/openGraph/OgTitle.tsx +8 -6
- package/src/components/twitter/twitterDescription.tsx +9 -7
- package/src/components/twitter/twitterTitle.tsx +7 -5
- package/src/index.ts +3 -6
- package/src/plugin.ts +10 -9
- package/src/schemas/index.ts +10 -15
- package/src/schemas/types/index.ts +7 -5
- package/src/schemas/types/metaAttribute/index.ts +10 -14
- package/src/schemas/types/metaTag/index.ts +15 -14
- package/src/schemas/types/openGraph/index.ts +16 -5
- package/src/schemas/types/twitter/index.ts +16 -4
- package/src/types.ts +4 -65
- package/src/utils/fieldsUtils.ts +17 -96
- package/src/utils/seoUtils.ts +15 -15
- package/src/utils/utils.ts +2 -2
- package/src/types/index.ts +0 -241
- package/src/utils/generaeDynamicJsonLd.ts +0 -295
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: !0 });
|
|
3
|
-
var sanity = require("sanity"), jsxRuntime = require("react/jsx-runtime"),
|
|
3
|
+
var sanity = require("sanity"), jsxRuntime = require("react/jsx-runtime"), ui = require("@sanity/ui"), react = require("react");
|
|
4
4
|
const stopWords = ["the", "a", "an", "and", "or", "but"], hasMatchingKeyword = (title, keywordList) => {
|
|
5
5
|
if (!title || keywordList.length === 0) return !1;
|
|
6
6
|
const lowerTitle = title.toLowerCase();
|
|
@@ -17,7 +17,7 @@ const stopWords = ["the", "a", "an", "and", "or", "but"], hasMatchingKeyword = (
|
|
|
17
17
|
if (!title) return !1;
|
|
18
18
|
const firstWord = title.trim().split(" ")[0].toLowerCase();
|
|
19
19
|
return stopWords.includes(firstWord);
|
|
20
|
-
}, truncate = (text, maxLength) => text.length > maxLength ? text.slice(0, maxLength)
|
|
20
|
+
}, truncate = (text, maxLength) => text.length > maxLength ? `${text.slice(0, maxLength)}\u2026` : text, hasExcessivePunctuation = (title) => /[!@#$%^&*]{2,}/.test(title), getMetaTitleValidationMessages = (title, keywords, isParentseoField) => {
|
|
21
21
|
const feedback = [], charCount = title?.length || 0;
|
|
22
22
|
if (!title?.trim())
|
|
23
23
|
return feedback.push({ text: "Meta Title is empty. Add content to improve SEO.", color: "red" }), feedback;
|
|
@@ -185,10 +185,9 @@ const stopWords = ["the", "a", "an", "and", "or", "but"], hasMatchingKeyword = (
|
|
|
185
185
|
text: "X Description has excessive punctuation \u2014 simplify it.",
|
|
186
186
|
color: "orange"
|
|
187
187
|
}), feedback;
|
|
188
|
-
},
|
|
189
|
-
sanity.
|
|
190
|
-
|
|
191
|
-
() => getMetaTitleValidationMessages(value || "", keywords, isParentseoField),
|
|
188
|
+
}, MetaDescription = (props) => {
|
|
189
|
+
const { value, renderDefault, path } = props, parent = sanity.useFormValue([path[0]]), isParentseoField = parent && parent?._type === "seoFields", keywords = react.useMemo(() => parent?.keywords || [], [parent?.keywords]), feedbackItems = react.useMemo(
|
|
190
|
+
() => getMetaDescriptionValidationMessages(value || "", keywords, isParentseoField),
|
|
192
191
|
[value, keywords, isParentseoField]
|
|
193
192
|
);
|
|
194
193
|
return /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, { space: 3, children: [
|
|
@@ -197,21 +196,15 @@ const stopWords = ["the", "a", "an", "and", "or", "but"], hasMatchingKeyword = (
|
|
|
197
196
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
198
197
|
"div",
|
|
199
198
|
{
|
|
200
|
-
style: {
|
|
201
|
-
minWidth: 10,
|
|
202
|
-
height: 10,
|
|
203
|
-
borderRadius: "50%",
|
|
204
|
-
backgroundColor: item.color
|
|
205
|
-
}
|
|
199
|
+
style: { width: 10, height: 10, borderRadius: "50%", backgroundColor: item.color }
|
|
206
200
|
}
|
|
207
201
|
),
|
|
208
202
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { weight: "bold", muted: !0, size: 14, children: item.text })
|
|
209
203
|
] }, item.text)) })
|
|
210
204
|
] });
|
|
211
|
-
},
|
|
212
|
-
sanity.
|
|
213
|
-
|
|
214
|
-
() => getMetaDescriptionValidationMessages(value || "", keywords, isParentseoField),
|
|
205
|
+
}, MetaTitle = (props) => {
|
|
206
|
+
const { value, renderDefault, path } = props, parent = sanity.useFormValue([path[0]]), isParentseoField = parent && parent?._type === "seoFields", keywords = react.useMemo(() => parent?.keywords || [], [parent?.keywords]), feedbackItems = react.useMemo(
|
|
207
|
+
() => getMetaTitleValidationMessages(value || "", keywords, isParentseoField),
|
|
215
208
|
[value, keywords, isParentseoField]
|
|
216
209
|
);
|
|
217
210
|
return /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, { space: 3, children: [
|
|
@@ -220,7 +213,12 @@ const stopWords = ["the", "a", "an", "and", "or", "but"], hasMatchingKeyword = (
|
|
|
220
213
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
221
214
|
"div",
|
|
222
215
|
{
|
|
223
|
-
style: {
|
|
216
|
+
style: {
|
|
217
|
+
minWidth: 10,
|
|
218
|
+
height: 10,
|
|
219
|
+
borderRadius: "50%",
|
|
220
|
+
backgroundColor: item.color
|
|
221
|
+
}
|
|
224
222
|
}
|
|
225
223
|
),
|
|
226
224
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { weight: "bold", muted: !0, size: 14, children: item.text })
|
|
@@ -248,10 +246,9 @@ const stopWords = ["the", "a", "an", "and", "or", "but"], hasMatchingKeyword = (
|
|
|
248
246
|
},
|
|
249
247
|
children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, { space: 3, children: [
|
|
250
248
|
/* @__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(/^\/+/, ""),
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
), slugStr].filter(Boolean).join("/"), finalUrl = path2 ? `${base}/${path2}` : base;
|
|
249
|
+
const base = (url || baseUrl)?.replace(/\/+$/, ""), slugStr = String(slug || "").replace(/^\/+/, ""), urlPath = [String(
|
|
250
|
+
prefixFunction ? prefixFunction(rootDoc) : ""
|
|
251
|
+
).replace(/^\/+|\/+$/g, ""), slugStr].filter(Boolean).join("/"), finalUrl = urlPath ? `${base}/${urlPath}` : base;
|
|
255
252
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
256
253
|
"a",
|
|
257
254
|
{
|
|
@@ -354,7 +351,7 @@ const stopWords = ["the", "a", "an", "and", "or", "but"], hasMatchingKeyword = (
|
|
|
354
351
|
description: "Enter the full URL of the image. Ensure the image is accessible and meets the recommended size of 1200x630px (minimum 600x315px)."
|
|
355
352
|
},
|
|
356
353
|
twitterCard: {
|
|
357
|
-
title: "Card Type",
|
|
354
|
+
title: "X Card Type",
|
|
358
355
|
description: ""
|
|
359
356
|
},
|
|
360
357
|
twitterSite: {
|
|
@@ -387,179 +384,16 @@ const stopWords = ["the", "a", "an", "and", "or", "but"], hasMatchingKeyword = (
|
|
|
387
384
|
}
|
|
388
385
|
}, getFieldInfo = (fieldName, fieldOverrides) => {
|
|
389
386
|
const fieldInfo = fieldOverrides && fieldOverrides[fieldName] || DEFAULT_FIELD_INFO[fieldName];
|
|
390
|
-
return fieldInfo ? { title: fieldInfo.title, description: fieldInfo.description } : { title: "", description: "" };
|
|
391
|
-
}, isFieldHidden = (fieldName, config, documentType) => !!(config.defaultHiddenFields?.includes(fieldName) || documentType && config.fieldVisibility?.[documentType]?.hiddenFields?.includes(fieldName)), getFieldHiddenFunction = (fieldName, config) => ({
|
|
387
|
+
return fieldInfo ? { title: fieldInfo.title || "", description: fieldInfo.description || "" } : { title: "", description: "" };
|
|
388
|
+
}, isFieldHidden = (fieldName, config, documentType) => !!(config.defaultHiddenFields?.includes(fieldName) || documentType && config.fieldVisibility?.[documentType]?.hiddenFields?.includes(fieldName)), getFieldHiddenFunction = (fieldName, config) => ({
|
|
389
|
+
document
|
|
390
|
+
}) => {
|
|
392
391
|
const documentType = document?._type;
|
|
393
392
|
return isFieldHidden(fieldName, config, documentType);
|
|
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
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
title: "SEO Fields",
|
|
399
|
-
type: "object",
|
|
400
|
-
fields: [
|
|
401
|
-
sanity.defineField({
|
|
402
|
-
name: "robots",
|
|
403
|
-
title: "Robots Settings",
|
|
404
|
-
type: "robots",
|
|
405
|
-
// Use the separate robots type here
|
|
406
|
-
hidden: getFieldHiddenFunction("robots", config)
|
|
407
|
-
}),
|
|
408
|
-
// 👇 conditionally spread preview field
|
|
409
|
-
...typeof config.seoPreview == "boolean" && config.seoPreview || typeof config.seoPreview == "object" && !isEmpty(config.seoPreview) ? [
|
|
410
|
-
sanity.defineField({
|
|
411
|
-
name: "preview",
|
|
412
|
-
title: "SEO Preview",
|
|
413
|
-
type: "string",
|
|
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
|
-
// Set an initial value
|
|
423
|
-
readOnly: !0
|
|
424
|
-
})
|
|
425
|
-
] : [],
|
|
426
|
-
sanity.defineField({
|
|
427
|
-
name: "title",
|
|
428
|
-
...getFieldInfo("title", config.fieldOverrides),
|
|
429
|
-
// title: 'Meta Title',
|
|
430
|
-
type: "string",
|
|
431
|
-
// description:
|
|
432
|
-
// 'The meta title is displayed in search engine results as the clickable headline for a given result. It should be concise and accurately reflect the content of the page.',
|
|
433
|
-
components: {
|
|
434
|
-
input: MetaTitle
|
|
435
|
-
},
|
|
436
|
-
// validation: (Rule) => Rule.max(60).warning('Meta title should be under 60 characters.'),
|
|
437
|
-
hidden: getFieldHiddenFunction("title", config)
|
|
438
|
-
}),
|
|
439
|
-
sanity.defineField({
|
|
440
|
-
name: "description",
|
|
441
|
-
...getFieldInfo("description", config.fieldOverrides),
|
|
442
|
-
// title: 'Meta Description',
|
|
443
|
-
// description:
|
|
444
|
-
// 'Provide a concise summary of the page content. This description may be used by search engines in search results.',
|
|
445
|
-
type: "text",
|
|
446
|
-
rows: 3,
|
|
447
|
-
components: {
|
|
448
|
-
input: MetaDescription
|
|
449
|
-
},
|
|
450
|
-
// validation: (Rule) => Rule.max(160).warning('Meta description should be under 160 characters.'),
|
|
451
|
-
hidden: getFieldHiddenFunction("description", config)
|
|
452
|
-
}),
|
|
453
|
-
sanity.defineField({
|
|
454
|
-
name: "metaImage",
|
|
455
|
-
...getFieldInfo("metaImage", config.fieldOverrides),
|
|
456
|
-
// title: 'Meta Image',
|
|
457
|
-
// description:
|
|
458
|
-
// 'Upload an image that represents the content of the page. This image may be used in social media previews and search engine results.',
|
|
459
|
-
type: "image",
|
|
460
|
-
options: {
|
|
461
|
-
hotspot: !0
|
|
462
|
-
},
|
|
463
|
-
hidden: getFieldHiddenFunction("metaImage", config)
|
|
464
|
-
}),
|
|
465
|
-
sanity.defineField({
|
|
466
|
-
name: "metaAttributes",
|
|
467
|
-
// title: 'Additional Meta Attributes',
|
|
468
|
-
...getFieldInfo("metaAttributes", config.fieldOverrides),
|
|
469
|
-
type: "array",
|
|
470
|
-
of: [{ type: "metaAttribute" }],
|
|
471
|
-
// description:
|
|
472
|
-
// 'Add custom meta attributes to the head of the document for additional SEO and social media integration.',
|
|
473
|
-
hidden: getFieldHiddenFunction("metaAttributes", config)
|
|
474
|
-
}),
|
|
475
|
-
sanity.defineField({
|
|
476
|
-
name: "keywords",
|
|
477
|
-
...getFieldInfo("keywords", config.fieldOverrides),
|
|
478
|
-
title: "Keywords",
|
|
479
|
-
type: "array",
|
|
480
|
-
of: [{ type: "string" }],
|
|
481
|
-
description: "Add relevant keywords for this page. These keywords will be used for SEO purposes.",
|
|
482
|
-
hidden: getFieldHiddenFunction("keywords", config)
|
|
483
|
-
}),
|
|
484
|
-
sanity.defineField({
|
|
485
|
-
name: "canonicalUrl",
|
|
486
|
-
...getFieldInfo("canonicalUrl", config.fieldOverrides),
|
|
487
|
-
title: "Canonical URL",
|
|
488
|
-
type: "url",
|
|
489
|
-
description: "Specify the canonical URL for this page. This helps prevent duplicate content issues by indicating the preferred version of a page.",
|
|
490
|
-
hidden: getFieldHiddenFunction("canonicalUrl", config)
|
|
491
|
-
}),
|
|
492
|
-
sanity.defineField({
|
|
493
|
-
name: "openGraph",
|
|
494
|
-
title: "Open Graph Settings",
|
|
495
|
-
type: "openGraph"
|
|
496
|
-
}),
|
|
497
|
-
sanity.defineField({
|
|
498
|
-
name: "twitter",
|
|
499
|
-
title: "X (Formerly Twitter) Card Settings",
|
|
500
|
-
type: "twitter"
|
|
501
|
-
})
|
|
502
|
-
]
|
|
503
|
-
});
|
|
504
|
-
}
|
|
505
|
-
var metaAttribute = sanity.defineType({
|
|
506
|
-
name: "metaAttribute",
|
|
507
|
-
title: "Meta Attribute",
|
|
508
|
-
type: "object",
|
|
509
|
-
fields: [
|
|
510
|
-
sanity.defineField({
|
|
511
|
-
name: "key",
|
|
512
|
-
title: "Attribute Name",
|
|
513
|
-
type: "string"
|
|
514
|
-
}),
|
|
515
|
-
sanity.defineField({
|
|
516
|
-
name: "type",
|
|
517
|
-
title: "Attribute Value Type",
|
|
518
|
-
type: "string",
|
|
519
|
-
options: {
|
|
520
|
-
list: [
|
|
521
|
-
{ title: "String", value: "string" },
|
|
522
|
-
{ title: "Image", value: "image" }
|
|
523
|
-
]
|
|
524
|
-
},
|
|
525
|
-
initialValue: "string"
|
|
526
|
-
}),
|
|
527
|
-
sanity.defineField({
|
|
528
|
-
name: "value",
|
|
529
|
-
title: "Attribute Value",
|
|
530
|
-
type: "string",
|
|
531
|
-
hidden: ({ parent }) => parent?.type === "image"
|
|
532
|
-
}),
|
|
533
|
-
sanity.defineField({
|
|
534
|
-
name: "image",
|
|
535
|
-
title: "Attribute Image Value",
|
|
536
|
-
type: "image",
|
|
537
|
-
hidden: ({ parent }) => parent?.type === "string"
|
|
538
|
-
})
|
|
539
|
-
],
|
|
540
|
-
preview: {
|
|
541
|
-
select: {
|
|
542
|
-
attributeName: "key",
|
|
543
|
-
attributeValueString: "value",
|
|
544
|
-
attributeValueImage: "image"
|
|
545
|
-
},
|
|
546
|
-
prepare({
|
|
547
|
-
attributeName,
|
|
548
|
-
attributeValueString,
|
|
549
|
-
attributeValueImage
|
|
550
|
-
}) {
|
|
551
|
-
return {
|
|
552
|
-
title: attributeName || "No Attribute Name",
|
|
553
|
-
subtitle: attributeValueString ? `Value: ${attributeValueString}` : attributeValueImage ? "Value: [Image]" : "No Attribute Value",
|
|
554
|
-
media: attributeValueImage
|
|
555
|
-
};
|
|
556
|
-
}
|
|
557
|
-
}
|
|
558
|
-
});
|
|
559
|
-
const OgTitle = (props) => {
|
|
560
|
-
const { value, renderDefault, path } = props, parent = sanity.useFormValue([path[0]]), isParentseoField = parent && parent?._type === "seoFields", keywords = parent?.keywords || [], feedbackItems = react.useMemo(
|
|
561
|
-
() => getOgTitleValidation(value || "", keywords, isParentseoField),
|
|
562
|
-
[value, keywords]
|
|
393
|
+
}, 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, OgDescription = (props) => {
|
|
394
|
+
const { value, renderDefault, path } = props, parent = sanity.useFormValue([path[0]]), isParentseoField = parent && parent?._type === "seoFields", keywords = react.useMemo(() => parent?.keywords || [], [parent?.keywords]), feedbackItems = react.useMemo(
|
|
395
|
+
() => getOgDescriptionValidation(value || "", keywords, isParentseoField),
|
|
396
|
+
[value, keywords, isParentseoField]
|
|
563
397
|
);
|
|
564
398
|
return /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, { space: 3, children: [
|
|
565
399
|
renderDefault(props),
|
|
@@ -578,9 +412,9 @@ const OgTitle = (props) => {
|
|
|
578
412
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { weight: "bold", muted: !0, size: 14, children: item.text })
|
|
579
413
|
] }, item.text)) })
|
|
580
414
|
] });
|
|
581
|
-
},
|
|
582
|
-
const { value, renderDefault, path } = props, parent = sanity.useFormValue([path[0]]), isParentseoField = parent && parent?._type === "seoFields", keywords = parent?.keywords || [], feedbackItems = react.useMemo(
|
|
583
|
-
() =>
|
|
415
|
+
}, OgTitle = (props) => {
|
|
416
|
+
const { value, renderDefault, path } = props, parent = sanity.useFormValue([path[0]]), isParentseoField = parent && parent?._type === "seoFields", keywords = react.useMemo(() => parent?.keywords || [], [parent?.keywords]), feedbackItems = react.useMemo(
|
|
417
|
+
() => getOgTitleValidation(value || "", keywords, isParentseoField),
|
|
584
418
|
[value, keywords, isParentseoField]
|
|
585
419
|
);
|
|
586
420
|
return /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, { space: 3, children: [
|
|
@@ -688,21 +522,31 @@ function openGraph(config = {}) {
|
|
|
688
522
|
description: "A description of the image for accessibility purposes."
|
|
689
523
|
})
|
|
690
524
|
],
|
|
691
|
-
hidden: (
|
|
525
|
+
hidden: (context) => {
|
|
526
|
+
const { parent } = context;
|
|
527
|
+
if (parent?.imageType !== "upload") return !0;
|
|
528
|
+
const hiddenFn = getFieldHiddenFunction("openGraphImage", config);
|
|
529
|
+
return typeof hiddenFn == "function" ? hiddenFn(context) : hiddenFn;
|
|
530
|
+
}
|
|
692
531
|
}),
|
|
693
532
|
sanity.defineField({
|
|
694
533
|
name: "imageUrl",
|
|
695
534
|
...getFieldInfo("openGraphImageUrl", config.fieldOverrides),
|
|
696
535
|
type: "url",
|
|
697
|
-
hidden: (
|
|
536
|
+
hidden: (context) => {
|
|
537
|
+
const { parent } = context;
|
|
538
|
+
if (parent?.imageType !== "url") return !0;
|
|
539
|
+
const hiddenFn = getFieldHiddenFunction("openGraphImage", config);
|
|
540
|
+
return typeof hiddenFn == "function" ? hiddenFn(context) : hiddenFn;
|
|
541
|
+
}
|
|
698
542
|
})
|
|
699
543
|
]
|
|
700
544
|
});
|
|
701
545
|
}
|
|
702
|
-
const
|
|
703
|
-
const { value, renderDefault, path } = props, parent = sanity.useFormValue([path[0]]), isParentseoField = parent && parent?._type === "seoFields", keywords = parent?.keywords || [], feedbackItems = react.useMemo(
|
|
704
|
-
() =>
|
|
705
|
-
[value, keywords]
|
|
546
|
+
const TwitterDescription = (props) => {
|
|
547
|
+
const { value, renderDefault, path } = props, parent = sanity.useFormValue([path[0]]), isParentseoField = parent && parent?._type === "seoFields", keywords = react.useMemo(() => parent?.keywords || [], [parent?.keywords]), feedbackItems = react.useMemo(
|
|
548
|
+
() => getTwitterDescriptionValidation(value || "", keywords, isParentseoField),
|
|
549
|
+
[value, keywords, isParentseoField]
|
|
706
550
|
);
|
|
707
551
|
return /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, { space: 3, children: [
|
|
708
552
|
renderDefault(props),
|
|
@@ -721,10 +565,10 @@ const TwitterTitle = (props) => {
|
|
|
721
565
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { weight: "bold", muted: !0, size: 14, children: item.text })
|
|
722
566
|
] }, item.text)) })
|
|
723
567
|
] });
|
|
724
|
-
},
|
|
725
|
-
const { value, renderDefault, path } = props, parent = sanity.useFormValue([path[0]]), isParentseoField = parent && parent?._type === "seoFields", keywords = parent?.keywords || [], feedbackItems = react.useMemo(
|
|
726
|
-
() =>
|
|
727
|
-
[value, keywords]
|
|
568
|
+
}, TwitterTitle = (props) => {
|
|
569
|
+
const { value, renderDefault, path } = props, parent = sanity.useFormValue([path[0]]), isParentseoField = parent && parent?._type === "seoFields", keywords = react.useMemo(() => parent?.keywords || [], [parent?.keywords]), feedbackItems = react.useMemo(
|
|
570
|
+
() => getTwitterTitleValidation(value || "", keywords, isParentseoField),
|
|
571
|
+
[value, keywords, isParentseoField]
|
|
728
572
|
);
|
|
729
573
|
return /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, { space: 3, children: [
|
|
730
574
|
renderDefault(props),
|
|
@@ -824,38 +668,180 @@ function twitter(config = {}) {
|
|
|
824
668
|
type: "string",
|
|
825
669
|
description: "A description of the image for accessibility purposes."
|
|
826
670
|
})
|
|
827
|
-
]
|
|
671
|
+
],
|
|
672
|
+
hidden: (context) => {
|
|
673
|
+
const { parent } = context;
|
|
674
|
+
if (parent?.imageType !== "upload") return !0;
|
|
675
|
+
const hiddenFn = getFieldHiddenFunction("twitterImage", config);
|
|
676
|
+
return typeof hiddenFn == "function" ? hiddenFn(context) : hiddenFn;
|
|
677
|
+
}
|
|
828
678
|
}),
|
|
829
679
|
sanity.defineField({
|
|
830
680
|
name: "imageUrl",
|
|
831
681
|
...getFieldInfo("twitterImageUrl", config.fieldOverrides),
|
|
832
682
|
type: "url",
|
|
833
|
-
hidden: (
|
|
683
|
+
hidden: (context) => {
|
|
684
|
+
const { parent } = context;
|
|
685
|
+
if (parent?.imageType !== "url") return !0;
|
|
686
|
+
const hiddenFn = getFieldHiddenFunction("twitterImage", config);
|
|
687
|
+
return typeof hiddenFn == "function" ? hiddenFn(context) : hiddenFn;
|
|
688
|
+
}
|
|
834
689
|
})
|
|
835
690
|
]
|
|
836
691
|
});
|
|
837
692
|
}
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
693
|
+
function seoFieldsSchema(config = {}) {
|
|
694
|
+
return sanity.defineType({
|
|
695
|
+
name: "seoFields",
|
|
696
|
+
title: "SEO Fields",
|
|
697
|
+
type: "object",
|
|
698
|
+
fields: [
|
|
699
|
+
sanity.defineField({
|
|
700
|
+
name: "robots",
|
|
701
|
+
title: "Robots Settings",
|
|
702
|
+
type: "robots",
|
|
703
|
+
// Use the separate robots type here
|
|
704
|
+
hidden: getFieldHiddenFunction("robots", config)
|
|
705
|
+
}),
|
|
706
|
+
// 👇 conditionally spread preview field
|
|
707
|
+
...typeof config.seoPreview == "boolean" && config.seoPreview || typeof config.seoPreview == "object" && !isEmpty(config.seoPreview) ? [
|
|
708
|
+
sanity.defineField({
|
|
709
|
+
name: "preview",
|
|
710
|
+
title: "SEO Preview",
|
|
711
|
+
type: "string",
|
|
712
|
+
components: { input: SeoPreview },
|
|
713
|
+
options: {
|
|
714
|
+
baseUrl: config.baseUrl || "https://www.example.com",
|
|
715
|
+
...typeof config.seoPreview == "object" && config.seoPreview && config.seoPreview.prefix ? { prefix: config.seoPreview.prefix } : {}
|
|
716
|
+
},
|
|
717
|
+
// Use a readOnly field to prevent editing
|
|
718
|
+
// This field is just for preview purposes
|
|
719
|
+
initialValue: "",
|
|
720
|
+
// Set an initial value
|
|
721
|
+
readOnly: !0
|
|
722
|
+
})
|
|
723
|
+
] : [],
|
|
724
|
+
sanity.defineField({
|
|
725
|
+
name: "title",
|
|
726
|
+
...getFieldInfo("title", config.fieldOverrides),
|
|
727
|
+
// title: 'Meta Title',
|
|
728
|
+
type: "string",
|
|
729
|
+
// description:
|
|
730
|
+
// 'The meta title is displayed in search engine results as the clickable headline for a given result. It should be concise and accurately reflect the content of the page.',
|
|
731
|
+
components: {
|
|
732
|
+
input: MetaTitle
|
|
733
|
+
},
|
|
734
|
+
// validation: (Rule) => Rule.max(60).warning('Meta title should be under 60 characters.'),
|
|
735
|
+
hidden: getFieldHiddenFunction("title", config)
|
|
736
|
+
}),
|
|
737
|
+
sanity.defineField({
|
|
738
|
+
name: "description",
|
|
739
|
+
...getFieldInfo("description", config.fieldOverrides),
|
|
740
|
+
// title: 'Meta Description',
|
|
741
|
+
// description:
|
|
742
|
+
// 'Provide a concise summary of the page content. This description may be used by search engines in search results.',
|
|
743
|
+
type: "text",
|
|
744
|
+
rows: 3,
|
|
745
|
+
components: {
|
|
746
|
+
input: MetaDescription
|
|
747
|
+
},
|
|
748
|
+
// validation: (Rule) => Rule.max(160).warning('Meta description should be under 160 characters.'),
|
|
749
|
+
hidden: getFieldHiddenFunction("description", config)
|
|
750
|
+
}),
|
|
751
|
+
sanity.defineField({
|
|
752
|
+
name: "metaImage",
|
|
753
|
+
...getFieldInfo("metaImage", config.fieldOverrides),
|
|
754
|
+
// title: 'Meta Image',
|
|
755
|
+
// description:
|
|
756
|
+
// 'Upload an image that represents the content of the page. This image may be used in social media previews and search engine results.',
|
|
757
|
+
type: "image",
|
|
758
|
+
options: {
|
|
759
|
+
hotspot: !0
|
|
760
|
+
},
|
|
761
|
+
hidden: getFieldHiddenFunction("metaImage", config)
|
|
762
|
+
}),
|
|
763
|
+
sanity.defineField({
|
|
764
|
+
name: "metaAttributes",
|
|
765
|
+
// title: 'Additional Meta Attributes',
|
|
766
|
+
...getFieldInfo("metaAttributes", config.fieldOverrides),
|
|
767
|
+
type: "array",
|
|
768
|
+
of: [{ type: "metaAttribute" }],
|
|
769
|
+
// description:
|
|
770
|
+
// 'Add custom meta attributes to the head of the document for additional SEO and social media integration.',
|
|
771
|
+
hidden: getFieldHiddenFunction("metaAttributes", config)
|
|
772
|
+
}),
|
|
773
|
+
sanity.defineField({
|
|
774
|
+
name: "keywords",
|
|
775
|
+
...getFieldInfo("keywords", config.fieldOverrides),
|
|
776
|
+
title: "Keywords",
|
|
777
|
+
type: "array",
|
|
778
|
+
of: [{ type: "string" }],
|
|
779
|
+
description: "Add relevant keywords for this page. These keywords will be used for SEO purposes.",
|
|
780
|
+
hidden: getFieldHiddenFunction("keywords", config)
|
|
781
|
+
}),
|
|
782
|
+
sanity.defineField({
|
|
783
|
+
name: "canonicalUrl",
|
|
784
|
+
...getFieldInfo("canonicalUrl", config.fieldOverrides),
|
|
785
|
+
title: "Canonical URL",
|
|
786
|
+
type: "url",
|
|
787
|
+
description: "Specify the canonical URL for this page. This helps prevent duplicate content issues by indicating the preferred version of a page.",
|
|
788
|
+
hidden: getFieldHiddenFunction("canonicalUrl", config)
|
|
789
|
+
}),
|
|
790
|
+
openGraph(config),
|
|
791
|
+
twitter(config)
|
|
792
|
+
]
|
|
793
|
+
});
|
|
794
|
+
}
|
|
795
|
+
var metaAttribute = sanity.defineType({
|
|
796
|
+
name: "metaAttribute",
|
|
797
|
+
title: "Meta Attribute",
|
|
841
798
|
type: "object",
|
|
842
799
|
fields: [
|
|
843
800
|
sanity.defineField({
|
|
844
|
-
name: "
|
|
845
|
-
title: "
|
|
846
|
-
type: "
|
|
847
|
-
initialValue: !1,
|
|
848
|
-
description: "Enable this to prevent search engines from indexing this page. The page will not appear in search results."
|
|
801
|
+
name: "key",
|
|
802
|
+
title: "Attribute Name",
|
|
803
|
+
type: "string"
|
|
849
804
|
}),
|
|
850
805
|
sanity.defineField({
|
|
851
|
-
name: "
|
|
852
|
-
title: "
|
|
853
|
-
type: "
|
|
854
|
-
|
|
855
|
-
|
|
806
|
+
name: "type",
|
|
807
|
+
title: "Attribute Value Type",
|
|
808
|
+
type: "string",
|
|
809
|
+
options: {
|
|
810
|
+
list: [
|
|
811
|
+
{ title: "String", value: "string" },
|
|
812
|
+
{ title: "Image", value: "image" }
|
|
813
|
+
]
|
|
814
|
+
},
|
|
815
|
+
initialValue: "string"
|
|
816
|
+
}),
|
|
817
|
+
sanity.defineField({
|
|
818
|
+
name: "value",
|
|
819
|
+
title: "Attribute Value",
|
|
820
|
+
type: "string",
|
|
821
|
+
hidden: ({ parent }) => parent?.type === "image"
|
|
822
|
+
}),
|
|
823
|
+
sanity.defineField({
|
|
824
|
+
name: "image",
|
|
825
|
+
title: "Attribute Image Value",
|
|
826
|
+
type: "image",
|
|
827
|
+
hidden: ({ parent }) => parent?.type === "string"
|
|
856
828
|
})
|
|
857
829
|
],
|
|
858
|
-
|
|
830
|
+
preview: {
|
|
831
|
+
select: {
|
|
832
|
+
attributeName: "key",
|
|
833
|
+
attributeValueString: "value",
|
|
834
|
+
attributeValueImage: "image"
|
|
835
|
+
},
|
|
836
|
+
prepare({ attributeName, attributeValueString, attributeValueImage }) {
|
|
837
|
+
let subtitle = "";
|
|
838
|
+
return attributeValueString ? subtitle = `Value: ${attributeValueString}` : attributeValueImage ? subtitle = "Value: [Image]" : subtitle = "No Attribute Value", {
|
|
839
|
+
title: attributeName || "No Attribute Name",
|
|
840
|
+
subtitle,
|
|
841
|
+
media: attributeValueImage
|
|
842
|
+
};
|
|
843
|
+
}
|
|
844
|
+
}
|
|
859
845
|
}), metaTag = sanity.defineType({
|
|
860
846
|
name: "metaTag",
|
|
861
847
|
title: "Meta Tag",
|
|
@@ -869,6 +855,27 @@ var robots = sanity.defineType({
|
|
|
869
855
|
description: "Add custom meta attributes to the head of the document for additional SEO and social media integration."
|
|
870
856
|
}
|
|
871
857
|
]
|
|
858
|
+
}), robots = sanity.defineType({
|
|
859
|
+
name: "robots",
|
|
860
|
+
title: "Robots Settings",
|
|
861
|
+
type: "object",
|
|
862
|
+
fields: [
|
|
863
|
+
sanity.defineField({
|
|
864
|
+
name: "noIndex",
|
|
865
|
+
title: "No Index",
|
|
866
|
+
type: "boolean",
|
|
867
|
+
initialValue: !1,
|
|
868
|
+
description: "Enable this to prevent search engines from indexing this page. The page will not appear in search results."
|
|
869
|
+
}),
|
|
870
|
+
sanity.defineField({
|
|
871
|
+
name: "noFollow",
|
|
872
|
+
title: "No Follow",
|
|
873
|
+
type: "boolean",
|
|
874
|
+
initialValue: !1,
|
|
875
|
+
description: "Enable this to prevent search engines from following links on this page. Links will not pass SEO value."
|
|
876
|
+
})
|
|
877
|
+
],
|
|
878
|
+
description: "Select how search engines should index and follow links on this page."
|
|
872
879
|
});
|
|
873
880
|
function types(config = {}) {
|
|
874
881
|
return [
|
|
@@ -889,35 +896,9 @@ const seofields = sanity.definePlugin((config = {}) => ({
|
|
|
889
896
|
types: types(config)
|
|
890
897
|
// pass config down to schemas
|
|
891
898
|
}
|
|
892
|
-
}))
|
|
893
|
-
title: {
|
|
894
|
-
maxLength: 70,
|
|
895
|
-
warningLength: 60
|
|
896
|
-
},
|
|
897
|
-
description: {
|
|
898
|
-
maxLength: 160,
|
|
899
|
-
warningLength: 150
|
|
900
|
-
},
|
|
901
|
-
openGraphTitle: {
|
|
902
|
-
maxLength: 95
|
|
903
|
-
},
|
|
904
|
-
openGraphDescription: {
|
|
905
|
-
maxLength: 200
|
|
906
|
-
},
|
|
907
|
-
twitterTitle: {
|
|
908
|
-
maxLength: 70
|
|
909
|
-
},
|
|
910
|
-
twitterDescription: {
|
|
911
|
-
maxLength: 200
|
|
912
|
-
}
|
|
913
|
-
};
|
|
899
|
+
}));
|
|
914
900
|
exports.allSchemas = types;
|
|
915
901
|
exports.default = seofields;
|
|
916
|
-
exports.defaultSeoValidationRules = defaultSeoValidationRules;
|
|
917
|
-
exports.isMetaAttribute = isMetaAttribute;
|
|
918
|
-
exports.isOpenGraphSettings = isOpenGraphSettings;
|
|
919
|
-
exports.isSeoFields = isSeoFields;
|
|
920
|
-
exports.isTwitterCardSettings = isTwitterCardSettings;
|
|
921
902
|
exports.metaAttributeSchema = metaAttribute;
|
|
922
903
|
exports.metaTagSchema = metaTag;
|
|
923
904
|
exports.openGraphSchema = openGraph;
|