sanity-plugin-seofields 1.0.1

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Desai Hardik
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,379 @@
1
+ # 🔍 Sanity SEO Fields Plugin
2
+
3
+ [![npm version](https://badge.fury.io/js/sanity-plugin-seofields.svg)](https://badge.fury.io/js/sanity-plugin-seofields)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
+
6
+ A comprehensive Sanity Studio v3 plugin to manage SEO fields like meta titles, descriptions, Open Graph tags, and Twitter Cards for structured, search-optimized content.
7
+
8
+ ## ✨ Features
9
+
10
+ - 🎯 **Meta Tags**: Title, description, keywords, and canonical URLs
11
+ - 📱 **Open Graph**: Complete social media sharing optimization
12
+ - 🐦 **Twitter Cards**: Twitter-specific meta tags with image support
13
+ - 🤖 **Robots Control**: Index/follow settings for search engines
14
+ - 🖼️ **Image Management**: Optimized image handling for social sharing
15
+ - 📋 **Live Preview**: Real-time SEO preview as you edit
16
+ - 🔧 **TypeScript Support**: Full type definitions included
17
+ - 📊 **Custom Attributes**: Flexible meta attribute system
18
+ - ✅ **Validation**: Built-in character limits and best practices
19
+
20
+ ## 📦 Installation
21
+
22
+ ```bash
23
+ npm install sanity-plugin-seofields
24
+ ```
25
+
26
+ or
27
+
28
+ ```bash
29
+ yarn add sanity-plugin-seofields
30
+ ```
31
+
32
+ ## 🚀 Quick Start
33
+
34
+ ### 1. Add the Plugin
35
+
36
+ Add the plugin to your `sanity.config.ts` (or `.js`) file:
37
+
38
+ ```typescript
39
+ import {defineConfig} from 'sanity'
40
+ import {seofields} from 'sanity-plugin-seofields'
41
+
42
+ export default defineConfig({
43
+ name: 'your-project',
44
+ title: 'Your Project',
45
+ projectId: 'your-project-id',
46
+ dataset: 'production',
47
+
48
+ plugins: [
49
+ seofields(), // Add the SEO fields plugin
50
+ // ... other plugins
51
+ ],
52
+
53
+ schema: {
54
+ types: [
55
+ // ... your schema types
56
+ ],
57
+ },
58
+ })
59
+ ```
60
+
61
+ ### 2. Add SEO Fields to Your Documents
62
+
63
+ Add the SEO fields to any document type in your schema:
64
+
65
+ ```typescript
66
+ import {defineField, defineType} from 'sanity'
67
+
68
+ export default defineType({
69
+ name: 'page',
70
+ title: 'Page',
71
+ type: 'document',
72
+ fields: [
73
+ defineField({
74
+ name: 'title',
75
+ title: 'Title',
76
+ type: 'string',
77
+ }),
78
+ defineField({
79
+ name: 'content',
80
+ title: 'Content',
81
+ type: 'text',
82
+ }),
83
+ // Add SEO fields
84
+ defineField({
85
+ name: 'seo',
86
+ title: 'SEO',
87
+ type: 'seoFields',
88
+ }),
89
+ ],
90
+ })
91
+ ```
92
+
93
+ ### 3. Using Individual SEO Components
94
+
95
+ You can also use individual components:
96
+
97
+ ```typescript
98
+ import {defineField, defineType} from 'sanity'
99
+
100
+ export default defineType({
101
+ name: 'article',
102
+ title: 'Article',
103
+ type: 'document',
104
+ fields: [
105
+ // ... other fields
106
+
107
+ // Individual SEO components
108
+ defineField({
109
+ name: 'openGraph',
110
+ title: 'Open Graph',
111
+ type: 'openGraph',
112
+ }),
113
+ defineField({
114
+ name: 'twitterCard',
115
+ title: 'Twitter Card',
116
+ type: 'twitter',
117
+ }),
118
+ defineField({
119
+ name: 'metaAttributes',
120
+ title: 'Custom Meta Tags',
121
+ type: 'metaTag',
122
+ }),
123
+ ],
124
+ })
125
+ ```
126
+
127
+ ## 🎨 Available Schema Types
128
+
129
+ | Type | Description | Use Case |
130
+ | --------------- | ------------------------- | -------------------------------- |
131
+ | `seoFields` | Complete SEO package | Main SEO fields for any document |
132
+ | `openGraph` | Open Graph meta tags | Social media sharing |
133
+ | `twitter` | Twitter Card settings | Twitter-specific optimization |
134
+ | `metaTag` | Custom meta attributes | Advanced meta tag management |
135
+ | `metaAttribute` | Individual meta attribute | Building custom meta tags |
136
+ | `robots` | Search engine directives | Control indexing and crawling |
137
+
138
+ ## 🔧 Configuration Options
139
+
140
+ ### Basic Configuration
141
+
142
+ ```typescript
143
+ import {seofields} from 'sanity-plugin-seofields'
144
+
145
+ export default defineConfig({
146
+ plugins: [
147
+ seofields({
148
+ // Plugin options (none required currently)
149
+ }),
150
+ ],
151
+ })
152
+ ```
153
+
154
+ ### Field Specifications
155
+
156
+ #### Meta Title
157
+
158
+ - **Max Length**: 70 characters (warning at 60)
159
+ - **Purpose**: Search engine result headlines
160
+ - **Best Practice**: Include primary keywords, keep under 60 chars
161
+
162
+ #### Meta Description
163
+
164
+ - **Max Length**: 160 characters (warning at 150)
165
+ - **Purpose**: Search result descriptions
166
+ - **Best Practice**: Compelling summary with keywords
167
+
168
+ #### Open Graph Image
169
+
170
+ - **Recommended Size**: 1200x630px
171
+ - **Minimum Size**: 600x315px
172
+ - **Aspect Ratio**: 1.91:1
173
+ - **Formats**: JPG, PNG, WebP
174
+
175
+ #### Twitter Card Image
176
+
177
+ - **Summary Card**: Minimum 120x120px
178
+ - **Large Image**: Minimum 280x150px
179
+ - **Required**: Alt text for accessibility
180
+
181
+ ## 💻 TypeScript Usage
182
+
183
+ The plugin includes full TypeScript support:
184
+
185
+ ```typescript
186
+ import type {SeoFields, OpenGraphSettings, TwitterCardSettings} from 'sanity-plugin-seofields'
187
+
188
+ // Use in your document interfaces
189
+ interface PageDocument {
190
+ _type: 'page'
191
+ title: string
192
+ seo?: SeoFields
193
+ }
194
+
195
+ // Type-safe field access
196
+ const seoData: SeoFields = {
197
+ _type: 'seoFields',
198
+ title: 'My Page Title',
199
+ description: 'A great page description',
200
+ openGraph: {
201
+ _type: 'openGraph',
202
+ title: 'Social Media Title',
203
+ description: 'Social media description',
204
+ type: 'website',
205
+ },
206
+ }
207
+ ```
208
+
209
+ ### Available Types
210
+
211
+ ```typescript
212
+ import type {
213
+ SeoFields,
214
+ OpenGraphSettings,
215
+ TwitterCardSettings,
216
+ MetaAttribute,
217
+ MetaTag,
218
+ RobotsSettings,
219
+ SanityImage,
220
+ } from 'sanity-plugin-seofields'
221
+ ```
222
+
223
+ ## 🎯 Examples
224
+
225
+ ### Complete SEO Setup
226
+
227
+ ```typescript
228
+ // In your schema
229
+ defineField({
230
+ name: 'seo',
231
+ title: 'SEO & Social Media',
232
+ type: 'seoFields',
233
+ group: 'seo', // Optional: group in a tab
234
+ })
235
+ ```
236
+
237
+ ### Custom Meta Tags
238
+
239
+ ```typescript
240
+ // For advanced users who need custom meta tags
241
+ defineField({
242
+ name: 'customMeta',
243
+ title: 'Custom Meta Tags',
244
+ type: 'metaTag',
245
+ description: 'Add custom meta attributes for specific needs',
246
+ })
247
+ ```
248
+
249
+ ### Open Graph Only
250
+
251
+ ```typescript
252
+ // If you only need Open Graph
253
+ defineField({
254
+ name: 'socialSharing',
255
+ title: 'Social Media Sharing',
256
+ type: 'openGraph',
257
+ })
258
+ ```
259
+
260
+ ## 🌐 Frontend Integration
261
+
262
+ ### Next.js Example
263
+
264
+ ```typescript
265
+ import {SeoFields} from 'sanity-plugin-seofields'
266
+ import Head from 'next/head'
267
+
268
+ interface SEOProps {
269
+ seo?: SeoFields
270
+ }
271
+
272
+ export function SEOHead({seo}: SEOProps) {
273
+ if (!seo) return null
274
+
275
+ return (
276
+ <Head>
277
+ {seo.title && <title>{seo.title}</title>}
278
+ {seo.description && (
279
+ <meta name="description" content={seo.description} />
280
+ )}
281
+
282
+ {/* Open Graph */}
283
+ {seo.openGraph?.title && (
284
+ <meta property="og:title" content={seo.openGraph.title} />
285
+ )}
286
+ {seo.openGraph?.description && (
287
+ <meta property="og:description" content={seo.openGraph.description} />
288
+ )}
289
+
290
+ {/* Twitter */}
291
+ {seo.twitter?.card && (
292
+ <meta name="twitter:card" content={seo.twitter.card} />
293
+ )}
294
+
295
+ {/* Robots */}
296
+ {seo.robots?.noIndex && <meta name="robots" content="noindex" />}
297
+ {seo.robots?.noFollow && <meta name="robots" content="nofollow" />}
298
+
299
+ {/* Canonical URL */}
300
+ {seo.canonicalUrl && <link rel="canonical" href={seo.canonicalUrl} />}
301
+ </Head>
302
+ )
303
+ }
304
+ ```
305
+
306
+ ### React/Gatsby Example
307
+
308
+ ```typescript
309
+ import {Helmet} from 'react-helmet'
310
+ import {SeoFields} from 'sanity-plugin-seofields'
311
+
312
+ interface SEOProps {
313
+ seo?: SeoFields
314
+ }
315
+
316
+ export function SEO({seo}: SEOProps) {
317
+ return (
318
+ <Helmet>
319
+ <title>{seo?.title}</title>
320
+ <meta name="description" content={seo?.description} />
321
+
322
+ {/* Keywords */}
323
+ {seo?.keywords && (
324
+ <meta name="keywords" content={seo.keywords.join(', ')} />
325
+ )}
326
+
327
+ {/* Open Graph */}
328
+ <meta property="og:title" content={seo?.openGraph?.title} />
329
+ <meta property="og:description" content={seo?.openGraph?.description} />
330
+ <meta property="og:type" content={seo?.openGraph?.type || 'website'} />
331
+ </Helmet>
332
+ )
333
+ }
334
+ ```
335
+
336
+ ## 📚 API Reference
337
+
338
+ ### Main Export
339
+
340
+ ```typescript
341
+ import {seofields} from 'sanity-plugin-seofields'
342
+ ```
343
+
344
+ ### Schema Types
345
+
346
+ - `seoFields` - Complete SEO fields object
347
+ - `openGraph` - Open Graph meta tags
348
+ - `twitter` - Twitter Card settings
349
+ - `metaTag` - Custom meta tag collection
350
+ - `metaAttribute` - Individual meta attribute
351
+ - `robots` - Search engine robots settings
352
+
353
+ ### TypeScript Types
354
+
355
+ All types are exported from the main module for use in your project.
356
+
357
+ ## 🤝 Contributing
358
+
359
+ Contributions are welcome! Please feel free to submit a Pull Request.
360
+
361
+ 1. Fork the repository
362
+ 2. Create your feature branch (`git checkout -b feature/amazing-feature`)
363
+ 3. Commit your changes (`git commit -m 'Add some amazing feature'`)
364
+ 4. Push to the branch (`git push origin feature/amazing-feature`)
365
+ 5. Open a Pull Request
366
+
367
+ ## 📄 License
368
+
369
+ [MIT](LICENSE) © [Desai Hardik](https://github.com/hardik-143)
370
+
371
+ ## 🆘 Support
372
+
373
+ - 📧 Email: dhardik1430@gmail.com
374
+ - 🐛 Issues: [GitHub Issues](https://github.com/hardik-143/sanity-plugin-seofields/issues)
375
+ - 📖 Documentation: [Types & Schema Docs](./TYPES_SCHEMA_DOCS.md)
376
+
377
+ ---
378
+
379
+ Made with ❤️ for the Sanity community
@@ -0,0 +1,226 @@
1
+ import {ObjectDefinition} from 'sanity'
2
+ import {Plugin as Plugin_2} from 'sanity'
3
+ import {PreviewConfig} from 'sanity'
4
+
5
+ export declare const allSchemas: (
6
+ | ({
7
+ type: 'object'
8
+ name: 'seoFields'
9
+ } & Omit<ObjectDefinition, 'preview'> & {
10
+ preview?: PreviewConfig<Record<string, string>, Record<never, any>> | undefined
11
+ })
12
+ | ({
13
+ type: 'object'
14
+ name: 'metaAttribute'
15
+ } & Omit<ObjectDefinition, 'preview'> & {
16
+ preview?:
17
+ | PreviewConfig<
18
+ {
19
+ attributeName: string
20
+ attributeValueString: string
21
+ attributeValueImage: string
22
+ },
23
+ {
24
+ attributeName: string
25
+ attributeValueString: string
26
+ attributeValueImage: any
27
+ }
28
+ >
29
+ | undefined
30
+ })
31
+ | ({
32
+ type: 'object'
33
+ name: 'openGraph'
34
+ } & Omit<ObjectDefinition, 'preview'> & {
35
+ preview?: PreviewConfig<Record<string, string>, Record<never, any>> | undefined
36
+ })
37
+ | ({
38
+ type: 'object'
39
+ name: 'twitter'
40
+ } & Omit<ObjectDefinition, 'preview'> & {
41
+ preview?: PreviewConfig<Record<string, string>, Record<never, any>> | undefined
42
+ })
43
+ | ({
44
+ type: 'object'
45
+ name: 'robots'
46
+ } & Omit<ObjectDefinition, 'preview'> & {
47
+ preview?: PreviewConfig<Record<string, string>, Record<never, any>> | undefined
48
+ })
49
+ | ({
50
+ type: 'object'
51
+ name: 'metaTag'
52
+ } & Omit<ObjectDefinition, 'preview'> & {
53
+ preview?: PreviewConfig<Record<string, string>, Record<never, any>> | undefined
54
+ })
55
+ )[]
56
+
57
+ export declare const defaultSeoValidationRules: SeoValidationRules
58
+
59
+ export declare const isMetaAttribute: (obj: any) => obj is MetaAttribute
60
+
61
+ export declare const isOpenGraphSettings: (obj: any) => obj is OpenGraphSettings
62
+
63
+ export declare const isSeoFields: (obj: any) => obj is SeoFields
64
+
65
+ export declare const isTwitterCardSettings: (obj: any) => obj is TwitterCardSettings
66
+
67
+ export declare interface MetaAttribute {
68
+ _type: 'metaAttribute'
69
+ key: string
70
+ type: 'string' | 'image'
71
+ value?: string
72
+ image?: SanityImage
73
+ }
74
+
75
+ export declare const metaAttributeSchema: {
76
+ type: 'object'
77
+ name: 'metaAttribute'
78
+ } & Omit<ObjectDefinition, 'preview'> & {
79
+ preview?:
80
+ | PreviewConfig<
81
+ {
82
+ attributeName: string
83
+ attributeValueString: string
84
+ attributeValueImage: string
85
+ },
86
+ {
87
+ attributeName: string
88
+ attributeValueString: string
89
+ attributeValueImage: any
90
+ }
91
+ >
92
+ | undefined
93
+ }
94
+
95
+ export declare const metaTagSchema: {
96
+ type: 'object'
97
+ name: 'metaTag'
98
+ } & Omit<ObjectDefinition, 'preview'> & {
99
+ preview?: PreviewConfig<Record<string, string>, Record<never, any>> | undefined
100
+ }
101
+
102
+ declare interface MyPluginConfig {}
103
+
104
+ export declare const openGraphSchema: {
105
+ type: 'object'
106
+ name: 'openGraph'
107
+ } & Omit<ObjectDefinition, 'preview'> & {
108
+ preview?: PreviewConfig<Record<string, string>, Record<never, any>> | undefined
109
+ }
110
+
111
+ export declare interface OpenGraphSettings {
112
+ _type: 'openGraph'
113
+ title?: string
114
+ description?: string
115
+ siteName?: string
116
+ type?: 'website' | 'article' | 'profile' | 'book' | 'music' | 'video' | 'product'
117
+ imageType?: 'upload' | 'url'
118
+ image?: SanityImage
119
+ imageUrl?: string
120
+ }
121
+
122
+ export declare interface RobotsSettings {
123
+ noIndex?: boolean
124
+ noFollow?: boolean
125
+ }
126
+
127
+ export declare interface SanityImage {
128
+ _type: 'image'
129
+ asset: {
130
+ _ref: string
131
+ _type: 'reference'
132
+ }
133
+ hotspot?: {
134
+ x: number
135
+ y: number
136
+ height: number
137
+ width: number
138
+ }
139
+ crop?: {
140
+ top: number
141
+ bottom: number
142
+ left: number
143
+ right: number
144
+ }
145
+ alt?: string
146
+ }
147
+
148
+ export declare interface SanityImageWithAlt extends SanityImage {
149
+ alt: string
150
+ }
151
+
152
+ export declare interface SeoFields {
153
+ _type: 'seoFields'
154
+ robots?: RobotsSettings
155
+ preview?: string
156
+ title?: string
157
+ description?: string
158
+ metaImage?: SanityImage
159
+ keywords?: string[]
160
+ canonicalUrl?: string
161
+ openGraph?: OpenGraphSettings
162
+ twitter?: TwitterCardSettings
163
+ }
164
+
165
+ /**
166
+ * Usage in `sanity.config.ts` (or .js)
167
+ *
168
+ * ```ts
169
+ * import {defineConfig} from 'sanity'
170
+ * import {myPlugin} from 'sanity-plugin-seofields'
171
+ *
172
+ * export default defineConfig({
173
+ * // ...
174
+ * plugins: [seofields()],
175
+ * })
176
+ * ```
177
+ */
178
+ export declare const seofields: Plugin_2<void | MyPluginConfig>
179
+
180
+ export declare const seoFieldsSchema: {
181
+ type: 'object'
182
+ name: 'seoFields'
183
+ } & Omit<ObjectDefinition, 'preview'> & {
184
+ preview?: PreviewConfig<Record<string, string>, Record<never, any>> | undefined
185
+ }
186
+
187
+ export declare interface SeoValidationRules {
188
+ title: {
189
+ maxLength: number
190
+ warningLength: number
191
+ }
192
+ description: {
193
+ maxLength: number
194
+ warningLength: number
195
+ }
196
+ openGraphTitle: {
197
+ maxLength: number
198
+ }
199
+ openGraphDescription: {
200
+ maxLength: number
201
+ }
202
+ twitterTitle: {
203
+ maxLength: number
204
+ }
205
+ twitterDescription: {
206
+ maxLength: number
207
+ }
208
+ }
209
+
210
+ export declare interface TwitterCardSettings {
211
+ _type: 'twitter'
212
+ card?: 'summary' | 'summary_large_image' | 'app' | 'player'
213
+ site?: string
214
+ title?: string
215
+ description?: string
216
+ image?: SanityImageWithAlt
217
+ }
218
+
219
+ export declare const twitterSchema: {
220
+ type: 'object'
221
+ name: 'twitter'
222
+ } & Omit<ObjectDefinition, 'preview'> & {
223
+ preview?: PreviewConfig<Record<string, string>, Record<never, any>> | undefined
224
+ }
225
+
226
+ export {}