Skip to content

Commit 1637d9b

Browse files
committed
chore: update package dependencies and enhance sitemap functionality
- Upgraded pnpm to version 10.34.1 for improved package management. - Added new skills to skills-lock.json for better content modeling and SEO practices. - Introduced schema-dts version 2.0.0 to enhance TypeScript support. - Updated sitemap generation to utilize SITE_URL for dynamic URL handling across various components. - Enhanced metadata generation for authors, guests, podcasts, posts, and sponsors to include structured data for better SEO.
1 parent f5c9c35 commit 1637d9b

66 files changed

Lines changed: 9900 additions & 98 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
---
2+
name: content-modeling-best-practices
3+
description: Structured content modeling guidance for schema design, content architecture, content reuse, references versus embedded objects, separation of concerns, and taxonomies across Sanity and other headless CMSes. Use this skill when designing or refactoring content types, deciding field shapes, debating reusable versus nested content, planning omnichannel content models, or reviewing whether a schema is too page-shaped or presentation-driven.
4+
---
5+
6+
# Content Modeling Best Practices
7+
8+
Principles for designing structured content that's flexible, reusable, and maintainable. These concepts apply to any headless CMS but include Sanity-specific implementation notes.
9+
10+
## When to Apply
11+
12+
Reference these guidelines when:
13+
- Starting a new project and designing the content model
14+
- Evaluating whether content should be structured or free-form
15+
- Deciding between references and embedded content
16+
- Planning for multi-channel content delivery
17+
- Refactoring existing content structures
18+
19+
## Core Principles
20+
21+
1. **Content is data, not pages** — Structure content for meaning, not presentation
22+
2. **Single source of truth** — Avoid content duplication
23+
3. **Future-proof** — Design for channels that don't exist yet
24+
4. **Editor-centric** — Optimize for the people creating content
25+
26+
## References
27+
28+
Start with the reference that matches the modeling decision in front of you, instead of loading every topic at once. See `references/` for detailed guidance on specific topics:
29+
- `references/separation-of-concerns.md` — Separating content from presentation
30+
- `references/reference-vs-embedding.md` — When to use references vs embedded objects
31+
- `references/content-reuse.md` — Content reuse patterns and the reuse spectrum
32+
- `references/taxonomy-classification.md` — Flat, hierarchical, and faceted classification
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
# Content Reuse Patterns
2+
3+
Effective content models maximize reuse while minimizing duplication. Here are patterns for achieving both.
4+
5+
## The Content Reuse Spectrum
6+
7+
```
8+
Full Duplication ←————————————————→ Full Reference
9+
(Copy everything) (Link to one source)
10+
```
11+
12+
Most real-world content sits somewhere in between.
13+
14+
## Pattern 1: Shared Components
15+
16+
Create reusable content blocks that can be embedded anywhere.
17+
18+
**Use case:** Testimonials, FAQs, CTAs that appear on multiple pages.
19+
20+
```typescript
21+
// Standalone testimonial documents
22+
defineType({
23+
name: 'testimonial',
24+
type: 'document',
25+
fields: [
26+
defineField({ name: 'quote', type: 'text' }),
27+
defineField({ name: 'author', type: 'string' }),
28+
defineField({ name: 'company', type: 'string' }),
29+
]
30+
})
31+
32+
// Reference in page builders
33+
defineField({
34+
name: 'pageBuilder',
35+
type: 'array',
36+
of: [
37+
{ type: 'reference', to: [{ type: 'testimonial' }] }
38+
]
39+
})
40+
```
41+
42+
## Pattern 2: Shared Field Sets
43+
44+
Extract common fields into reusable definitions.
45+
46+
**Use case:** SEO fields, social metadata, common dates.
47+
48+
```typescript
49+
// Shared field definition
50+
export const seoFields = [
51+
defineField({ name: 'seoTitle', type: 'string' }),
52+
defineField({ name: 'seoDescription', type: 'text' }),
53+
defineField({ name: 'ogImage', type: 'image' }),
54+
]
55+
56+
// Spread into multiple types
57+
defineType({
58+
name: 'page',
59+
fields: [
60+
defineField({ name: 'title', type: 'string' }),
61+
...seoFields
62+
]
63+
})
64+
65+
defineType({
66+
name: 'post',
67+
fields: [
68+
defineField({ name: 'title', type: 'string' }),
69+
...seoFields
70+
]
71+
})
72+
```
73+
74+
## Pattern 3: Taxonomy References
75+
76+
Centralize classification for consistent tagging.
77+
78+
**Use case:** Categories, tags, topics that span content types.
79+
80+
```typescript
81+
// Central taxonomy
82+
defineType({
83+
name: 'category',
84+
type: 'document',
85+
fields: [
86+
defineField({ name: 'title', type: 'string' }),
87+
defineField({ name: 'slug', type: 'slug' }),
88+
]
89+
})
90+
91+
// Used across content types
92+
defineField({
93+
name: 'categories',
94+
type: 'array',
95+
of: [{ type: 'reference', to: [{ type: 'category' }] }]
96+
})
97+
```
98+
99+
## Pattern 4: Content Fragments
100+
101+
Small, reusable pieces that combine into larger content.
102+
103+
**Use case:** Bios, addresses, contact info.
104+
105+
```typescript
106+
// Fragment type
107+
defineType({
108+
name: 'contactInfo',
109+
type: 'object',
110+
fields: [
111+
defineField({ name: 'email', type: 'email' }),
112+
defineField({ name: 'phone', type: 'string' }),
113+
defineField({ name: 'address', type: 'text' }),
114+
]
115+
})
116+
117+
// Reused across types
118+
defineType({
119+
name: 'office',
120+
fields: [
121+
defineField({ name: 'name', type: 'string' }),
122+
defineField({ name: 'contact', type: 'contactInfo' }),
123+
]
124+
})
125+
```
126+
127+
## Anti-Pattern: Over-Abstraction
128+
129+
Not everything needs to be reusable. If content is only used in one place, embedding is simpler.
130+
131+
**Signs of over-abstraction:**
132+
- References that are only used once
133+
- Editors navigating multiple documents for one page
134+
- Complex queries joining rarely-shared content
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
# Reference vs Embedding Content
2+
3+
When should content be linked (referenced) vs copied (embedded)? This decision affects reusability, query complexity, and editing workflows.
4+
5+
## The Trade-offs
6+
7+
| Aspect | Reference | Embedded Object |
8+
|--------|-----------|-----------------|
9+
| Reusability | ✅ Shared across documents | ❌ Copied per document |
10+
| Single source | ✅ Update once, reflects everywhere | ❌ Must update each copy |
11+
| Query complexity | Requires joins/expansion | Inline, simpler queries |
12+
| Editing UX | Separate editing interface | All fields in one place |
13+
| Independence | Can exist on its own | Only exists within parent |
14+
15+
## When to Reference
16+
17+
Use references when content:
18+
- **Is reusable** — Same author across many articles
19+
- **Needs central management** — Update product info once
20+
- **Has its own lifecycle** — Published/draft independent of parent
21+
- **Should stay in sync** — Price changes reflect everywhere
22+
23+
**Examples:**
24+
- Author profiles
25+
- Product catalog items
26+
- Shared testimonials
27+
- Category taxonomy
28+
- Reusable CTAs
29+
30+
## When to Embed
31+
32+
Use embedded objects when content:
33+
- **Is unique to this document** — Page-specific hero
34+
- **Doesn't make sense alone** — SEO metadata
35+
- **Should be copied, not linked** — Historical snapshot
36+
- **Simplifies editing** — All fields in one form
37+
38+
**Examples:**
39+
- SEO metadata
40+
- Page-specific sections
41+
- Address information
42+
- Social links
43+
- Configuration options
44+
45+
## Sanity Implementation
46+
47+
```typescript
48+
// Reference: Author is reusable
49+
defineField({
50+
name: 'author',
51+
type: 'reference',
52+
to: [{ type: 'author' }]
53+
})
54+
55+
// Embedded: SEO is page-specific
56+
defineField({
57+
name: 'seo',
58+
type: 'object',
59+
fields: [
60+
defineField({ name: 'title', type: 'string' }),
61+
defineField({ name: 'description', type: 'text' })
62+
]
63+
})
64+
```
65+
66+
## The Hybrid Approach
67+
68+
Sometimes you want both: a reference for the canonical data, plus embedded overrides.
69+
70+
```typescript
71+
defineField({
72+
name: 'featuredProduct',
73+
type: 'object',
74+
fields: [
75+
defineField({
76+
name: 'product',
77+
type: 'reference',
78+
to: [{ type: 'product' }]
79+
}),
80+
defineField({
81+
name: 'overrideTitle',
82+
type: 'string',
83+
description: 'Optional: Override the product title for this context'
84+
}),
85+
]
86+
})
87+
```
88+
89+
Query uses `coalesce(overrideTitle, product->title)`.
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
# Separation of Content and Presentation
2+
3+
The most important principle in structured content: **separate what content IS from how it LOOKS**.
4+
5+
## The Problem
6+
7+
When content is tied to presentation:
8+
- Redesigns require content migration
9+
- Content can't be reused across channels (web, mobile, voice)
10+
- Editors make design decisions instead of content decisions
11+
- A/B testing requires duplicate content
12+
13+
## The Principle
14+
15+
Model content based on **meaning and purpose**, not visual appearance.
16+
17+
### Bad: Presentation-Focused
18+
19+
```
20+
BigHeroText → What if we want small heroes?
21+
RedButton → What if brand colors change?
22+
ThreeColumnLayout → What if mobile needs one column?
23+
LeftSidebar → Position is a frontend concern
24+
MobileImage → Device-specific content is fragile
25+
```
26+
27+
### Good: Meaning-Focused
28+
29+
```
30+
Headline → The main message (render however)
31+
CallToAction → An action we want users to take
32+
Features → A list of things (columns decided by frontend)
33+
RelatedContent → Content relationships (position by context)
34+
Image → One image with responsive crops
35+
```
36+
37+
## Testing Your Model
38+
39+
Ask: "If we completely redesigned the site, would these field names still make sense?"
40+
41+
- `threeColumnFeatures` → ❌ Fails (what if 2 columns?)
42+
- `features` → ✅ Works (describes the content's purpose: a list of product features)
43+
- `blueHighlightBox` → ❌ Fails (what if we go purple?)
44+
- `callout` → ✅ Works (describes the content's role: an attention-grabbing aside)
45+
46+
## Sanity Implementation
47+
48+
```typescript
49+
// ❌ Avoid presentation-focused names
50+
defineField({ name: 'bigHeroText', type: 'string' })
51+
defineField({ name: 'fontSize', type: 'number' })
52+
defineField({ name: 'backgroundColor', type: 'color' })
53+
54+
// ✅ Use meaning-focused names
55+
defineField({ name: 'headline', type: 'string' })
56+
defineField({ name: 'emphasis', type: 'string', options: { list: ['standard', 'prominent'] } })
57+
defineField({ name: 'tone', type: 'string', options: { list: ['neutral', 'warning', 'success'] } })
58+
```
59+
60+
The frontend translates `tone: 'warning'` to visual styles. Content stays semantic.

0 commit comments

Comments
 (0)