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