multisite-cms-mcp 1.2.4 → 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/dist/index.js +5 -6
- package/dist/tools/get-conversion-guide.d.ts.map +1 -1
- package/dist/tools/get-conversion-guide.js +134 -295
- package/dist/tools/get-example.d.ts.map +1 -1
- package/dist/tools/get-example.js +166 -409
- package/dist/tools/get-schema.d.ts +1 -1
- package/dist/tools/get-schema.d.ts.map +1 -1
- package/dist/tools/get-schema.js +130 -450
- package/dist/tools/get-tenant-schema.d.ts +9 -3
- package/dist/tools/get-tenant-schema.d.ts.map +1 -1
- package/dist/tools/get-tenant-schema.js +16 -4
- package/dist/tools/sync-schema.d.ts +1 -1
- package/dist/tools/sync-schema.d.ts.map +1 -1
- package/dist/tools/sync-schema.js +51 -97
- package/dist/tools/validate-manifest.d.ts.map +1 -1
- package/dist/tools/validate-manifest.js +41 -107
- package/dist/tools/validate-package.d.ts.map +1 -1
- package/dist/tools/validate-package.js +46 -41
- package/dist/tools/validate-template.d.ts +2 -2
- package/dist/tools/validate-template.d.ts.map +1 -1
- package/dist/tools/validate-template.js +67 -201
- package/package.json +1 -1
package/dist/tools/get-schema.js
CHANGED
|
@@ -2,325 +2,141 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.getSchema = getSchema;
|
|
4
4
|
/**
|
|
5
|
-
* Returns the complete CMS schema
|
|
5
|
+
* Returns the complete CMS schema reference for custom collections
|
|
6
6
|
*/
|
|
7
7
|
async function getSchema() {
|
|
8
8
|
return `# CMS Schema Reference
|
|
9
9
|
|
|
10
|
-
##
|
|
11
|
-
|
|
12
|
-
### Blog Posts (\`blogs\`)
|
|
13
|
-
Time-stamped articles with optional author reference.
|
|
14
|
-
|
|
15
|
-
**Fields:**
|
|
16
|
-
- \`{{name}}\` (text, required) - Post title
|
|
17
|
-
- \`{{slug}}\` (text, required) - URL slug
|
|
18
|
-
- \`{{mainImage}}\` (image) - Hero/cover image URL
|
|
19
|
-
- \`{{thumbnailImage}}\` (image) - Smaller preview image
|
|
20
|
-
- \`{{postSummary}}\` (text) - Short excerpt/description
|
|
21
|
-
- \`{{{postBody}}}\` (richText) - Main content (MUST use triple braces)
|
|
22
|
-
- \`{{featured}}\` (boolean) - Featured flag
|
|
23
|
-
- \`{{url}}\` (special) - Generated URL to post detail page
|
|
24
|
-
|
|
25
|
-
**Date tokens (automatically tracked):**
|
|
26
|
-
- \`{{createdAt}}\` - When the post was first created
|
|
27
|
-
- \`{{publishedAt}}\` - When the post was published (empty for drafts)
|
|
28
|
-
- \`{{updatedAt}}\` - When the post was last updated
|
|
29
|
-
|
|
30
|
-
**Author Reference (when assigned):**
|
|
31
|
-
- \`{{author.name}}\` - Author's name
|
|
32
|
-
- \`{{author.picture}}\` - Author's photo URL
|
|
33
|
-
- \`{{{author.bio}}}\` (richText) - Author's biography
|
|
34
|
-
- \`{{author.email}}\` - Author's email
|
|
35
|
-
- \`{{author.twitterProfileLink}}\` - Twitter URL
|
|
36
|
-
- \`{{author.linkedinProfileLink}}\` - LinkedIn URL
|
|
37
|
-
- \`{{author.url}}\` - Link to author's page
|
|
38
|
-
|
|
39
|
-
**Loop syntax:** \`{{#each blogs}}\` or \`{{#each blogs featured=true limit=3}}\`
|
|
10
|
+
## Collections Overview
|
|
40
11
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
### Authors (\`authors\`)
|
|
44
|
-
Content creators who can be referenced by blog posts.
|
|
45
|
-
|
|
46
|
-
**Fields:**
|
|
47
|
-
- \`{{name}}\` (text, required) - Author's name
|
|
48
|
-
- \`{{slug}}\` (text, required) - URL slug
|
|
49
|
-
- \`{{{bio}}}\` (richText) - Biography (MUST use triple braces)
|
|
50
|
-
- \`{{picture}}\` (image) - Author photo URL
|
|
51
|
-
- \`{{email}}\` (email) - Email address
|
|
52
|
-
- \`{{twitterProfileLink}}\` (url) - Twitter URL
|
|
53
|
-
- \`{{linkedinProfileLink}}\` (url) - LinkedIn URL
|
|
54
|
-
- \`{{url}}\` (special) - Generated URL to author detail page
|
|
12
|
+
All CMS content is managed through **custom collections**. Collections are content types you define (e.g., Blog Posts, Team Members, Services, Products) with custom fields.
|
|
55
13
|
|
|
56
|
-
**
|
|
14
|
+
**To see the exact collections and fields for a specific project, use the \`get_tenant_schema\` tool.**
|
|
57
15
|
|
|
58
16
|
---
|
|
59
17
|
|
|
60
|
-
|
|
61
|
-
Staff, employees, leadership profiles.
|
|
18
|
+
## Collection Templates
|
|
62
19
|
|
|
63
|
-
**
|
|
64
|
-
- \`{{name}}\` (text, required) - Team member's name
|
|
65
|
-
- \`{{slug}}\` (text) - URL slug (if using detail pages)
|
|
66
|
-
- \`{{role}}\` (text) - Job title/role
|
|
67
|
-
- \`{{{bio}}}\` (richText) - Biography (MUST use triple braces)
|
|
68
|
-
- \`{{photo}}\` (image) - Headshot/photo URL
|
|
69
|
-
- \`{{email}}\` (email) - Email address
|
|
70
|
-
- \`{{order}}\` (number) - Display order
|
|
71
|
-
|
|
72
|
-
**Loop syntax:** \`{{#each team sort="order" order="asc"}}\`
|
|
73
|
-
|
|
74
|
-
---
|
|
20
|
+
When creating a new collection, you can start from a **template** that pre-configures common field sets:
|
|
75
21
|
|
|
76
|
-
|
|
77
|
-
|
|
22
|
+
- **Blog Posts** - Articles with images, summary, body, author reference
|
|
23
|
+
- **Authors** - Content creators with bio, photo, social links
|
|
24
|
+
- **Team Members** - Staff profiles with role, photo, bio
|
|
25
|
+
- **Downloads** - Downloadable files with description and category
|
|
26
|
+
- **FAQs** - Question and answer pairs
|
|
27
|
+
- **Products** - Items with price, description, images
|
|
78
28
|
|
|
79
|
-
|
|
80
|
-
- \`{{title}}\` (text, required) - File title
|
|
81
|
-
- \`{{slug}}\` (text) - URL slug
|
|
82
|
-
- \`{{description}}\` (text) - Description
|
|
83
|
-
- \`{{fileUrl}}\` (url) - Download link
|
|
84
|
-
- \`{{category}}\` (select) - File category
|
|
85
|
-
- \`{{order}}\` (number) - Display order
|
|
86
|
-
|
|
87
|
-
**Loop syntax:** \`{{#each downloads sort="order" order="asc"}}\`
|
|
29
|
+
Templates are just starting points - you can customize fields after creation.
|
|
88
30
|
|
|
89
31
|
---
|
|
90
32
|
|
|
91
|
-
##
|
|
92
|
-
|
|
93
|
-
Custom collections are tenant-defined content types created in the CMS dashboard. Each custom collection has its own slug and user-defined fields.
|
|
33
|
+
## Token Syntax
|
|
94
34
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
35
|
+
### Basic Tokens
|
|
36
|
+
\`\`\`html
|
|
37
|
+
{{fieldSlug}} <!-- For text, number, boolean, image, url, date, select -->
|
|
38
|
+
{{{fieldSlug}}} <!-- For richText fields (MUST use triple braces) -->
|
|
39
|
+
\`\`\`
|
|
98
40
|
|
|
99
|
-
|
|
41
|
+
### Built-in Tokens (Available on ALL items)
|
|
100
42
|
- \`{{name}}\` - Item name/title (REQUIRED - every item has a name)
|
|
101
|
-
- \`{{slug}}\` - Item URL slug (if collection has detail pages
|
|
43
|
+
- \`{{slug}}\` - Item URL slug (if collection has detail pages)
|
|
102
44
|
- \`{{url}}\` - Full item URL (e.g., /services/my-service)
|
|
103
45
|
|
|
104
|
-
|
|
46
|
+
### Date Tokens (Automatically tracked)
|
|
105
47
|
- \`{{createdAt}}\` - When the item was first created
|
|
106
48
|
- \`{{publishedAt}}\` - When the item was published (empty for drafts)
|
|
107
49
|
- \`{{updatedAt}}\` - When the item was last updated
|
|
108
50
|
|
|
109
|
-
**Example - A "Services" collection with fields: image, description (richText), price:**
|
|
110
|
-
\`\`\`html
|
|
111
|
-
<section class="services">
|
|
112
|
-
{{#each services sort="publishedAt" order="desc"}}
|
|
113
|
-
<div class="service-card">
|
|
114
|
-
<img src="{{image}}" alt="{{name}}">
|
|
115
|
-
<h2><a href="{{url}}">{{name}}</a></h2>
|
|
116
|
-
{{{description}}}
|
|
117
|
-
<p class="price">\${{price}}</p>
|
|
118
|
-
<time>{{publishedAt}}</time>
|
|
119
|
-
</div>
|
|
120
|
-
{{/each}}
|
|
121
|
-
</section>
|
|
122
|
-
\`\`\`
|
|
123
|
-
|
|
124
|
-
**Example - A "Testimonials" collection with fields: quote (richText), company, rating:**
|
|
125
|
-
\`\`\`html
|
|
126
|
-
<section class="testimonials">
|
|
127
|
-
{{#each testimonials limit=6 sort="publishedAt" order="desc"}}
|
|
128
|
-
<blockquote class="testimonial">
|
|
129
|
-
{{{quote}}}
|
|
130
|
-
<cite>
|
|
131
|
-
<strong>{{name}}</strong>
|
|
132
|
-
{{#if company}}<span>{{company}}</span>{{/if}}
|
|
133
|
-
</cite>
|
|
134
|
-
</blockquote>
|
|
135
|
-
{{/each}}
|
|
136
|
-
</section>
|
|
137
|
-
\`\`\`
|
|
138
|
-
|
|
139
|
-
**To see exact fields for a tenant's custom collections, use the \`get_tenant_schema\` tool.**
|
|
140
|
-
|
|
141
51
|
---
|
|
142
52
|
|
|
143
|
-
##
|
|
144
|
-
|
|
145
|
-
Tenants can add custom fields to Blog Posts, Authors, Team Members, and Downloads. These custom fields work exactly like built-in fields.
|
|
53
|
+
## Loop Syntax
|
|
146
54
|
|
|
147
|
-
|
|
148
|
-
- \`{{customFieldSlug}}\` for text, number, boolean, image, url, date, select
|
|
149
|
-
- \`{{{customFieldSlug}}}\` for richText fields
|
|
150
|
-
|
|
151
|
-
**Example - "category" field added to blogs:**
|
|
55
|
+
### Basic Loop
|
|
152
56
|
\`\`\`html
|
|
153
|
-
{{#each
|
|
154
|
-
<article
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
<span class="category-badge">{{category}}</span>
|
|
158
|
-
{{/if}}
|
|
159
|
-
<p>{{postSummary}}</p>
|
|
160
|
-
</article>
|
|
161
|
-
{{/each}}
|
|
162
|
-
\`\`\`
|
|
163
|
-
|
|
164
|
-
**Example - "department" and "linkedinUrl" fields added to team:**
|
|
165
|
-
\`\`\`html
|
|
166
|
-
{{#each team sort="order" order="asc"}}
|
|
167
|
-
<div class="team-member">
|
|
168
|
-
<img src="{{photo}}" alt="{{name}}">
|
|
169
|
-
<h3>{{name}}</h3>
|
|
170
|
-
<p class="role">{{role}}</p>
|
|
171
|
-
{{#if department}}
|
|
172
|
-
<p class="department">{{department}}</p>
|
|
173
|
-
{{/if}}
|
|
174
|
-
{{#if linkedinUrl}}
|
|
175
|
-
<a href="{{linkedinUrl}}">LinkedIn</a>
|
|
176
|
-
{{/if}}
|
|
177
|
-
</div>
|
|
57
|
+
{{#each collectionSlug}}
|
|
58
|
+
<article>
|
|
59
|
+
<h2>{{name}}</h2>
|
|
60
|
+
</article>
|
|
178
61
|
{{/each}}
|
|
179
62
|
\`\`\`
|
|
180
63
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
Relation fields allow you to link items from one collection to items in another collection. This is similar to how blog posts can have an author reference.
|
|
188
|
-
|
|
189
|
-
### Creating Relation Fields
|
|
190
|
-
|
|
191
|
-
When creating a custom collection field, choose type "Relation" and select the target collection. You can link to:
|
|
192
|
-
- Built-in collections: \`blogs\`, \`authors\`, \`team\`, \`downloads\`
|
|
193
|
-
- Custom collections: Any collection you've created (e.g., \`tags\`, \`categories\`, \`services\`)
|
|
194
|
-
|
|
195
|
-
### Using Relation Fields in Templates
|
|
196
|
-
|
|
197
|
-
When an item has a relation field set, the related item's data is available using dot notation:
|
|
64
|
+
### Loop Modifiers
|
|
65
|
+
- \`limit=N\` - Limit to N items
|
|
66
|
+
- \`featured=true\` - Only featured items (if collection has a boolean "featured" field)
|
|
67
|
+
- \`sort="fieldName"\` - Sort by field
|
|
68
|
+
- \`order="asc|desc"\` - Sort direction
|
|
198
69
|
|
|
199
70
|
\`\`\`html
|
|
200
|
-
|
|
201
|
-
{{
|
|
202
|
-
<article class="project-card">
|
|
203
|
-
<h2>{{name}}</h2>
|
|
204
|
-
{{#if category}}
|
|
205
|
-
<span class="category-tag">{{category.name}}</span>
|
|
206
|
-
<a href="{{category.url}}">View all {{category.name}} projects</a>
|
|
207
|
-
{{/if}}
|
|
208
|
-
</article>
|
|
71
|
+
{{#each posts limit=6 sort="publishedAt" order="desc"}}
|
|
72
|
+
<article>{{name}}</article>
|
|
209
73
|
{{/each}}
|
|
210
74
|
\`\`\`
|
|
211
75
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
- \`{{
|
|
215
|
-
- \`{{
|
|
216
|
-
- \`{{
|
|
217
|
-
|
|
218
|
-
### Common Use Cases
|
|
219
|
-
|
|
220
|
-
**Tags on Blog Posts:**
|
|
221
|
-
\`\`\`html
|
|
222
|
-
{{#each blogs}}
|
|
223
|
-
<article>
|
|
224
|
-
<h2>{{name}}</h2>
|
|
225
|
-
{{#if tag}}
|
|
226
|
-
<span class="tag">{{tag.name}}</span>
|
|
227
|
-
{{/if}}
|
|
228
|
-
</article>
|
|
229
|
-
{{/each}}
|
|
230
|
-
\`\`\`
|
|
76
|
+
### Loop Variables
|
|
77
|
+
Inside \`{{#each}}\` blocks:
|
|
78
|
+
- \`{{@first}}\` - true for first item
|
|
79
|
+
- \`{{@last}}\` - true for last item
|
|
80
|
+
- \`{{@index}}\` - zero-based index
|
|
231
81
|
|
|
232
|
-
**Category Pages - Filtering by Relation:**
|
|
233
82
|
\`\`\`html
|
|
234
|
-
|
|
235
|
-
{{#
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
<h3>{{name}}</h3>
|
|
239
|
-
</div>
|
|
240
|
-
{{/if}}
|
|
83
|
+
{{#each services limit=3}}
|
|
84
|
+
<div class="{{#if @first}}featured{{/if}}">
|
|
85
|
+
{{name}}
|
|
86
|
+
</div>
|
|
241
87
|
{{/each}}
|
|
242
88
|
\`\`\`
|
|
243
89
|
|
|
244
|
-
**Related Services on Projects:**
|
|
245
|
-
\`\`\`html
|
|
246
|
-
{{#if relatedService}}
|
|
247
|
-
<div class="related-service">
|
|
248
|
-
<h4>Service Used</h4>
|
|
249
|
-
<a href="{{relatedService.url}}">{{relatedService.name}}</a>
|
|
250
|
-
{{#if relatedService.description}}
|
|
251
|
-
<p>{{relatedService.description}}</p>
|
|
252
|
-
{{/if}}
|
|
253
|
-
</div>
|
|
254
|
-
{{/if}}
|
|
255
|
-
\`\`\`
|
|
256
|
-
|
|
257
90
|
---
|
|
258
91
|
|
|
259
|
-
##
|
|
92
|
+
## Conditionals
|
|
260
93
|
|
|
261
|
-
###
|
|
94
|
+
### Check if field has value
|
|
262
95
|
\`\`\`html
|
|
263
|
-
{{#
|
|
264
|
-
<
|
|
265
|
-
<h2>{{name}}</h2>
|
|
266
|
-
</article>
|
|
267
|
-
{{/each}}
|
|
268
|
-
\`\`\`
|
|
269
|
-
|
|
270
|
-
**Loop modifiers:**
|
|
271
|
-
- \`limit=N\` - Limit to N items
|
|
272
|
-
- \`featured=true\` - Only featured items
|
|
273
|
-
- \`sort="fieldName"\` - Sort by field
|
|
274
|
-
- \`order="asc|desc"\` - Sort direction
|
|
275
|
-
|
|
276
|
-
### Conditionals
|
|
277
|
-
\`\`\`html
|
|
278
|
-
<!-- Check if a field has a value -->
|
|
279
|
-
{{#if mainImage}}
|
|
280
|
-
<img src="{{mainImage}}" alt="{{name}}">
|
|
96
|
+
{{#if image}}
|
|
97
|
+
<img src="{{image}}" alt="{{name}}">
|
|
281
98
|
{{else}}
|
|
282
99
|
<div class="placeholder"></div>
|
|
283
100
|
{{/if}}
|
|
284
101
|
|
|
285
102
|
{{#unless featured}}
|
|
286
|
-
<span>Regular
|
|
103
|
+
<span>Regular item</span>
|
|
287
104
|
{{/unless}}
|
|
288
105
|
\`\`\`
|
|
289
106
|
|
|
290
|
-
### Collection Empty Checks
|
|
291
|
-
Check if a collection has items - useful for "No posts yet" fallbacks:
|
|
292
|
-
|
|
107
|
+
### Collection Empty Checks
|
|
293
108
|
\`\`\`html
|
|
294
|
-
{{#each
|
|
109
|
+
{{#each posts}}
|
|
295
110
|
<article>{{name}}</article>
|
|
296
111
|
{{/each}}
|
|
297
112
|
|
|
298
|
-
{{#unless
|
|
113
|
+
{{#unless posts}}
|
|
299
114
|
<p>No posts yet. Check back soon!</p>
|
|
300
115
|
{{/unless}}
|
|
301
116
|
\`\`\`
|
|
302
117
|
|
|
303
|
-
|
|
118
|
+
---
|
|
119
|
+
|
|
120
|
+
## Equality Comparisons
|
|
304
121
|
|
|
305
|
-
|
|
306
|
-
Compare two field values using the \`(eq field1 field2)\` helper:
|
|
122
|
+
Compare field values using the \`(eq field1 field2)\` helper:
|
|
307
123
|
|
|
308
124
|
\`\`\`html
|
|
309
125
|
<!-- Show content when fields ARE equal -->
|
|
310
|
-
{{#if (eq
|
|
311
|
-
<span>
|
|
126
|
+
{{#if (eq category.slug ../slug)}}
|
|
127
|
+
<span>Current category</span>
|
|
312
128
|
{{/if}}
|
|
313
129
|
|
|
314
|
-
<!-- Show content when fields are NOT equal -->
|
|
130
|
+
<!-- Show content when fields are NOT equal (exclude current) -->
|
|
315
131
|
{{#unless (eq slug ../slug)}}
|
|
316
132
|
<a href="{{url}}">{{name}}</a>
|
|
317
133
|
{{/unless}}
|
|
318
134
|
\`\`\`
|
|
319
135
|
|
|
320
|
-
|
|
136
|
+
### Related Items Pattern (Exclude Current)
|
|
321
137
|
\`\`\`html
|
|
322
138
|
<h3>Other Posts</h3>
|
|
323
|
-
{{#each
|
|
139
|
+
{{#each posts limit=3}}
|
|
324
140
|
{{#unless (eq slug ../slug)}}
|
|
325
141
|
<article>
|
|
326
142
|
<a href="{{url}}">{{name}}</a>
|
|
@@ -329,28 +145,15 @@ Compare two field values using the \`(eq field1 field2)\` helper:
|
|
|
329
145
|
{{/each}}
|
|
330
146
|
\`\`\`
|
|
331
147
|
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
### Loop Variables
|
|
335
|
-
Inside \`{{#each}}\` blocks:
|
|
336
|
-
- \`{{@first}}\` - true for first item
|
|
337
|
-
- \`{{@last}}\` - true for last item
|
|
338
|
-
- \`{{@index}}\` - zero-based index
|
|
148
|
+
---
|
|
339
149
|
|
|
340
|
-
|
|
341
|
-
{{#each blogs limit=3}}
|
|
342
|
-
<article class="{{#if @first}}featured{{/if}}">
|
|
343
|
-
{{name}}
|
|
344
|
-
</article>
|
|
345
|
-
{{/each}}
|
|
346
|
-
\`\`\`
|
|
150
|
+
## Parent Context References
|
|
347
151
|
|
|
348
|
-
|
|
349
|
-
Inside loops, access the parent scope (page's current item) using \`../\`:
|
|
152
|
+
Inside loops, access the parent scope using \`../\`:
|
|
350
153
|
|
|
351
154
|
\`\`\`html
|
|
352
155
|
<!-- On author detail page, show only posts by THIS author -->
|
|
353
|
-
{{#each
|
|
156
|
+
{{#each posts}}
|
|
354
157
|
{{#if (eq author.name ../name)}}
|
|
355
158
|
<h3>{{name}}</h3>
|
|
356
159
|
{{/if}}
|
|
@@ -361,186 +164,93 @@ Inside loops, access the parent scope (page's current item) using \`../\`:
|
|
|
361
164
|
- \`../slug\` - Parent item's slug
|
|
362
165
|
- \`../fieldName\` - Any field from the parent scope
|
|
363
166
|
|
|
364
|
-
|
|
365
|
-
- Author pages: filter posts by current author
|
|
366
|
-
- Category pages: filter items by current category
|
|
367
|
-
- Related items: match based on current detail page
|
|
167
|
+
---
|
|
368
168
|
|
|
369
|
-
|
|
169
|
+
## Relation Fields
|
|
370
170
|
|
|
371
|
-
|
|
372
|
-
|--------|-------------|----------------------|
|
|
373
|
-
| \`{{#if (eq field1 field2)}}\` | Compare two fields | Fields ARE equal |
|
|
374
|
-
| \`{{#unless (eq field1 field2)}}\` | Exclude matches | Fields are NOT equal |
|
|
375
|
-
| \`{{#eq field "value"}}\` | Compare to string | Field equals string |
|
|
171
|
+
Link items from one collection to another. Access related item data using dot notation:
|
|
376
172
|
|
|
377
|
-
**Examples:**
|
|
378
173
|
\`\`\`html
|
|
379
|
-
|
|
380
|
-
|
|
174
|
+
{{#each projects}}
|
|
175
|
+
<article>
|
|
176
|
+
<h2>{{name}}</h2>
|
|
177
|
+
{{#if category}}
|
|
178
|
+
<span class="tag">{{category.name}}</span>
|
|
179
|
+
<a href="{{category.url}}">View all {{category.name}}</a>
|
|
180
|
+
{{/if}}
|
|
181
|
+
</article>
|
|
182
|
+
{{/each}}
|
|
183
|
+
\`\`\`
|
|
381
184
|
|
|
382
|
-
|
|
383
|
-
{{
|
|
185
|
+
**Available tokens for related items:**
|
|
186
|
+
- \`{{relationField.name}}\` - Related item's name
|
|
187
|
+
- \`{{relationField.slug}}\` - Related item's slug
|
|
188
|
+
- \`{{relationField.url}}\` - Related item's full URL
|
|
189
|
+
- \`{{relationField.anyField}}\` - Any field from the related collection
|
|
384
190
|
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
191
|
+
---
|
|
192
|
+
|
|
193
|
+
## Rich Text (Triple Braces)
|
|
388
194
|
|
|
389
|
-
### Rich Text (Triple Braces)
|
|
390
195
|
For HTML content that should NOT be escaped:
|
|
391
196
|
\`\`\`html
|
|
392
|
-
{{{
|
|
393
|
-
{{
|
|
197
|
+
{{{description}}} ✓ Correct - renders HTML
|
|
198
|
+
{{description}} ✗ Wrong - escapes HTML as text
|
|
394
199
|
\`\`\`
|
|
395
200
|
|
|
396
201
|
---
|
|
397
202
|
|
|
398
203
|
## Important Rules
|
|
399
204
|
|
|
400
|
-
1. **Triple braces for richText fields** - \`{{{
|
|
401
|
-
2. **Double braces for everything else** - \`{{name}}\`, \`{{
|
|
205
|
+
1. **Triple braces for richText fields** - \`{{{body}}}\`, \`{{{bio}}}\`
|
|
206
|
+
2. **Double braces for everything else** - \`{{name}}\`, \`{{image}}\`
|
|
402
207
|
3. **Always wrap optional fields in {{#if}}** - Check before rendering
|
|
403
208
|
4. **Use {{url}} for links** - Generates correct path based on manifest
|
|
404
|
-
5. **Match field
|
|
209
|
+
5. **Match field slugs exactly** - Case-sensitive
|
|
405
210
|
|
|
406
211
|
---
|
|
407
212
|
|
|
408
|
-
## Image Handling
|
|
409
|
-
|
|
410
|
-
### Two Types of Images
|
|
411
|
-
|
|
412
|
-
**1. Static/UI Images** - Logos, icons, decorative backgrounds, UI elements
|
|
413
|
-
- These are bundled with the site package
|
|
414
|
-
- Use \`/public/\` paths
|
|
415
|
-
- Keep these as static files
|
|
416
|
-
|
|
417
|
-
**2. Content Images** - Blog photos, team headshots, product images, user-uploaded media
|
|
418
|
-
- These are managed through the CMS dashboard
|
|
419
|
-
- Use CMS tokens like \`{{mainImage}}\`, \`{{photo}}\`
|
|
420
|
-
- Never hardcode example/placeholder content images
|
|
421
|
-
|
|
422
|
-
### Static UI Images (Keep as /public/ paths)
|
|
423
|
-
|
|
424
|
-
\`\`\`html
|
|
425
|
-
<!-- These are CORRECT - static UI elements -->
|
|
426
|
-
<img src="/public/images/logo.png" alt="Company Logo">
|
|
427
|
-
<img src="/public/images/icons/arrow.svg" alt="">
|
|
428
|
-
<div style="background-image: url('/public/images/hero-bg.jpg')">
|
|
429
|
-
<link rel="icon" href="/public/images/favicon.ico">
|
|
430
|
-
\`\`\`
|
|
431
|
-
|
|
432
|
-
### Content Images (Use CMS Tokens)
|
|
213
|
+
## Image Handling
|
|
433
214
|
|
|
215
|
+
### Static UI Images (logos, icons)
|
|
434
216
|
\`\`\`html
|
|
435
|
-
|
|
436
|
-
<img src="{{mainImage}}" alt="{{name}}">
|
|
437
|
-
<img src="{{thumbnailImage}}" alt="{{name}}">
|
|
438
|
-
<img src="{{photo}}" alt="{{name}}">
|
|
439
|
-
|
|
440
|
-
<!-- WRONG - Don't hardcode example/placeholder content -->
|
|
441
|
-
<img src="/images/sample-blog-post.jpg" alt="Sample Post">
|
|
442
|
-
<img src="/images/placeholder-team.jpg" alt="Team Member">
|
|
217
|
+
<img src="/public/images/logo.png" alt="Logo">
|
|
443
218
|
\`\`\`
|
|
444
219
|
|
|
445
|
-
###
|
|
446
|
-
|
|
447
|
-
Always wrap image fields in conditionals since they may not be set:
|
|
448
|
-
|
|
220
|
+
### CMS Content Images
|
|
449
221
|
\`\`\`html
|
|
450
|
-
{{#if
|
|
451
|
-
<img src="{{
|
|
222
|
+
{{#if heroImage}}
|
|
223
|
+
<img src="{{heroImage}}" alt="{{name}}">
|
|
452
224
|
{{/if}}
|
|
453
225
|
\`\`\`
|
|
454
226
|
|
|
455
|
-
### Custom Collection Image Fields
|
|
456
|
-
|
|
457
|
-
For custom collections, the **token name matches the field slug** defined when creating the collection.
|
|
458
|
-
|
|
459
|
-
**Example:** A "video" collection with these fields:
|
|
460
|
-
- \`videothumbnail\` (type: image)
|
|
461
|
-
- \`ogimage\` (type: image)
|
|
462
|
-
- \`shortdescription\` (type: text)
|
|
463
|
-
|
|
464
|
-
**Template uses the field slugs as tokens:**
|
|
465
|
-
\`\`\`html
|
|
466
|
-
{{#each video sort="publishedAt" order="desc"}}
|
|
467
|
-
<article class="video-card">
|
|
468
|
-
{{#if videothumbnail}}
|
|
469
|
-
<img src="{{videothumbnail}}" alt="{{name}}">
|
|
470
|
-
{{/if}}
|
|
471
|
-
<h2><a href="{{url}}">{{name}}</a></h2>
|
|
472
|
-
<p>{{shortdescription}}</p>
|
|
473
|
-
</article>
|
|
474
|
-
{{/each}}
|
|
475
|
-
\`\`\`
|
|
476
|
-
|
|
477
|
-
**To find exact field slugs for a tenant's custom collections, use the \`get_tenant_schema\` tool.**
|
|
478
|
-
|
|
479
|
-
### Common Mistakes to Avoid
|
|
480
|
-
|
|
481
|
-
1. **Replacing logos/icons with CMS tokens** - Static UI images should stay as \`/public/\` paths
|
|
482
|
-
2. **Hardcoding example blog/product content** - Use \`{{#each}}\` loops with CMS tokens
|
|
483
|
-
3. **Missing \`{{#each}}\` loops** - Dynamic content requires iteration over the collection
|
|
484
|
-
4. **Wrong field names** - Token must match the exact field slug (case-sensitive)
|
|
485
|
-
|
|
486
227
|
---
|
|
487
228
|
|
|
488
229
|
## CMS Template Configuration
|
|
489
230
|
|
|
490
|
-
|
|
231
|
+
Configure templates in manifest.json:
|
|
491
232
|
|
|
492
|
-
### manifest.json Format
|
|
493
233
|
\`\`\`json
|
|
494
234
|
{
|
|
495
235
|
"cmsTemplates": {
|
|
496
|
-
|
|
497
|
-
"
|
|
498
|
-
"
|
|
499
|
-
"
|
|
500
|
-
"blogPostPath": "/blog",
|
|
501
|
-
|
|
502
|
-
// Built-in: Team, Downloads, Authors
|
|
503
|
-
"team": "pages/team.html",
|
|
504
|
-
"teamPath": "/team",
|
|
505
|
-
"downloads": "pages/downloads.html",
|
|
506
|
-
"downloadsPath": "/resources",
|
|
507
|
-
"authorsIndex": "pages/authors.html",
|
|
508
|
-
"authorsIndexPath": "/authors",
|
|
236
|
+
"postsIndex": "pages/blog.html",
|
|
237
|
+
"postsIndexPath": "/blog",
|
|
238
|
+
"postsDetail": "templates/blog-post.html",
|
|
239
|
+
"postsDetailPath": "/blog",
|
|
509
240
|
|
|
510
|
-
|
|
511
|
-
"
|
|
512
|
-
"
|
|
513
|
-
"
|
|
514
|
-
"videoDetailPath": "/videos",
|
|
515
|
-
|
|
516
|
-
"serviceIndex": "pages/services.html",
|
|
517
|
-
"serviceIndexPath": "/services",
|
|
518
|
-
"serviceDetail": "templates/service-detail.html",
|
|
519
|
-
"serviceDetailPath": "/service"
|
|
241
|
+
"servicesIndex": "pages/services.html",
|
|
242
|
+
"servicesIndexPath": "/services",
|
|
243
|
+
"servicesDetail": "templates/service-detail.html",
|
|
244
|
+
"servicesDetailPath": "/services"
|
|
520
245
|
}
|
|
521
246
|
}
|
|
522
247
|
\`\`\`
|
|
523
248
|
|
|
524
|
-
###
|
|
525
|
-
|
|
526
|
-
**
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
**Example:** Collection with slug \`video\` but paths \`/videos\` and \`/videos/:itemSlug\`:
|
|
530
|
-
- \`videoIndexPath: "/videos"\` → Index page at \`/videos\`
|
|
531
|
-
- \`videoDetailPath: "/videos"\` → Detail pages at \`/videos/my-video\`
|
|
532
|
-
|
|
533
|
-
**Different paths for index and detail:**
|
|
534
|
-
- \`serviceIndexPath: "/services"\` → Index at \`/services\`
|
|
535
|
-
- \`serviceDetailPath: "/service"\` → Detail at \`/service/my-service\`
|
|
536
|
-
|
|
537
|
-
### Template Types
|
|
538
|
-
- **{slug}Index** - Template file for the index/listing page
|
|
539
|
-
- **{slug}IndexPath** - URL path for the index page
|
|
540
|
-
- **{slug}Detail** - Template file for the detail page
|
|
541
|
-
- **{slug}DetailPath** - URL path base for detail pages (item slug appended)
|
|
542
|
-
|
|
543
|
-
**Note:** The CMS settings UI can also configure these, but manifest.json takes precedence for AI conversions.
|
|
249
|
+
### Template Keys Pattern
|
|
250
|
+
- **{collectionSlug}Index** - Template file for listing page
|
|
251
|
+
- **{collectionSlug}IndexPath** - URL path for listing page
|
|
252
|
+
- **{collectionSlug}Detail** - Template file for detail page
|
|
253
|
+
- **{collectionSlug}DetailPath** - URL base for detail pages
|
|
544
254
|
|
|
545
255
|
---
|
|
546
256
|
|
|
@@ -548,10 +258,6 @@ URL paths come EXCLUSIVELY from the manifest's \`{slug}IndexPath\` and \`{slug}D
|
|
|
548
258
|
|
|
549
259
|
Forms are automatically captured and stored in the CMS.
|
|
550
260
|
|
|
551
|
-
### Form Setup
|
|
552
|
-
1. Add \`data-form-name="xxx"\` attribute to the form
|
|
553
|
-
2. Include the form handler script in your JavaScript
|
|
554
|
-
|
|
555
261
|
\`\`\`html
|
|
556
262
|
<form data-form-name="contact">
|
|
557
263
|
<input type="text" name="firstName" required>
|
|
@@ -561,7 +267,7 @@ Forms are automatically captured and stored in the CMS.
|
|
|
561
267
|
</form>
|
|
562
268
|
\`\`\`
|
|
563
269
|
|
|
564
|
-
### Form Handler Script
|
|
270
|
+
### Form Handler Script
|
|
565
271
|
\`\`\`javascript
|
|
566
272
|
document.querySelectorAll('form[data-form-name]').forEach(form => {
|
|
567
273
|
form.addEventListener('submit', async (e) => {
|
|
@@ -586,55 +292,29 @@ document.querySelectorAll('form[data-form-name]').forEach(form => {
|
|
|
586
292
|
|
|
587
293
|
**CRITICAL:** Endpoint is \`/_forms/{formName}\` - NOT \`/api/forms/submit\`
|
|
588
294
|
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
295
|
+
---
|
|
296
|
+
|
|
297
|
+
## SEO Template Tokens
|
|
298
|
+
|
|
299
|
+
For CMS detail pages, use tokens in SEO templates:
|
|
300
|
+
- \`{{name}}\` - Item name for title
|
|
301
|
+
- \`{{description}}\` or summary field - For meta description
|
|
302
|
+
- \`{{image}}\` field - For OG image
|
|
594
303
|
|
|
595
|
-
|
|
304
|
+
SEO templates are configured in the Fast Mode Editor.
|
|
596
305
|
|
|
597
306
|
---
|
|
598
307
|
|
|
599
|
-
##
|
|
308
|
+
## Next Steps
|
|
600
309
|
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
### Available SEO Tokens by Collection
|
|
606
|
-
|
|
607
|
-
#### Blog Posts (\`blogs\`)
|
|
608
|
-
| Token | Use For | Example Output |
|
|
609
|
-
|-------|---------|----------------|
|
|
610
|
-
| \`{{name}}\` | Meta Title | "How to Build a Website" |
|
|
611
|
-
| \`{{postSummary}}\` | Meta Description | "Learn the fundamentals..." |
|
|
612
|
-
| \`{{mainImage}}\` | OG Image | "https://cdn.example.com/hero.jpg" |
|
|
613
|
-
| \`{{author.name}}\` | Author Attribution | "Jane Smith" |
|
|
614
|
-
|
|
615
|
-
**Example SEO Template for Blog:**
|
|
616
|
-
- Meta Title: \`{{name}} | {{author.name}} | My Blog\`
|
|
617
|
-
- Meta Description: \`{{postSummary}}\`
|
|
618
|
-
- OG Image: \`{{mainImage}}\`
|
|
619
|
-
|
|
620
|
-
#### Authors (\`authors\`)
|
|
621
|
-
| Token | Use For |
|
|
622
|
-
|-------|---------|
|
|
623
|
-
| \`{{name}}\` | Meta Title |
|
|
624
|
-
| \`{{bio}}\` | Meta Description |
|
|
625
|
-
| \`{{picture}}\` | OG Image |
|
|
626
|
-
|
|
627
|
-
#### Custom Collections
|
|
628
|
-
All custom field tokens are available:
|
|
629
|
-
- \`{{name}}\` - Item name
|
|
630
|
-
- \`{{slug}}\` - URL slug
|
|
631
|
-
- \`{{customFieldSlug}}\` - Any custom field
|
|
632
|
-
|
|
633
|
-
Date tokens (automatically tracked):
|
|
634
|
-
- \`{{createdAt}}\` - When the item was created
|
|
635
|
-
- \`{{publishedAt}}\` - When the item was published
|
|
636
|
-
- \`{{updatedAt}}\` - When the item was last updated
|
|
310
|
+
**To see exact collections and fields for a specific project, use:**
|
|
311
|
+
\`\`\`
|
|
312
|
+
get_tenant_schema(projectId: "your-project-name-or-id")
|
|
313
|
+
\`\`\`
|
|
637
314
|
|
|
638
|
-
|
|
315
|
+
This will show you:
|
|
316
|
+
- All collections with their slugs
|
|
317
|
+
- All fields with their tokens, types, and descriptions
|
|
318
|
+
- Relation field targets
|
|
639
319
|
`;
|
|
640
320
|
}
|