sanity-plugin-seofields 1.3.1 → 1.4.0
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 +69 -40
- package/dist/index.cjs +1924 -1618
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +68 -17
- package/dist/index.d.ts +68 -17
- package/dist/index.js +1879 -1563
- package/dist/index.js.map +1 -1
- package/dist/next.cjs +1506 -0
- package/dist/next.cjs.map +1 -1
- package/dist/next.d.cts +4 -1
- package/dist/next.d.ts +4 -1
- package/dist/next.js +1457 -0
- package/dist/next.js.map +1 -1
- package/dist/schema/next.cjs +1548 -0
- package/dist/schema/next.cjs.map +1 -0
- package/dist/schema/next.d.cts +438 -0
- package/dist/schema/next.d.ts +438 -0
- package/dist/schema/next.js +1476 -0
- package/dist/schema/next.js.map +1 -0
- package/dist/schema.cjs +1743 -0
- package/dist/schema.cjs.map +1 -0
- package/dist/schema.d.cts +387 -0
- package/dist/schema.d.ts +387 -0
- package/dist/schema.js +1691 -0
- package/dist/schema.js.map +1 -0
- package/dist/types-CVaAX7uy.d.cts +589 -0
- package/dist/types-Ci-ZZT7A.d.ts +589 -0
- package/dist/{types-B91ena4g.d.cts → types-R3n9Fu4w.d.cts} +16 -1
- package/dist/{types-B91ena4g.d.ts → types-R3n9Fu4w.d.ts} +16 -1
- package/package.json +18 -3
package/README.md
CHANGED
|
@@ -482,11 +482,9 @@ seofields({
|
|
|
482
482
|
description: 'Track SEO quality across all published content.',
|
|
483
483
|
},
|
|
484
484
|
|
|
485
|
-
// Table columns
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
documentId: false, // show document _id (default: true)
|
|
489
|
-
},
|
|
485
|
+
// Table columns (flat keys — replaces the deprecated display.* object)
|
|
486
|
+
showTypeColumn: true, // show document type column (default: true)
|
|
487
|
+
showDocumentId: false, // show document _id under titles (default: true)
|
|
490
488
|
|
|
491
489
|
// Document query
|
|
492
490
|
query: {
|
|
@@ -496,6 +494,14 @@ seofields({
|
|
|
496
494
|
// ^ custom GROQ takes precedence over types + requireSeo
|
|
497
495
|
},
|
|
498
496
|
|
|
497
|
+
// Human-readable labels for document type names
|
|
498
|
+
typeDisplayLabels: {productDrug: 'Products', landingPage: 'Landing Page'},
|
|
499
|
+
|
|
500
|
+
// Custom badge next to the document title
|
|
501
|
+
getDocumentBadge: (doc) => {
|
|
502
|
+
if (doc.status === 'draft') return {label: 'Draft', bgColor: '#f3f4f6', textColor: '#6b7280'}
|
|
503
|
+
},
|
|
504
|
+
|
|
499
505
|
apiVersion: '2023-01-01', // Sanity API version (default: '2023-01-01')
|
|
500
506
|
},
|
|
501
507
|
})
|
|
@@ -506,6 +512,21 @@ seofields({
|
|
|
506
512
|
})
|
|
507
513
|
```
|
|
508
514
|
|
|
515
|
+
### Deprecated keys (v1.3.2)
|
|
516
|
+
|
|
517
|
+
The following keys were renamed in **v1.3.2** for clarity. The old keys still work but will print a console warning and show an amber banner inside the dashboard. They will be removed in a future major release.
|
|
518
|
+
|
|
519
|
+
| Deprecated (old) | Replacement (new) |
|
|
520
|
+
| ------------------------------------ | ----------------------------------- |
|
|
521
|
+
| `healthDashboard.display.typeColumn` | `healthDashboard.showTypeColumn` |
|
|
522
|
+
| `healthDashboard.display.documentId` | `healthDashboard.showDocumentId` |
|
|
523
|
+
| `healthDashboard.typeLabels` | `healthDashboard.typeDisplayLabels` |
|
|
524
|
+
| `healthDashboard.docBadge` | `healthDashboard.getDocumentBadge` |
|
|
525
|
+
|
|
526
|
+
The same renames apply to `SeoHealthDashboardProps` when using `createSeoHealthPane` directly.
|
|
527
|
+
|
|
528
|
+
See the [v1.3.2 changelog](./CHANGELOG.md#132--2026-03-23) for the full migration diff.
|
|
529
|
+
|
|
509
530
|
### What it shows
|
|
510
531
|
|
|
511
532
|
| Feature | Details |
|
|
@@ -583,13 +604,13 @@ export default defineConfig({
|
|
|
583
604
|
|
|
584
605
|
### `createSeoHealthPane` options
|
|
585
606
|
|
|
586
|
-
| Option | Type | Default | Description
|
|
587
|
-
| ------------ | --------- | -------------- |
|
|
588
|
-
| `licenseKey` | `string` | **required** | License key (format `SEOF-XXXX-XXXX-XXXX`).
|
|
589
|
-
| `query` | `string` | — | GROQ query. Must return `_id`, `_type`, `title`, `seo`, `_updatedAt`.
|
|
590
|
-
| `title` | `string` | `'SEO Health'` | Pane title shown in breadcrumb
|
|
607
|
+
| Option | Type | Default | Description |
|
|
608
|
+
| ------------ | --------- | -------------- | ---------------------------------------------------------------------- |
|
|
609
|
+
| `licenseKey` | `string` | **required** | License key (format `SEOF-XXXX-XXXX-XXXX`). |
|
|
610
|
+
| `query` | `string` | — | GROQ query. Must return `_id`, `_type`, `title`, `seo`, `_updatedAt`. |
|
|
611
|
+
| `title` | `string` | `'SEO Health'` | Pane title shown in breadcrumb |
|
|
591
612
|
| `openInPane` | `boolean` | `true` | Enable row links that open the document editor as a pane to the right. |
|
|
592
|
-
| `...rest` | — | — | All other `SeoHealthDashboardProps`
|
|
613
|
+
| `...rest` | — | — | All other `SeoHealthDashboardProps` |
|
|
593
614
|
|
|
594
615
|
## 🌐 Frontend Integration
|
|
595
616
|
|
|
@@ -678,13 +699,13 @@ export const loader: LoaderFunction = async ({params}) => {
|
|
|
678
699
|
}`,
|
|
679
700
|
{slug: params.slug},
|
|
680
701
|
)
|
|
681
|
-
|
|
702
|
+
|
|
682
703
|
// Use buildSeoMeta to generate meta tags
|
|
683
704
|
const seoMeta = buildSeoMeta(post.seo, {
|
|
684
705
|
defaultTitle: 'Blog',
|
|
685
706
|
siteUrl: 'https://example.com',
|
|
686
707
|
})
|
|
687
|
-
|
|
708
|
+
|
|
688
709
|
return json({post, seoMeta})
|
|
689
710
|
}
|
|
690
711
|
|
|
@@ -711,9 +732,9 @@ export const useSanityMeta = (seo: SEOFields, options = {}) => {
|
|
|
711
732
|
defaultTitle = 'My Site',
|
|
712
733
|
siteUrl = 'https://example.com',
|
|
713
734
|
} = options
|
|
714
|
-
|
|
735
|
+
|
|
715
736
|
const meta = buildSeoMeta(seo, {defaultTitle, siteUrl})
|
|
716
|
-
|
|
737
|
+
|
|
717
738
|
// useHead() handles SSR + client-side rendering
|
|
718
739
|
useHead({
|
|
719
740
|
title: seo?.title || defaultTitle,
|
|
@@ -721,7 +742,7 @@ export const useSanityMeta = (seo: SEOFields, options = {}) => {
|
|
|
721
742
|
name: m.name || m.property,
|
|
722
743
|
content: m.content,
|
|
723
744
|
})),
|
|
724
|
-
link: seo?.canonicalUrl
|
|
745
|
+
link: seo?.canonicalUrl
|
|
725
746
|
? [{rel: 'canonical', href: seo.canonicalUrl}]
|
|
726
747
|
: [],
|
|
727
748
|
})
|
|
@@ -803,17 +824,17 @@ export function PostHead({seo, fallbackTitle}: PostHeadProps) {
|
|
|
803
824
|
{/* Basic Meta */}
|
|
804
825
|
<title>{seo?.title || fallbackTitle}</title>
|
|
805
826
|
<meta name="description" content={seo?.description || ''} />
|
|
806
|
-
|
|
827
|
+
|
|
807
828
|
{/* Open Graph - critical for social shares */}
|
|
808
829
|
<meta property="og:title" content={seo?.openGraph?.title} />
|
|
809
830
|
<meta property="og:description" content={seo?.openGraph?.description} />
|
|
810
831
|
{seo?.openGraph?.image?.url && (
|
|
811
832
|
<meta property="og:image" content={seo.openGraph.image.url} />
|
|
812
833
|
)}
|
|
813
|
-
|
|
834
|
+
|
|
814
835
|
{/* Robots */}
|
|
815
836
|
{seo?.robots?.noIndex && <meta name="robots" content="noindex" />}
|
|
816
|
-
|
|
837
|
+
|
|
817
838
|
{/* Canonical (limit crawl budget) */}
|
|
818
839
|
{seo?.canonicalUrl && (
|
|
819
840
|
<link rel="canonical" href={seo.canonicalUrl} />
|
|
@@ -833,17 +854,17 @@ export function PostHead({seo, fallbackTitle}: PostHeadProps) {
|
|
|
833
854
|
|
|
834
855
|
Coming from **Yoast**, **All in One SEO**, or **RankMath**?
|
|
835
856
|
|
|
836
|
-
| Feature
|
|
837
|
-
|
|
838
|
-
| **Meta Title/Description** | ✅
|
|
839
|
-
| **Open Graph Tags**
|
|
840
|
-
| **Twitter Cards**
|
|
841
|
-
| **Readability Analysis**
|
|
842
|
-
| **Keyword Density**
|
|
843
|
-
| **Custom Meta Attributes** | ⚠️ Limited | ✅
|
|
844
|
-
| **Robots/Canonical**
|
|
845
|
-
| **Headless-First**
|
|
846
|
-
| **SSR-Ready**
|
|
857
|
+
| Feature | Yoast | All in One SEO | RankMath | sanity-plugin-seofields |
|
|
858
|
+
| -------------------------- | ---------- | -------------- | -------- | ------------------------ |
|
|
859
|
+
| **Meta Title/Description** | ✅ | ✅ | ✅ | ✅ |
|
|
860
|
+
| **Open Graph Tags** | ✅ | ✅ | ✅ | ✅ |
|
|
861
|
+
| **Twitter Cards** | ⚠️ Limited | ✅ | ✅ | ✅ |
|
|
862
|
+
| **Readability Analysis** | ✅ | ✅ | ✅ | ❌ (Sanity-native focus) |
|
|
863
|
+
| **Keyword Density** | ✅ | ✅ | ✅ | ❌ (External tools) |
|
|
864
|
+
| **Custom Meta Attributes** | ⚠️ Limited | ✅ | ✅ | ✅ |
|
|
865
|
+
| **Robots/Canonical** | ✅ | ✅ | ✅ | ✅ |
|
|
866
|
+
| **Headless-First** | ❌ | ❌ | ❌ | ✅ Framework-agnostic |
|
|
867
|
+
| **SSR-Ready** | N/A | N/A | N/A | ✅ All frameworks |
|
|
847
868
|
|
|
848
869
|
### Migration Path
|
|
849
870
|
|
|
@@ -883,6 +904,7 @@ import seofields from 'sanity-plugin-seofields'
|
|
|
883
904
|
**Solution:**
|
|
884
905
|
|
|
885
906
|
1. Check your `package.json` exports field has a `"types"` condition:
|
|
907
|
+
|
|
886
908
|
```json
|
|
887
909
|
{
|
|
888
910
|
"exports": {
|
|
@@ -899,6 +921,7 @@ import seofields from 'sanity-plugin-seofields'
|
|
|
899
921
|
```
|
|
900
922
|
|
|
901
923
|
2. Verify your `tsconfig.json` has the correct `moduleResolution`:
|
|
924
|
+
|
|
902
925
|
```json
|
|
903
926
|
{
|
|
904
927
|
"compilerOptions": {
|
|
@@ -917,17 +940,20 @@ import seofields from 'sanity-plugin-seofields'
|
|
|
917
940
|
**Solution:**
|
|
918
941
|
|
|
919
942
|
1. Ensure built files exist in `dist/next.js`:
|
|
943
|
+
|
|
920
944
|
```bash
|
|
921
945
|
npm run build
|
|
922
946
|
```
|
|
923
947
|
|
|
924
948
|
2. Clear and reinstall node_modules:
|
|
949
|
+
|
|
925
950
|
```bash
|
|
926
951
|
rm -rf node_modules package-lock.json
|
|
927
952
|
npm install
|
|
928
953
|
```
|
|
929
954
|
|
|
930
955
|
3. Verify `package.json` exports includes the next export:
|
|
956
|
+
|
|
931
957
|
```json
|
|
932
958
|
{
|
|
933
959
|
"exports": {
|
|
@@ -954,7 +980,7 @@ import {buildSeoMeta} from 'sanity-plugin-seofields/next'
|
|
|
954
980
|
export async function generateMetadata(): Promise<Metadata> {
|
|
955
981
|
const seoData = await fetchSeoData()
|
|
956
982
|
const metadata = buildSeoMeta(seoData)
|
|
957
|
-
|
|
983
|
+
|
|
958
984
|
return {
|
|
959
985
|
title: metadata.title,
|
|
960
986
|
description: metadata.description,
|
|
@@ -981,6 +1007,7 @@ export async function generateMetadata(): Promise<Metadata> {
|
|
|
981
1007
|
**Solution:**
|
|
982
1008
|
|
|
983
1009
|
1. Ensure the plugin is added to `sanity.config.ts`:
|
|
1010
|
+
|
|
984
1011
|
```typescript
|
|
985
1012
|
import seofields from 'sanity-plugin-seofields'
|
|
986
1013
|
|
|
@@ -996,6 +1023,7 @@ export default defineConfig({
|
|
|
996
1023
|
```
|
|
997
1024
|
|
|
998
1025
|
2. Check that `documentTypes` array includes your document types:
|
|
1026
|
+
|
|
999
1027
|
```typescript
|
|
1000
1028
|
seofields({
|
|
1001
1029
|
documentTypes: ['post', 'page'], // Add your document types here
|
|
@@ -1003,6 +1031,7 @@ seofields({
|
|
|
1003
1031
|
```
|
|
1004
1032
|
|
|
1005
1033
|
3. Verify plugin config fieldVisibility is not hiding SEO fields:
|
|
1034
|
+
|
|
1006
1035
|
```typescript
|
|
1007
1036
|
seofields({
|
|
1008
1037
|
documentTypes: ['post'],
|
|
@@ -1048,12 +1077,12 @@ const imageBuilder = imageUrlBuilder(client)
|
|
|
1048
1077
|
|
|
1049
1078
|
export async function generateMetadata(): Promise<Metadata> {
|
|
1050
1079
|
const seoData = await sanityFetch(SeoQuery)
|
|
1051
|
-
|
|
1080
|
+
|
|
1052
1081
|
const metadata = buildSeoMeta({
|
|
1053
1082
|
...seoData,
|
|
1054
1083
|
imageUrlResolver: (image) => imageBuilder.image(image).url(),
|
|
1055
1084
|
})
|
|
1056
|
-
|
|
1085
|
+
|
|
1057
1086
|
return metadata
|
|
1058
1087
|
}
|
|
1059
1088
|
```
|
|
@@ -1067,6 +1096,7 @@ export async function generateMetadata(): Promise<Metadata> {
|
|
|
1067
1096
|
**Solution:**
|
|
1068
1097
|
|
|
1069
1098
|
1. Ensure `sanityFetch` is properly awaited:
|
|
1099
|
+
|
|
1070
1100
|
```tsx
|
|
1071
1101
|
import {sanityFetch} from '@/lib/sanity.client'
|
|
1072
1102
|
|
|
@@ -1082,6 +1112,7 @@ export async function generateMetadata(): Promise<Metadata> {
|
|
|
1082
1112
|
```
|
|
1083
1113
|
|
|
1084
1114
|
2. Verify environment variables are set:
|
|
1115
|
+
|
|
1085
1116
|
```bash
|
|
1086
1117
|
# .env.local
|
|
1087
1118
|
NEXT_PUBLIC_SANITY_PROJECT_ID=your_project_id
|
|
@@ -1090,6 +1121,7 @@ SANITY_API_TOKEN=your_token (if using authenticated fetches)
|
|
|
1090
1121
|
```
|
|
1091
1122
|
|
|
1092
1123
|
3. Complete example with proper error handling:
|
|
1124
|
+
|
|
1093
1125
|
```tsx
|
|
1094
1126
|
import type {Metadata} from 'next'
|
|
1095
1127
|
import {buildSeoMeta} from 'sanity-plugin-seofields/next'
|
|
@@ -1113,18 +1145,14 @@ const SeoQuery = `*[_type == "post" && slug.current == $slug][0] {
|
|
|
1113
1145
|
},
|
|
1114
1146
|
}`
|
|
1115
1147
|
|
|
1116
|
-
export async function generateMetadata({
|
|
1117
|
-
params,
|
|
1118
|
-
}: {
|
|
1119
|
-
params: {slug: string}
|
|
1120
|
-
}): Promise<Metadata> {
|
|
1148
|
+
export async function generateMetadata({params}: {params: {slug: string}}): Promise<Metadata> {
|
|
1121
1149
|
try {
|
|
1122
1150
|
const doc = await sanityFetch(SeoQuery, {slug: params.slug})
|
|
1123
|
-
|
|
1151
|
+
|
|
1124
1152
|
if (!doc) {
|
|
1125
1153
|
return {title: 'Post not found'}
|
|
1126
1154
|
}
|
|
1127
|
-
|
|
1155
|
+
|
|
1128
1156
|
return buildSeoMeta(doc.seo || {})
|
|
1129
1157
|
} catch (error) {
|
|
1130
1158
|
console.error('SEO metadata error:', error)
|
|
@@ -1136,6 +1164,7 @@ export async function generateMetadata({
|
|
|
1136
1164
|
---
|
|
1137
1165
|
|
|
1138
1166
|
**Still stuck?** Check our:
|
|
1167
|
+
|
|
1139
1168
|
- 📖 [Full Documentation](./TYPES_SCHEMA_DOCS.md)
|
|
1140
1169
|
- 🐛 [GitHub Issues](https://github.com/hardik-143/sanity-plugin-seofields/issues)
|
|
1141
1170
|
- 📧 [Email Support](mailto:dhardik1430@gmail.com)
|