sanity-plugin-seofields 1.2.5 → 1.2.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 +465 -0
- package/dist/index.cjs +2604 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +422 -0
- package/dist/index.d.ts +339 -492
- package/dist/index.js +1284 -2013
- package/dist/index.js.map +1 -1
- package/dist/next.cjs +182 -0
- package/dist/next.cjs.map +1 -0
- package/dist/next.d.cts +241 -0
- package/dist/next.d.ts +202 -295
- package/dist/next.js +110 -70
- package/dist/next.js.map +1 -1
- package/dist/types-B91ena4g.d.cts +89 -0
- package/dist/types-B91ena4g.d.ts +89 -0
- package/package.json +46 -20
- package/dist/index.d.mts +0 -575
- package/dist/index.mjs +0 -3292
- package/dist/index.mjs.map +0 -1
- package/dist/next.d.mts +0 -334
- package/dist/next.mjs +0 -102
- package/dist/next.mjs.map +0 -1
- package/sanity.json +0 -8
- package/src/components/SeoHealthDashboard.tsx +0 -1568
- package/src/components/SeoHealthPane.tsx +0 -81
- package/src/components/SeoHealthTool.tsx +0 -11
- package/src/components/SeoPreview.tsx +0 -178
- package/src/components/meta/MetaDescription.tsx +0 -39
- package/src/components/meta/MetaTitle.tsx +0 -44
- package/src/components/openGraph/OgDescription.tsx +0 -46
- package/src/components/openGraph/OgTitle.tsx +0 -45
- package/src/components/twitter/twitterDescription.tsx +0 -45
- package/src/components/twitter/twitterTitle.tsx +0 -45
- package/src/helpers/SeoMetaTags.tsx +0 -154
- package/src/helpers/seoMeta.ts +0 -283
- package/src/index.ts +0 -26
- package/src/next.ts +0 -12
- package/src/plugin.ts +0 -344
- package/src/schemas/index.ts +0 -121
- package/src/schemas/types/index.ts +0 -20
- package/src/schemas/types/metaAttribute/index.ts +0 -60
- package/src/schemas/types/metaTag/index.ts +0 -17
- package/src/schemas/types/openGraph/index.ts +0 -114
- package/src/schemas/types/robots/index.ts +0 -26
- package/src/schemas/types/twitter/index.ts +0 -108
- package/src/types.ts +0 -108
- package/src/utils/fieldsUtils.ts +0 -160
- package/src/utils/seoUtils.ts +0 -423
- package/src/utils/utils.ts +0 -9
- package/v2-incompatible.js +0 -11
package/README.md
CHANGED
|
@@ -658,6 +658,205 @@ export function SEO({seo}) {
|
|
|
658
658
|
}
|
|
659
659
|
```
|
|
660
660
|
|
|
661
|
+
## 🎯 Framework Integration Examples
|
|
662
|
+
|
|
663
|
+
### Remix (Loader + Action Approach)
|
|
664
|
+
|
|
665
|
+
Handle SEO metadata in Remix loaders for server-side rendering with JSON responses:
|
|
666
|
+
|
|
667
|
+
```typescript
|
|
668
|
+
// routes/posts.$slug.tsx
|
|
669
|
+
import {json, type LoaderFunction} from '@remix-run/node'
|
|
670
|
+
import {useLoaderData} from '@remix-run/react'
|
|
671
|
+
import {buildSeoMeta} from 'sanity-plugin-seofields/utils'
|
|
672
|
+
|
|
673
|
+
export const loader: LoaderFunction = async ({params}) => {
|
|
674
|
+
// Fetch post with SEO fields from Sanity
|
|
675
|
+
const post = await sanityClient.fetch(
|
|
676
|
+
`*[_type == "post" && slug.current == $slug][0]{
|
|
677
|
+
title, content, seo, slug
|
|
678
|
+
}`,
|
|
679
|
+
{slug: params.slug},
|
|
680
|
+
)
|
|
681
|
+
|
|
682
|
+
// Use buildSeoMeta to generate meta tags
|
|
683
|
+
const seoMeta = buildSeoMeta(post.seo, {
|
|
684
|
+
defaultTitle: 'Blog',
|
|
685
|
+
siteUrl: 'https://example.com',
|
|
686
|
+
})
|
|
687
|
+
|
|
688
|
+
return json({post, seoMeta})
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
export const meta: MetaFunction<typeof loader> = ({data}) => {
|
|
692
|
+
return data?.seoMeta || []
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
export default function PostRoute() {
|
|
696
|
+
const {post} = useLoaderData<typeof loader>()
|
|
697
|
+
return <article>{post.title}</article>
|
|
698
|
+
}
|
|
699
|
+
```
|
|
700
|
+
|
|
701
|
+
### Nuxt 3 (Composable Approach)
|
|
702
|
+
|
|
703
|
+
Create a composable for SSR-friendly SEO management:
|
|
704
|
+
|
|
705
|
+
```typescript
|
|
706
|
+
// composables/useSanityMeta.ts
|
|
707
|
+
import {buildSeoMeta} from 'sanity-plugin-seofields/utils'
|
|
708
|
+
|
|
709
|
+
export const useSanityMeta = (seo: SEOFields, options = {}) => {
|
|
710
|
+
const {
|
|
711
|
+
defaultTitle = 'My Site',
|
|
712
|
+
siteUrl = 'https://example.com',
|
|
713
|
+
} = options
|
|
714
|
+
|
|
715
|
+
const meta = buildSeoMeta(seo, {defaultTitle, siteUrl})
|
|
716
|
+
|
|
717
|
+
// useHead() handles SSR + client-side rendering
|
|
718
|
+
useHead({
|
|
719
|
+
title: seo?.title || defaultTitle,
|
|
720
|
+
meta: meta.map(m => ({
|
|
721
|
+
name: m.name || m.property,
|
|
722
|
+
content: m.content,
|
|
723
|
+
})),
|
|
724
|
+
link: seo?.canonicalUrl
|
|
725
|
+
? [{rel: 'canonical', href: seo.canonicalUrl}]
|
|
726
|
+
: [],
|
|
727
|
+
})
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
// pages/blog/[slug].vue
|
|
731
|
+
<script setup lang="ts">
|
|
732
|
+
const route = useRoute()
|
|
733
|
+
const {data: post} = await useFetch(`/api/posts/${route.params.slug}`)
|
|
734
|
+
|
|
735
|
+
useSanityMeta(post.value?.seo, {
|
|
736
|
+
siteUrl: 'https://example.com',
|
|
737
|
+
})
|
|
738
|
+
</script>
|
|
739
|
+
|
|
740
|
+
<template>
|
|
741
|
+
<article v-if="post">
|
|
742
|
+
<h1>{{ post.title }}</h1>
|
|
743
|
+
</article>
|
|
744
|
+
</template>
|
|
745
|
+
```
|
|
746
|
+
|
|
747
|
+
### Astro (Server-Side Rendering)
|
|
748
|
+
|
|
749
|
+
Leverage Astro's component-level SEO with static generation:
|
|
750
|
+
|
|
751
|
+
```typescript
|
|
752
|
+
// src/pages/blog/[slug].astro
|
|
753
|
+
---
|
|
754
|
+
import {buildSeoMeta} from 'sanity-plugin-seofields/utils'
|
|
755
|
+
import Layout from '../../layouts/Layout.astro'
|
|
756
|
+
|
|
757
|
+
// Fetch from Sanity at build time
|
|
758
|
+
const {slug} = Astro.params
|
|
759
|
+
const post = await sanityClient.fetch(
|
|
760
|
+
`*[_type == "post" && slug.current == $slug][0]{
|
|
761
|
+
title, content, seo, slug
|
|
762
|
+
}`,
|
|
763
|
+
{slug},
|
|
764
|
+
)
|
|
765
|
+
|
|
766
|
+
// Generate meta tags for static HTML
|
|
767
|
+
const seoMeta = buildSeoMeta(post.seo, {
|
|
768
|
+
defaultTitle: 'Blog',
|
|
769
|
+
siteUrl: Astro.site,
|
|
770
|
+
})
|
|
771
|
+
---
|
|
772
|
+
|
|
773
|
+
<Layout
|
|
774
|
+
title={post.seo?.title}
|
|
775
|
+
meta={seoMeta}
|
|
776
|
+
canonicalUrl={post.seo?.canonicalUrl}
|
|
777
|
+
>
|
|
778
|
+
<article>
|
|
779
|
+
<h1>{post.title}</h1>
|
|
780
|
+
</article>
|
|
781
|
+
</Layout>
|
|
782
|
+
|
|
783
|
+
<!-- Astro layouts handle meta tag rendering -->
|
|
784
|
+
```
|
|
785
|
+
|
|
786
|
+
### React SPA (Client-Side with Helmet)
|
|
787
|
+
|
|
788
|
+
For client-rendered React apps without SSR:
|
|
789
|
+
|
|
790
|
+
```typescript
|
|
791
|
+
// components/PostHead.tsx
|
|
792
|
+
import {Helmet} from 'react-helmet-async'
|
|
793
|
+
import type {SEOFields} from 'sanity-plugin-seofields'
|
|
794
|
+
|
|
795
|
+
interface PostHeadProps {
|
|
796
|
+
seo?: SEOFields
|
|
797
|
+
fallbackTitle: string
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
export function PostHead({seo, fallbackTitle}: PostHeadProps) {
|
|
801
|
+
return (
|
|
802
|
+
<Helmet>
|
|
803
|
+
{/* Basic Meta */}
|
|
804
|
+
<title>{seo?.title || fallbackTitle}</title>
|
|
805
|
+
<meta name="description" content={seo?.description || ''} />
|
|
806
|
+
|
|
807
|
+
{/* Open Graph - critical for social shares */}
|
|
808
|
+
<meta property="og:title" content={seo?.openGraph?.title} />
|
|
809
|
+
<meta property="og:description" content={seo?.openGraph?.description} />
|
|
810
|
+
{seo?.openGraph?.image?.url && (
|
|
811
|
+
<meta property="og:image" content={seo.openGraph.image.url} />
|
|
812
|
+
)}
|
|
813
|
+
|
|
814
|
+
{/* Robots */}
|
|
815
|
+
{seo?.robots?.noIndex && <meta name="robots" content="noindex" />}
|
|
816
|
+
|
|
817
|
+
{/* Canonical (limit crawl budget) */}
|
|
818
|
+
{seo?.canonicalUrl && (
|
|
819
|
+
<link rel="canonical" href={seo.canonicalUrl} />
|
|
820
|
+
)}
|
|
821
|
+
</Helmet>
|
|
822
|
+
)
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
// Usage in page component
|
|
826
|
+
// Note: Client-side rendering cannot inject meta tags pre-page-load.
|
|
827
|
+
// For public pages, use SSR or static generation instead.
|
|
828
|
+
```
|
|
829
|
+
|
|
830
|
+
---
|
|
831
|
+
|
|
832
|
+
## 🚀 Migrating from Other SEO Plugins
|
|
833
|
+
|
|
834
|
+
Coming from **Yoast**, **All in One SEO**, or **RankMath**?
|
|
835
|
+
|
|
836
|
+
| Feature | Yoast | All in One SEO | RankMath | sanity-plugin-seofields |
|
|
837
|
+
|---------|-------|----------------|----------|------------------------|
|
|
838
|
+
| **Meta Title/Description** | ✅ | ✅ | ✅ | ✅ |
|
|
839
|
+
| **Open Graph Tags** | ✅ | ✅ | ✅ | ✅ |
|
|
840
|
+
| **Twitter Cards** | ⚠️ Limited | ✅ | ✅ | ✅ |
|
|
841
|
+
| **Readability Analysis** | ✅ | ✅ | ✅ | ❌ (Sanity-native focus) |
|
|
842
|
+
| **Keyword Density** | ✅ | ✅ | ✅ | ❌ (External tools) |
|
|
843
|
+
| **Custom Meta Attributes** | ⚠️ Limited | ✅ | ✅ | ✅ |
|
|
844
|
+
| **Robots/Canonical** | ✅ | ✅ | ✅ | ✅ |
|
|
845
|
+
| **Headless-First** | ❌ | ❌ | ❌ | ✅ Framework-agnostic |
|
|
846
|
+
| **SSR-Ready** | N/A | N/A | N/A | ✅ All frameworks |
|
|
847
|
+
|
|
848
|
+
### Migration Path
|
|
849
|
+
|
|
850
|
+
1. **Export existing metadata** from your old plugin (title, description, OG tags)
|
|
851
|
+
2. **Create a Sanity schema** matching your current fields — map to `seoFields` type
|
|
852
|
+
3. **Bulk import** using Sanity's API or migration scripts
|
|
853
|
+
4. **Update your frontend** to use `buildSeoMeta` utilities instead of plugin hooks
|
|
854
|
+
5. **Test meta rendering** in browsers DevTools and social preview tools
|
|
855
|
+
|
|
856
|
+
For detailed migration guides, see [Migration Guides](#) in our documentation.
|
|
857
|
+
|
|
858
|
+
---
|
|
859
|
+
|
|
661
860
|
## 📚 API Reference
|
|
662
861
|
|
|
663
862
|
### Main Export
|
|
@@ -675,6 +874,272 @@ import seofields from 'sanity-plugin-seofields'
|
|
|
675
874
|
- `metaAttribute` - Individual meta attribute
|
|
676
875
|
- `robots` - Search engine robots settings
|
|
677
876
|
|
|
877
|
+
## 🔧 Troubleshooting
|
|
878
|
+
|
|
879
|
+
### TypeScript auto-import not working
|
|
880
|
+
|
|
881
|
+
**Problem:** `buildSeoMeta` doesn't appear in IDE autocomplete
|
|
882
|
+
|
|
883
|
+
**Solution:**
|
|
884
|
+
|
|
885
|
+
1. Check your `package.json` exports field has a `"types"` condition:
|
|
886
|
+
```json
|
|
887
|
+
{
|
|
888
|
+
"exports": {
|
|
889
|
+
".": {
|
|
890
|
+
"types": "./dist/index.d.ts",
|
|
891
|
+
"default": "./dist/index.js"
|
|
892
|
+
},
|
|
893
|
+
"./next": {
|
|
894
|
+
"types": "./dist/next.d.ts",
|
|
895
|
+
"default": "./dist/next.js"
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
```
|
|
900
|
+
|
|
901
|
+
2. Verify your `tsconfig.json` has the correct `moduleResolution`:
|
|
902
|
+
```json
|
|
903
|
+
{
|
|
904
|
+
"compilerOptions": {
|
|
905
|
+
"moduleResolution": "bundler",
|
|
906
|
+
"resolveJsonModule": true
|
|
907
|
+
}
|
|
908
|
+
}
|
|
909
|
+
```
|
|
910
|
+
|
|
911
|
+
---
|
|
912
|
+
|
|
913
|
+
### "Cannot find module 'sanity-plugin-seofields/next'"
|
|
914
|
+
|
|
915
|
+
**Problem:** Runtime import error when trying to use Next.js utilities
|
|
916
|
+
|
|
917
|
+
**Solution:**
|
|
918
|
+
|
|
919
|
+
1. Ensure built files exist in `dist/next.js`:
|
|
920
|
+
```bash
|
|
921
|
+
npm run build
|
|
922
|
+
```
|
|
923
|
+
|
|
924
|
+
2. Clear and reinstall node_modules:
|
|
925
|
+
```bash
|
|
926
|
+
rm -rf node_modules package-lock.json
|
|
927
|
+
npm install
|
|
928
|
+
```
|
|
929
|
+
|
|
930
|
+
3. Verify `package.json` exports includes the next export:
|
|
931
|
+
```json
|
|
932
|
+
{
|
|
933
|
+
"exports": {
|
|
934
|
+
"./next": {
|
|
935
|
+
"types": "./dist/next.d.ts",
|
|
936
|
+
"default": "./dist/next.js"
|
|
937
|
+
}
|
|
938
|
+
}
|
|
939
|
+
}
|
|
940
|
+
```
|
|
941
|
+
|
|
942
|
+
---
|
|
943
|
+
|
|
944
|
+
### Type inference in generateMetadata()
|
|
945
|
+
|
|
946
|
+
**Problem:** `buildSeoMeta()` return type is not recognized as Next.js `Metadata`
|
|
947
|
+
|
|
948
|
+
**Solution:** Explicitly type the return value:
|
|
949
|
+
|
|
950
|
+
```tsx
|
|
951
|
+
import type {Metadata} from 'next'
|
|
952
|
+
import {buildSeoMeta} from 'sanity-plugin-seofields/next'
|
|
953
|
+
|
|
954
|
+
export async function generateMetadata(): Promise<Metadata> {
|
|
955
|
+
const seoData = await fetchSeoData()
|
|
956
|
+
const metadata = buildSeoMeta(seoData)
|
|
957
|
+
|
|
958
|
+
return {
|
|
959
|
+
title: metadata.title,
|
|
960
|
+
description: metadata.description,
|
|
961
|
+
openGraph: {
|
|
962
|
+
title: metadata.openGraph?.title,
|
|
963
|
+
description: metadata.openGraph?.description,
|
|
964
|
+
url: metadata.openGraph?.url,
|
|
965
|
+
},
|
|
966
|
+
twitter: {
|
|
967
|
+
card: metadata.twitter?.card as any,
|
|
968
|
+
site: metadata.twitter?.site,
|
|
969
|
+
creator: metadata.twitter?.creator,
|
|
970
|
+
},
|
|
971
|
+
}
|
|
972
|
+
}
|
|
973
|
+
```
|
|
974
|
+
|
|
975
|
+
---
|
|
976
|
+
|
|
977
|
+
### Dashboard not showing in Sanity Studio
|
|
978
|
+
|
|
979
|
+
**Problem:** SEO Health tool doesn't appear in the studio
|
|
980
|
+
|
|
981
|
+
**Solution:**
|
|
982
|
+
|
|
983
|
+
1. Ensure the plugin is added to `sanity.config.ts`:
|
|
984
|
+
```typescript
|
|
985
|
+
import seofields from 'sanity-plugin-seofields'
|
|
986
|
+
|
|
987
|
+
export default defineConfig({
|
|
988
|
+
// ... other config
|
|
989
|
+
plugins: [
|
|
990
|
+
seofields({
|
|
991
|
+
documentTypes: ['post', 'page', 'product'],
|
|
992
|
+
// other options
|
|
993
|
+
}),
|
|
994
|
+
],
|
|
995
|
+
})
|
|
996
|
+
```
|
|
997
|
+
|
|
998
|
+
2. Check that `documentTypes` array includes your document types:
|
|
999
|
+
```typescript
|
|
1000
|
+
seofields({
|
|
1001
|
+
documentTypes: ['post', 'page'], // Add your document types here
|
|
1002
|
+
})
|
|
1003
|
+
```
|
|
1004
|
+
|
|
1005
|
+
3. Verify plugin config fieldVisibility is not hiding SEO fields:
|
|
1006
|
+
```typescript
|
|
1007
|
+
seofields({
|
|
1008
|
+
documentTypes: ['post'],
|
|
1009
|
+
fieldVisibility: {
|
|
1010
|
+
// Make sure SEO fields aren't set to hidden
|
|
1011
|
+
},
|
|
1012
|
+
})
|
|
1013
|
+
```
|
|
1014
|
+
|
|
1015
|
+
---
|
|
1016
|
+
|
|
1017
|
+
### Image URLs not resolving
|
|
1018
|
+
|
|
1019
|
+
**Problem:** OG/Twitter images show as `undefined` in meta tags
|
|
1020
|
+
|
|
1021
|
+
**Solution:** Provide an `imageUrlResolver` function:
|
|
1022
|
+
|
|
1023
|
+
```tsx
|
|
1024
|
+
import imageUrlBuilder from '@sanity/image-url'
|
|
1025
|
+
import {client} from './sanity.client'
|
|
1026
|
+
|
|
1027
|
+
const imageBuilder = imageUrlBuilder(client)
|
|
1028
|
+
|
|
1029
|
+
export function buildImageUrl(source) {
|
|
1030
|
+
if (!source) return undefined
|
|
1031
|
+
return imageBuilder.image(source).url()
|
|
1032
|
+
}
|
|
1033
|
+
|
|
1034
|
+
// In your buildSeoMeta call:
|
|
1035
|
+
const metadata = buildSeoMeta({
|
|
1036
|
+
...seoData,
|
|
1037
|
+
imageUrlResolver: buildImageUrl,
|
|
1038
|
+
})
|
|
1039
|
+
```
|
|
1040
|
+
|
|
1041
|
+
Or use it in your Next.js layout:
|
|
1042
|
+
|
|
1043
|
+
```tsx
|
|
1044
|
+
import {buildSeoMeta} from 'sanity-plugin-seofields/next'
|
|
1045
|
+
import imageUrlBuilder from '@sanity/image-url'
|
|
1046
|
+
|
|
1047
|
+
const imageBuilder = imageUrlBuilder(client)
|
|
1048
|
+
|
|
1049
|
+
export async function generateMetadata(): Promise<Metadata> {
|
|
1050
|
+
const seoData = await sanityFetch(SeoQuery)
|
|
1051
|
+
|
|
1052
|
+
const metadata = buildSeoMeta({
|
|
1053
|
+
...seoData,
|
|
1054
|
+
imageUrlResolver: (image) => imageBuilder.image(image).url(),
|
|
1055
|
+
})
|
|
1056
|
+
|
|
1057
|
+
return metadata
|
|
1058
|
+
}
|
|
1059
|
+
```
|
|
1060
|
+
|
|
1061
|
+
---
|
|
1062
|
+
|
|
1063
|
+
### generateMetadata() not finding Sanity data
|
|
1064
|
+
|
|
1065
|
+
**Problem:** Data is `undefined` when trying to fetch from Sanity in Next.js
|
|
1066
|
+
|
|
1067
|
+
**Solution:**
|
|
1068
|
+
|
|
1069
|
+
1. Ensure `sanityFetch` is properly awaited:
|
|
1070
|
+
```tsx
|
|
1071
|
+
import {sanityFetch} from '@/lib/sanity.client'
|
|
1072
|
+
|
|
1073
|
+
export async function generateMetadata(): Promise<Metadata> {
|
|
1074
|
+
try {
|
|
1075
|
+
const seoData = await sanityFetch(SeoQuery) // Don't forget await!
|
|
1076
|
+
return buildSeoMeta(seoData)
|
|
1077
|
+
} catch (error) {
|
|
1078
|
+
console.error('Failed to fetch SEO data:', error)
|
|
1079
|
+
return {title: 'Default Title'}
|
|
1080
|
+
}
|
|
1081
|
+
}
|
|
1082
|
+
```
|
|
1083
|
+
|
|
1084
|
+
2. Verify environment variables are set:
|
|
1085
|
+
```bash
|
|
1086
|
+
# .env.local
|
|
1087
|
+
NEXT_PUBLIC_SANITY_PROJECT_ID=your_project_id
|
|
1088
|
+
NEXT_PUBLIC_SANITY_DATASET=production
|
|
1089
|
+
SANITY_API_TOKEN=your_token (if using authenticated fetches)
|
|
1090
|
+
```
|
|
1091
|
+
|
|
1092
|
+
3. Complete example with proper error handling:
|
|
1093
|
+
```tsx
|
|
1094
|
+
import type {Metadata} from 'next'
|
|
1095
|
+
import {buildSeoMeta} from 'sanity-plugin-seofields/next'
|
|
1096
|
+
import {sanityFetch} from '@/lib/sanity.client'
|
|
1097
|
+
|
|
1098
|
+
const SeoQuery = `*[_type == "post" && slug.current == $slug][0] {
|
|
1099
|
+
title,
|
|
1100
|
+
seo {
|
|
1101
|
+
title,
|
|
1102
|
+
description,
|
|
1103
|
+
openGraph {
|
|
1104
|
+
title,
|
|
1105
|
+
description,
|
|
1106
|
+
image,
|
|
1107
|
+
},
|
|
1108
|
+
twitter {
|
|
1109
|
+
card,
|
|
1110
|
+
site,
|
|
1111
|
+
creator,
|
|
1112
|
+
},
|
|
1113
|
+
},
|
|
1114
|
+
}`
|
|
1115
|
+
|
|
1116
|
+
export async function generateMetadata({
|
|
1117
|
+
params,
|
|
1118
|
+
}: {
|
|
1119
|
+
params: {slug: string}
|
|
1120
|
+
}): Promise<Metadata> {
|
|
1121
|
+
try {
|
|
1122
|
+
const doc = await sanityFetch(SeoQuery, {slug: params.slug})
|
|
1123
|
+
|
|
1124
|
+
if (!doc) {
|
|
1125
|
+
return {title: 'Post not found'}
|
|
1126
|
+
}
|
|
1127
|
+
|
|
1128
|
+
return buildSeoMeta(doc.seo || {})
|
|
1129
|
+
} catch (error) {
|
|
1130
|
+
console.error('SEO metadata error:', error)
|
|
1131
|
+
return {title: 'Error loading page'}
|
|
1132
|
+
}
|
|
1133
|
+
}
|
|
1134
|
+
```
|
|
1135
|
+
|
|
1136
|
+
---
|
|
1137
|
+
|
|
1138
|
+
**Still stuck?** Check our:
|
|
1139
|
+
- 📖 [Full Documentation](./TYPES_SCHEMA_DOCS.md)
|
|
1140
|
+
- 🐛 [GitHub Issues](https://github.com/hardik-143/sanity-plugin-seofields/issues)
|
|
1141
|
+
- 📧 [Email Support](mailto:dhardik1430@gmail.com)
|
|
1142
|
+
|
|
678
1143
|
## 🤝 Contributing
|
|
679
1144
|
|
|
680
1145
|
Contributions are welcome! Please feel free to submit a Pull Request.
|