sanity-plugin-seofields 1.2.0 → 1.2.2

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/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: !0 });
3
- var o = require("react"), sanity = require("sanity"), jsxRuntime = require("react/jsx-runtime"), router = require("sanity/router"), ui = require("@sanity/ui");
3
+ var o = require("react"), sanity = require("sanity"), jsxRuntime = require("react/jsx-runtime"), router = require("sanity/router"), structure = require("sanity/structure"), ui = require("@sanity/ui");
4
4
  function _interopDefaultCompat(e) {
5
5
  return e && typeof e == "object" && "default" in e ? e : { default: e };
6
6
  }
@@ -1172,22 +1172,29 @@ const DashboardContainer = dt.div`
1172
1172
  font-weight: 700;
1173
1173
  color: #111827;
1174
1174
  letter-spacing: -0.3px;
1175
+ display: flex;
1176
+ align-items: center;
1177
+ gap: 10px;
1178
+ `, PreviewBadge = dt.span`
1179
+ display: inline-block;
1180
+ background: #fef3c7;
1181
+ color: #92400e;
1182
+ font-size: 11px;
1183
+ font-weight: 600;
1184
+ padding: 4px 8px;
1185
+ border-radius: 4px;
1186
+ text-transform: uppercase;
1187
+ letter-spacing: 0.5px;
1188
+ margin-left: 8px;
1175
1189
  `, PageSubtitle = dt.p`
1176
1190
  margin: 0;
1177
1191
  font-size: 13px;
1178
1192
  color: #6b7280;
1179
1193
  `, StatsGrid = dt.div`
1180
1194
  display: grid;
1181
- grid-template-columns: repeat(6, 1fr);
1195
+ grid-template-columns: repeat(auto-fit, minmax(130px, 1fr));
1182
1196
  gap: 14px;
1183
1197
  margin-bottom: 20px;
1184
-
1185
- @media (max-width: 1100px) {
1186
- grid-template-columns: repeat(3, 1fr);
1187
- }
1188
- @media (max-width: 600px) {
1189
- grid-template-columns: repeat(2, 1fr);
1190
- }
1191
1198
  `, StatCard = dt.div`
1192
1199
  background: #ffffff;
1193
1200
  border-radius: 10px;
@@ -1320,6 +1327,11 @@ const DashboardContainer = dt.div`
1320
1327
  align-items: center;
1321
1328
  gap: 4px;
1322
1329
  flex-wrap: wrap;
1330
+ min-width: 0;
1331
+ `, TitleCell = dt.div`
1332
+ min-width: 0;
1333
+ overflow: hidden;
1334
+ flex: 1;
1323
1335
  `, ColType = dt.div`
1324
1336
  flex: 0.8;
1325
1337
  min-width: 80px;
@@ -1357,8 +1369,8 @@ const DashboardContainer = dt.div`
1357
1369
  border-radius: 5px;
1358
1370
  font-size: 11px;
1359
1371
  font-weight: 500;
1360
- background: #ede9fe;
1361
- color: #5b21b6;
1372
+ background: ${(p) => p.$bgColor || "#ede9fe"};
1373
+ color: ${(p) => p.$textColor || "#5b21b6"};
1362
1374
  `, TypeText = dt.span`
1363
1375
  font-size: 12px;
1364
1376
  font-weight: 500;
@@ -1518,6 +1530,34 @@ const DashboardContainer = dt.div`
1518
1530
  }) => {
1519
1531
  const { onClick, href } = router.useIntentLink({ intent: "edit", params: { id, type } });
1520
1532
  return /* @__PURE__ */ jsxRuntime.jsx(DocTitleLink, { href, onClick, title: "Open document", children });
1533
+ }, PaneLinkWrapper = dt.span`
1534
+ display: block;
1535
+ min-width: 0;
1536
+ overflow: hidden;
1537
+
1538
+ a {
1539
+ font-size: 13px;
1540
+ font-weight: 600;
1541
+ color: #4f46e5;
1542
+ white-space: nowrap;
1543
+ overflow: hidden;
1544
+ text-overflow: ellipsis;
1545
+ text-decoration: none;
1546
+ display: block;
1547
+ transition: color 0.15s;
1548
+
1549
+ &:hover {
1550
+ color: #4338ca;
1551
+ text-decoration: underline;
1552
+ }
1553
+ }
1554
+ `, DocTitleAnchorPane = ({
1555
+ id,
1556
+ type,
1557
+ children
1558
+ }) => {
1559
+ const { ChildLink } = structure.usePaneRouter();
1560
+ return /* @__PURE__ */ jsxRuntime.jsx(PaneLinkWrapper, { children: /* @__PURE__ */ jsxRuntime.jsx(ChildLink, { childId: id, childParameters: { type }, children }) });
1521
1561
  }, DocBadgeRenderer = ({ doc, docBadge }) => {
1522
1562
  const badge = docBadge(doc);
1523
1563
  return badge ? /* @__PURE__ */ jsxRuntime.jsx(CustomBadge, { $bgColor: badge.bgColor, $textColor: badge.textColor, $fontSize: badge.fontSize, children: badge.label }) : null;
@@ -1541,7 +1581,48 @@ const DashboardContainer = dt.div`
1541
1581
  text-align: center;
1542
1582
  color: #9ca3af;
1543
1583
  font-size: 13px;
1544
- `, getStatusCategory = (score) => score >= 80 ? "excellent" : score >= 60 ? "good" : score >= 40 ? "fair" : score > 0 ? "poor" : "missing", scoreMetaTitle = (title) => {
1584
+ `, TYPE_COLOR_PALETTE = [
1585
+ { bg: "#dbeafe", text: "#0c4a6e" },
1586
+ // Blue
1587
+ { bg: "#dcfce7", text: "#14532d" },
1588
+ // Green
1589
+ { bg: "#fce7f3", text: "#500724" },
1590
+ // Pink
1591
+ { bg: "#fed7aa", text: "#7c2d12" },
1592
+ // Orange
1593
+ { bg: "#e9d5ff", text: "#581c87" },
1594
+ // Purple
1595
+ { bg: "#f3e8ff", text: "#3f0f5c" },
1596
+ // Deep Purple
1597
+ { bg: "#ccfbf1", text: "#134e4a" },
1598
+ // Teal
1599
+ { bg: "#ddd6fe", text: "#3730a3" },
1600
+ // Indigo
1601
+ { bg: "#fca5a5", text: "#7f1d1d" },
1602
+ // Red
1603
+ { bg: "#a7f3d0", text: "#065f46" },
1604
+ // Emerald
1605
+ { bg: "#fbbf24", text: "#78350f" },
1606
+ // Amber
1607
+ { bg: "#c4b5fd", text: "#3b0764" },
1608
+ // Violet
1609
+ { bg: "#f0fdf4", text: "#15803d" },
1610
+ // Light Green
1611
+ { bg: "#fef2f2", text: "#991b1b" },
1612
+ // Light Red
1613
+ { bg: "#f5f3ff", text: "#5b21b6" },
1614
+ // Light Purple
1615
+ { bg: "#fffbeb", text: "#92400e" }
1616
+ // Light Amber
1617
+ ], getTypeColor = (type) => {
1618
+ let hash2 = 0;
1619
+ for (let i = 0; i < type.length; i += 1) {
1620
+ const char2 = type.charCodeAt(i);
1621
+ hash2 = Math.abs(hash2 * 31 + char2);
1622
+ }
1623
+ const colorIndex = hash2 % TYPE_COLOR_PALETTE.length;
1624
+ return TYPE_COLOR_PALETTE[colorIndex];
1625
+ }, getStatusCategory = (score) => score >= 80 ? "excellent" : score >= 60 ? "good" : score >= 40 ? "fair" : score > 0 ? "poor" : "missing", scoreMetaTitle = (title) => {
1545
1626
  const issues = [];
1546
1627
  let score = 0;
1547
1628
  return title && title.length >= 50 && title.length <= 60 ? score = 15 : title && title.length > 0 ? (score = 10, title.length < 50 && issues.push("Meta title too short (< 50 chars)"), title.length > 60 && issues.push("Meta title too long (> 60 chars)")) : issues.push("Missing meta title"), { score, issues };
@@ -1572,7 +1653,135 @@ const DashboardContainer = dt.div`
1572
1653
  totalScore += twitterScore.score, allIssues.push(...twitterScore.issues), robots2 && !robots2.noIndex && (totalScore += 5);
1573
1654
  const status = getStatusCategory(totalScore);
1574
1655
  return { score: totalScore, status, issues: allIssues };
1575
- }, resolveTypeLabel = (type, typeLabels) => typeLabels?.[type] ?? type, buildTitleProjection = (titleField) => !titleField || titleField === "title" ? "title" : typeof titleField == "string" ? `"title": ${titleField}` : `"title": select(${Object.entries(titleField).map(([type, field]) => `_type == "${type}" => ${field}`).join(", ")}, title)`, SeoHealthDashboard = ({
1656
+ }, resolveTypeLabel = (type, typeLabels) => typeLabels?.[type] ?? type, buildTitleProjection = (titleField) => !titleField || titleField === "title" ? "title" : typeof titleField == "string" ? `"title": ${titleField}` : `"title": select(${Object.entries(titleField).map(([type, field]) => `_type == "${type}" => ${field}`).join(", ")}, title)`, generateDummyData = () => [
1657
+ {
1658
+ _id: "preview-post-1",
1659
+ _type: "post",
1660
+ title: "Getting Started with SEO Best Practices",
1661
+ slug: { current: "getting-started-seo" },
1662
+ _updatedAt: new Date(Date.now() - 1728e5).toISOString(),
1663
+ seo: {
1664
+ title: "Getting Started with SEO Best Practices | My Blog",
1665
+ description: "Learn the fundamentals of SEO optimization to improve your website visibility and search rankings.",
1666
+ keywords: ["seo", "best practices", "optimization"],
1667
+ metaImage: { _type: "image", asset: { _ref: "image-123", _type: "reference" } },
1668
+ openGraph: {
1669
+ title: "SEO Best Practices Guide",
1670
+ description: "Master SEO optimization",
1671
+ image: { _type: "image", asset: { _ref: "image-123", _type: "reference" }, alt: "SEO Guide" },
1672
+ type: "article"
1673
+ },
1674
+ twitter: {
1675
+ title: "SEO Best Practices",
1676
+ description: "Learn SEO optimization",
1677
+ image: { _type: "image", asset: { _ref: "image-123", _type: "reference" }, alt: "Guide" },
1678
+ card: "summary_large_image"
1679
+ }
1680
+ }
1681
+ },
1682
+ {
1683
+ _id: "preview-post-2",
1684
+ _type: "post",
1685
+ title: "Advanced Analytics Strategy",
1686
+ slug: { current: "advanced-analytics" },
1687
+ _updatedAt: new Date(Date.now() - 432e6).toISOString(),
1688
+ seo: {
1689
+ title: "Advanced Analytics",
1690
+ description: "Strategy tips",
1691
+ keywords: ["analytics", "data"],
1692
+ openGraph: {
1693
+ title: "Analytics Guide"
1694
+ }
1695
+ }
1696
+ },
1697
+ {
1698
+ _id: "preview-page-1",
1699
+ _type: "page",
1700
+ title: "About Us",
1701
+ slug: { current: "about" },
1702
+ _updatedAt: new Date(Date.now() - 864e6).toISOString(),
1703
+ seo: {
1704
+ title: "About",
1705
+ keywords: ["company", "team"],
1706
+ metaImage: { _type: "image", asset: { _ref: "image-456", _type: "reference" } }
1707
+ }
1708
+ },
1709
+ {
1710
+ _id: "preview-post-3",
1711
+ _type: "post",
1712
+ title: "Content Marketing Trends for 2024",
1713
+ slug: { current: "content-marketing-trends" },
1714
+ _updatedAt: new Date(Date.now() - 864e5).toISOString(),
1715
+ seo: {
1716
+ title: "Content Marketing Trends 2024",
1717
+ description: "Discover the latest content marketing trends and strategies to engage your audience effectively.",
1718
+ keywords: ["content marketing", "trends", "strategy", "engagement"],
1719
+ metaImage: { _type: "image", asset: { _ref: "image-789", _type: "reference" } },
1720
+ openGraph: {
1721
+ title: "Content Marketing Trends 2024",
1722
+ description: "Latest trends in content marketing",
1723
+ image: { _type: "image", asset: { _ref: "image-789", _type: "reference" }, alt: "Trends" },
1724
+ type: "article"
1725
+ },
1726
+ twitter: {
1727
+ title: "Content Marketing Trends",
1728
+ description: "Discover the latest trends",
1729
+ card: "summary"
1730
+ }
1731
+ }
1732
+ },
1733
+ {
1734
+ _id: "preview-post-4",
1735
+ _type: "product",
1736
+ title: "Pro Plan",
1737
+ slug: { current: "pro-plan" },
1738
+ _updatedAt: new Date(Date.now() - 1296e6).toISOString(),
1739
+ seo: {
1740
+ title: "Pro",
1741
+ keywords: ["pricing"]
1742
+ }
1743
+ },
1744
+ {
1745
+ _id: "preview-page-2",
1746
+ _type: "page",
1747
+ title: "Contact",
1748
+ slug: { current: "contact" },
1749
+ _updatedAt: new Date(Date.now() - 6912e5).toISOString(),
1750
+ seo: {
1751
+ openGraph: {
1752
+ title: "Get in Touch"
1753
+ }
1754
+ }
1755
+ },
1756
+ {
1757
+ _id: "preview-post-5",
1758
+ _type: "post",
1759
+ title: "Mobile Optimization Guide",
1760
+ slug: { current: "mobile-optimization" },
1761
+ _updatedAt: new Date(Date.now() - 2592e5).toISOString(),
1762
+ seo: {
1763
+ title: "Mobile Optimization Guide: Best Practices for Responsive Design",
1764
+ description: "Complete guide to mobile optimization including responsive design, performance tips, and user experience best practices for modern web development.",
1765
+ keywords: ["mobile", "optimization", "responsive", "performance"],
1766
+ metaImage: { _type: "image", asset: { _ref: "image-mobile", _type: "reference" } },
1767
+ openGraph: {
1768
+ title: "Mobile Optimization Best Practices",
1769
+ description: "Master mobile web optimization",
1770
+ image: { _type: "image", asset: { _ref: "image-mobile", _type: "reference" }, alt: "Mobile" },
1771
+ type: "article"
1772
+ },
1773
+ twitter: {
1774
+ title: "Mobile Optimization Tips",
1775
+ description: "Responsive design best practices",
1776
+ image: { _type: "image", asset: { _ref: "image-mobile", _type: "reference" }, alt: "Mobile" },
1777
+ card: "summary_large_image"
1778
+ }
1779
+ }
1780
+ }
1781
+ ].map((doc) => ({
1782
+ ...doc,
1783
+ health: calculateHealthScore(doc)
1784
+ })), SeoHealthDashboard = ({
1576
1785
  icon = "\u{1F4CA}",
1577
1786
  title = "SEO Health Dashboard",
1578
1787
  description = "Monitor and optimize SEO fields across all your documents",
@@ -1589,10 +1798,16 @@ const DashboardContainer = dt.div`
1589
1798
  docBadge,
1590
1799
  loadingLicense,
1591
1800
  loadingDocuments,
1592
- noDocuments
1801
+ noDocuments,
1802
+ previewMode = !1,
1803
+ openInPane = !1
1593
1804
  }) => {
1594
1805
  const client = sanity.useClient({ apiVersion }), [licenseStatus, setLicenseStatus] = o.useState("loading"), [documents, setDocuments] = o.useState([]), [loading, setLoading] = o.useState(!0), [searchQuery, setSearchQuery] = o.useState(""), [filterStatus, setFilterStatus] = o.useState("all"), [filterType, setFilterType] = o.useState("all"), [sortBy, setSortBy] = o.useState("score"), [activePopover, setActivePopover] = o.useState(null), VALIDATION_ENDPOINT = "https://sanity-plugin-seofields.thehardik.in/api/validate-license", CACHE_TTL_MS = 3600 * 1e3, validateLicense = o.useCallback(
1595
1806
  async (forceRefresh = !1) => {
1807
+ if (previewMode) {
1808
+ setLicenseStatus("valid");
1809
+ return;
1810
+ }
1596
1811
  if (!licenseKey) {
1597
1812
  setLicenseStatus("invalid");
1598
1813
  return;
@@ -1632,11 +1847,11 @@ const DashboardContainer = dt.div`
1632
1847
  }
1633
1848
  },
1634
1849
  // eslint-disable-next-line react-hooks/exhaustive-deps
1635
- [licenseKey]
1850
+ [licenseKey, previewMode]
1636
1851
  );
1637
1852
  o.useEffect(() => {
1638
1853
  validateLicense();
1639
- }, [licenseKey]);
1854
+ }, [licenseKey, previewMode]);
1640
1855
  const handleMouseEnterIssues = (el, issues) => {
1641
1856
  if (!el) return;
1642
1857
  const rect = el.getBoundingClientRect(), popoverWidth = 280, viewportWidth = window.innerWidth;
@@ -1646,7 +1861,10 @@ const DashboardContainer = dt.div`
1646
1861
  o.useEffect(() => {
1647
1862
  (async () => {
1648
1863
  try {
1649
- setLoading(!0);
1864
+ if (setLoading(!0), previewMode) {
1865
+ setDocuments(generateDummyData());
1866
+ return;
1867
+ }
1650
1868
  let groqQuery, params = {};
1651
1869
  if (customQuery)
1652
1870
  groqQuery = customQuery;
@@ -1680,7 +1898,16 @@ const DashboardContainer = dt.div`
1680
1898
  setLoading(!1);
1681
1899
  }
1682
1900
  })();
1683
- }, [client, customQuery, queryRequireSeo, JSON.stringify(queryTypes), JSON.stringify(titleField)]);
1901
+ }, [
1902
+ client,
1903
+ customQuery,
1904
+ queryRequireSeo,
1905
+ // eslint-disable-next-line react-hooks/exhaustive-deps
1906
+ JSON.stringify(queryTypes),
1907
+ // eslint-disable-next-line react-hooks/exhaustive-deps
1908
+ JSON.stringify(titleField),
1909
+ previewMode
1910
+ ]);
1684
1911
  const uniqueDocumentTypes = o.useMemo(() => {
1685
1912
  const types2 = new Set(documents.map((doc) => doc._type));
1686
1913
  return Array.from(types2).sort();
@@ -1749,9 +1976,12 @@ export default defineConfig({
1749
1976
  licenseStatus === "valid" && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1750
1977
  /* @__PURE__ */ jsxRuntime.jsxs(PageHeader, { children: [
1751
1978
  /* @__PURE__ */ jsxRuntime.jsxs(PageTitle, { children: [
1752
- icon,
1753
- " ",
1754
- title
1979
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
1980
+ icon,
1981
+ " ",
1982
+ title
1983
+ ] }),
1984
+ previewMode && /* @__PURE__ */ jsxRuntime.jsx(PreviewBadge, { children: "Preview Mode" })
1755
1985
  ] }),
1756
1986
  /* @__PURE__ */ jsxRuntime.jsx(PageSubtitle, { children: description })
1757
1987
  ] }),
@@ -1855,8 +2085,8 @@ export default defineConfig({
1855
2085
  ] }),
1856
2086
  filteredAndSortedDocs.map((doc) => /* @__PURE__ */ jsxRuntime.jsxs(TableRow, { children: [
1857
2087
  /* @__PURE__ */ jsxRuntime.jsx(ColTitle, { children: /* @__PURE__ */ jsxRuntime.jsxs(TitleWrapper, { children: [
1858
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
1859
- /* @__PURE__ */ jsxRuntime.jsx(DocTitleAnchor, { id: doc._id, type: doc._type, children: doc.title || "Untitled" }),
2088
+ /* @__PURE__ */ jsxRuntime.jsxs(TitleCell, { children: [
2089
+ openInPane ? /* @__PURE__ */ jsxRuntime.jsx(DocTitleAnchorPane, { id: doc._id, type: doc._type, children: doc.title || "Untitled" }) : /* @__PURE__ */ jsxRuntime.jsx(DocTitleAnchor, { id: doc._id, type: doc._type, children: doc.title || "Untitled" }),
1860
2090
  showDocumentId && /* @__PURE__ */ jsxRuntime.jsx(DocId, { children: doc._id })
1861
2091
  ] }),
1862
2092
  docBadge && /* @__PURE__ */ jsxRuntime.jsx(
@@ -1867,7 +2097,10 @@ export default defineConfig({
1867
2097
  }
1868
2098
  )
1869
2099
  ] }) }),
1870
- showTypeColumn && /* @__PURE__ */ jsxRuntime.jsx(ColType, { children: typeColumnMode === "text" ? /* @__PURE__ */ jsxRuntime.jsx(TypeText, { children: resolveTypeLabel(doc._type, typeLabels) }) : /* @__PURE__ */ jsxRuntime.jsx(TypeBadge, { children: resolveTypeLabel(doc._type, typeLabels) }) }),
2100
+ showTypeColumn && /* @__PURE__ */ jsxRuntime.jsx(ColType, { children: typeColumnMode === "text" ? /* @__PURE__ */ jsxRuntime.jsx(TypeText, { children: resolveTypeLabel(doc._type, typeLabels) }) : (() => {
2101
+ const typeColor = getTypeColor(doc._type);
2102
+ return /* @__PURE__ */ jsxRuntime.jsx(TypeBadge, { $bgColor: typeColor.bg, $textColor: typeColor.text, children: resolveTypeLabel(doc._type, typeLabels) });
2103
+ })() }),
1871
2104
  /* @__PURE__ */ jsxRuntime.jsx(ColScore, { children: /* @__PURE__ */ jsxRuntime.jsxs(ScoreBadge, { $score: doc.health.score, children: [
1872
2105
  doc.health.score,
1873
2106
  "%"
@@ -2874,7 +3107,8 @@ const resolveDashboardConfig = (healthDashboard) => {
2874
3107
  docBadge: cfg?.docBadge,
2875
3108
  loadingLicense: cfg?.content?.loadingLicense,
2876
3109
  loadingDocuments: cfg?.content?.loadingDocuments,
2877
- noDocuments: cfg?.content?.noDocuments
3110
+ noDocuments: cfg?.content?.noDocuments,
3111
+ previewMode: cfg?.previewMode
2878
3112
  };
2879
3113
  }, seofields = sanity.definePlugin((config = {}) => {
2880
3114
  const { healthDashboard = !0 } = config, dash = resolveDashboardConfig(healthDashboard), BoundSeoHealthTool = () => o__default.default.createElement(SeoHealthTool, {
@@ -2894,7 +3128,8 @@ const resolveDashboardConfig = (healthDashboard) => {
2894
3128
  docBadge: dash.docBadge,
2895
3129
  loadingLicense: dash.loadingLicense,
2896
3130
  loadingDocuments: dash.loadingDocuments,
2897
- noDocuments: dash.noDocuments
3131
+ noDocuments: dash.noDocuments,
3132
+ previewMode: dash.previewMode
2898
3133
  });
2899
3134
  return {
2900
3135
  name: "sanity-plugin-seofields",
@@ -2913,9 +3148,17 @@ const resolveDashboardConfig = (healthDashboard) => {
2913
3148
  }
2914
3149
  };
2915
3150
  });
3151
+ function createSeoHealthPane(optionsOrS, optionsWhenS) {
3152
+ const S2 = optionsOrS, { query, openInPane = !0, title: paneTitle, ...rest } = optionsWhenS ?? {}, SeoHealthPane = () => /* @__PURE__ */ jsxRuntime.jsx(SeoHealthDashboard, { customQuery: query, openInPane, title: paneTitle, ...rest });
3153
+ return SeoHealthPane.displayName = "SeoHealthPane", S2.component(SeoHealthPane).title(paneTitle ?? "SEO Health").child((docId, { params }) => {
3154
+ const builder = S2.document().documentId(docId);
3155
+ return params?.type ? builder.schemaType(params.type) : builder;
3156
+ });
3157
+ }
2916
3158
  exports.SeoHealthDashboard = SeoHealthDashboard;
2917
3159
  exports.SeoHealthTool = SeoHealthTool;
2918
3160
  exports.allSchemas = types;
3161
+ exports.createSeoHealthPane = createSeoHealthPane;
2919
3162
  exports.default = seofields;
2920
3163
  exports.metaAttributeSchema = metaAttribute;
2921
3164
  exports.metaTagSchema = metaTag;