sanity-plugin-seo
Version:
The Sanity SEO Field Plugin simplifies the process of generating SEO fields for various types of content. It enhances structured data, making your content more accessible and understandable for search engines, ultimately improving your site's visibility a
398 lines (396 loc) • 10.2 kB
JavaScript
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true
});
var sanity = require('sanity');
var jsxRuntime = require('react/jsx-runtime');
var react = require('react');
var ui = require('@sanity/ui');
const SEOTitleFeedback = props => {
const client = sanity.useClient({
apiVersion: "2021-06-07"
});
const {
value,
onChange,
renderDefault
} = props;
const {
path
} = props;
const parentPath = path.slice(0, -1);
const parent = sanity.useFormValue(parentPath);
const keywords = (parent == null ? void 0 : parent.seoKeywords) || [];
react.useEffect(() => {
if (value) return;
const fetchData = async () => {
const data = await client.fetch("*[_type=='homePage'][0]{'title':seo.metaTitle}");
const titleFromHomePage = data == null ? void 0 : data.title;
if (titleFromHomePage && !value) {
onChange(sanity.set(titleFromHomePage));
}
};
fetchData();
}, [client, onChange, value]);
const getTitleFeedback = (title, seoKeywords) => {
const feedbackItems2 = [];
if (!(title == null ? void 0 : title.trim())) {
feedbackItems2.push({
text: "Your title is empty. Please add some content for better SEO.",
color: "red"
});
return feedbackItems2;
}
const charCount = title.length;
const minChar = 50;
const maxChar = 60;
if (charCount < minChar) {
feedbackItems2.push({
text: "Your title is only ".concat(charCount, " characters long \u2014 below ").concat(minChar, "."),
color: "orange"
});
} else if (charCount > maxChar) {
feedbackItems2.push({
text: "Your title is ".concat(charCount, " characters long \u2014 above ").concat(maxChar, "."),
color: "red"
});
} else {
feedbackItems2.push({
text: "Great! Your title length (".concat(charCount, ") looks good for SEO."),
color: "green"
});
}
if (seoKeywords.length > 0) {
const foundKeyword = seoKeywords.some(kw => title.toLowerCase().includes(kw.toLowerCase()));
if (!foundKeyword) {
feedbackItems2.push({
text: "You have defined keywords but none appear in the title.",
color: "red"
});
} else {
feedbackItems2.push({
text: "Your keyword is in the title. Good job!",
color: "green"
});
}
} else {
feedbackItems2.push({
text: "No keywords defined. Consider adding relevant keywords for better SEO.",
color: "orange"
});
}
return feedbackItems2;
};
const feedbackItems = getTitleFeedback(value || "", keywords);
return /* @__PURE__ */jsxRuntime.jsxs(ui.Stack, {
space: 3,
children: [renderDefault(props), /* @__PURE__ */jsxRuntime.jsx(ui.Stack, {
space: 2,
children: feedbackItems.map(item => /* @__PURE__ */jsxRuntime.jsxs("div", {
style: {
display: "flex",
alignItems: "center",
gap: "7px"
},
children: [/* @__PURE__ */jsxRuntime.jsx("div", {
style: {
width: "10px",
height: "10px",
borderRadius: "50%",
backgroundColor: item.color
}
}), /* @__PURE__ */jsxRuntime.jsx(ui.Text, {
weight: "bold",
muted: true,
size: 14,
children: item.text
})]
}, item.text))
})]
});
};
const SEODescriptionFeedback = props => {
const {
value,
renderDefault,
onChange
} = props;
const client = sanity.useClient({
apiVersion: "2021-06-07"
});
const {
path
} = props;
const parentPath = path.slice(0, -1);
const parent = sanity.useFormValue(parentPath);
const description = (parent == null ? void 0 : parent.metaDescription) || "";
react.useEffect(() => {
const fetchData = async () => {
await client.fetch("*[_type=='homePage'][0]{'description':seo.metaDescription}").then(data => {
const descriptionFromHomePage = data == null ? void 0 : data.description;
if (descriptionFromHomePage && !value) {
onChange(sanity.set(descriptionFromHomePage));
}
});
};
fetchData();
}, [client, onChange, value]);
const getDescriptionFeedback = metaDescription => {
if (!metaDescription || !metaDescription.trim()) {
return {
text: "No meta description has been specified. Search engines will display copy from the page instead. Make sure to write one!",
color: "red"
};
}
const charCount = metaDescription.trim().length;
const minLength = 100;
const maxLength = 160;
if (charCount < minLength) {
return {
text: "The meta description is too short at ".concat(charCount, " characters. You have up to ").concat(maxLength, " characters to use \u2014 make the most of it!"),
color: "orange"
};
}
if (charCount > maxLength) {
return {
text: "The meta description is too long at ".concat(charCount, " characters. It may get truncated in search results. Try keeping it under ").concat(maxLength, "."),
color: "red"
};
}
return {
text: "Well done! Your meta description length looks good for SEO.",
color: "green"
};
};
const {
text,
color
} = getDescriptionFeedback(value || description);
return /* @__PURE__ */jsxRuntime.jsxs(ui.Stack, {
space: 3,
children: [renderDefault(props), /* @__PURE__ */jsxRuntime.jsxs("div", {
style: {
display: "flex",
alignItems: "center",
gap: "7px"
},
children: [/* @__PURE__ */jsxRuntime.jsx("div", {
style: {
minWidth: "15px"
},
children: /* @__PURE__ */jsxRuntime.jsx("div", {
style: {
width: "10px",
height: "10px",
backgroundColor: color,
borderRadius: "50%"
}
})
}), /* @__PURE__ */jsxRuntime.jsxs(ui.Text, {
weight: "bold",
muted: true,
size: 14,
children: ["Meta description length: ", text]
})]
})]
});
};
const schema = sanity.defineType({
title: "Seo MetaFields",
name: "seoMetaFields",
type: "object",
fields: [{
name: "nofollowAttributes",
title: "Noindex",
type: "boolean",
initialValue: false,
description: "To prevent a URL from being indexed, you'll also need to select the true Noindex on the tag."
}, {
name: "metaTitle",
title: "Title",
type: "string",
components: {
input: SEOTitleFeedback
}
}, {
name: "metaDescription",
title: "Description",
type: "string",
components: {
input: SEODescriptionFeedback
}
}, {
name: "metaImage",
title: "Meta Image",
type: "image"
}, {
name: "seoKeywords",
title: "Keywords",
type: "array",
of: [{
type: "string"
}]
}, {
name: "openGraph",
title: "Open Graph",
type: "openGraph"
}, {
name: "additionalMetaTags",
title: "Additional Meta Tags",
type: "array",
of: [{
type: "metaTag"
}]
}, {
name: "twitter",
title: "Twitter",
type: "twitter"
}]
});
var metaAttribute = {
name: "metaAttribute",
title: "Meta Attribute",
type: "object",
fields: [{
name: "attributeKey",
title: "Key",
type: "string"
}, {
name: "attributeType",
title: "type",
type: "string",
options: {
list: ["string", "image"],
layout: "radio",
direction: "horizontal"
},
initialValue: "image"
}, {
name: "attributeValueImage",
title: "Value",
type: "image",
hidden: _ref => {
let {
parent
} = _ref;
return (parent == null ? void 0 : parent.attributeType) !== "image";
}
}, {
name: "attributeValueString",
title: "Value",
type: "string",
hidden: _ref2 => {
let {
parent
} = _ref2;
return (parent == null ? void 0 : parent.attributeType) !== "string";
}
}],
preview: {
select: {
title: "attributeKey"
},
prepare(_ref3) {
let {
title
} = _ref3;
return {
title
};
}
}
};
var metaTag = {
name: "metaTag",
title: "Meta tag",
type: "object",
fields: [{
name: "metaAttributes",
title: "Meta Attributes",
type: "array",
of: [{
type: "metaAttribute"
}]
}],
preview: {
select: {
title: "attributeName",
metaTags: "metaAttributes"
},
prepare(_ref4) {
let {
metaTags
} = _ref4;
var _a, _b;
return {
title: metaTags && ((_a = metaTags[0]) == null ? void 0 : _a.attributeValueString) ? (_b = metaTags[0]) == null ? void 0 : _b.attributeValueString : "Meta Tag"
};
}
}
};
var openGraph = {
name: "openGraph",
title: "Open Graph",
type: "object",
description: "Control how your content appears when shared on social media platforms (e.g., Facebook, LinkedIn) or in messaging apps (e.g., Slack, WhatsApp).",
fields: [{
name: "url",
title: "URL",
type: "string"
}, {
name: "image",
title: "Image",
type: "image"
}, {
name: "title",
title: "Title",
type: "string",
components: {
input: SEOTitleFeedback
}
}, {
name: "description",
title: "Description",
type: "string",
components: {
input: SEODescriptionFeedback
}
}, {
name: "siteName",
title: "Site Name",
type: "string"
}]
};
var twitter = {
name: "twitter",
title: "Twitter",
type: "object",
fields: [{
name: "cardType",
title: "CardType",
type: "string"
}, {
name: "creator",
title: "Creator",
type: "string"
}, {
name: "site",
title: "Site",
type: "string"
}, {
name: "handle",
title: "Handle",
type: "string"
}]
};
const types = [schema, metaAttribute, metaTag, openGraph, twitter];
const seoMetaFields = sanity.definePlugin(() => {
return {
name: "sanity-plugin-seo",
schema: {
types
}
};
});
exports.seoMetaFields = seoMetaFields;
//# sourceMappingURL=index.js.map