Skip to content

Commit ac97d39

Browse files
authored
feat(content): add defineRobotsSchema() composable (#283)
1 parent cb9c152 commit ac97d39

File tree

11 files changed

+146
-10
lines changed

11 files changed

+146
-10
lines changed

docs/content/3.advanced/3.content.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,22 +9,22 @@ Nuxt Robots comes with an integration for Nuxt Content that allows you to config
99

1010
## Setup Nuxt Content v3
1111

12-
In Nuxt Content v3 we need to use the `asRobotsCollection()`{lang="ts"} function to augment any collections
13-
to be able to use the `robots` frontmatter key.
12+
Add `defineRobotsSchema()`{lang="ts"} to your collection's schema to enable the `robots` frontmatter key.
1413

1514
```ts [content.config.ts]
1615
import { defineCollection, defineContentConfig } from '@nuxt/content'
17-
import { asRobotsCollection } from '@nuxtjs/robots/content'
16+
import { defineRobotsSchema } from '@nuxtjs/robots/content'
17+
import { z } from 'zod'
1818

1919
export default defineContentConfig({
2020
collections: {
21-
content: defineCollection(
22-
// adds the robots frontmatter key to the collection
23-
asRobotsCollection({
24-
type: 'page',
25-
source: '**/*.md',
21+
content: defineCollection({
22+
type: 'page',
23+
source: '**/*.md',
24+
schema: z.object({
25+
robots: defineRobotsSchema(),
2626
}),
27-
),
27+
}),
2828
},
2929
})
3030
```

src/content.ts

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,49 @@
11
import type { Collection } from '@nuxt/content'
22
import { z } from 'zod'
33

4+
const robotsFieldSchema = z.union([z.string(), z.boolean()]).optional()
5+
6+
function withEditorHidden<T extends z.ZodTypeAny>(s: T): T {
7+
// .editor() is patched onto ZodType by @nuxt/content at runtime
8+
if (typeof (s as any).editor === 'function')
9+
return (s as any).editor({ hidden: true })
10+
return s
11+
}
12+
13+
export interface DefineRobotsSchemaOptions {
14+
/**
15+
* Pass the `z` instance from `@nuxt/content` to ensure `.editor({ hidden: true })` works
16+
* across Zod versions. When omitted, the bundled `z` is used (`.editor()` applied if available).
17+
*/
18+
z?: typeof z
19+
}
20+
21+
/**
22+
* Define the robots schema field for a Nuxt Content collection.
23+
*
24+
* @example
25+
* defineCollection({
26+
* type: 'page',
27+
* source: '**',
28+
* schema: z.object({
29+
* robots: defineRobotsSchema()
30+
* })
31+
* })
32+
*/
33+
export function defineRobotsSchema(options?: DefineRobotsSchemaOptions) {
34+
const _z = options?.z ?? z
35+
const s = _z.union([_z.string(), _z.boolean()]).optional()
36+
return withEditorHidden(s)
37+
}
38+
39+
// Legacy schema export (wraps entire collection)
440
export const schema = z.object({
5-
robots: z.union([z.string(), z.boolean()]).optional(),
41+
robots: withEditorHidden(robotsFieldSchema),
642
})
743

44+
/** @deprecated Use `defineRobotsSchema()` in your collection schema instead. See https://nuxtseo.com/robots/advanced/content */
845
export function asRobotsCollection<T>(collection: Collection<T>): Collection<T> {
46+
console.warn('[robots] `asRobotsCollection()` is deprecated. Use `defineRobotsSchema()` in your collection schema instead. See https://nuxtseo.com/robots/advanced/content')
947
if (collection.type === 'page') {
1048
// @ts-expect-error untyped
1149
collection.schema = collection.schema ? schema.extend(collection.schema.shape) : schema
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { createResolver } from '@nuxt/kit'
2+
import { $fetch, setup } from '@nuxt/test-utils'
3+
import { describe, expect, it } from 'vitest'
4+
5+
const { resolve } = createResolver(import.meta.url)
6+
7+
await setup({
8+
rootDir: resolve('../fixtures/content-v3-define-schema'),
9+
})
10+
11+
describe('nuxt/content v3 defineRobotsSchema', () => {
12+
it('renders robots meta from content frontmatter', async () => {
13+
const barHtml = await $fetch('/bar')
14+
expect(String(barHtml).match(/<meta name="robots" content="([^"]+)">/)).toMatchInlineSnapshot(`
15+
[
16+
"<meta name="robots" content="test">",
17+
"test",
18+
]
19+
`)
20+
21+
const fooHtml = await $fetch('/foo')
22+
expect(String(fooHtml).match(/<meta name="robots" content="([^"]+)">/)).toMatchInlineSnapshot(`
23+
[
24+
"<meta name="robots" content="noindex, nofollow">",
25+
"noindex, nofollow",
26+
]
27+
`)
28+
}, 60000)
29+
})
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
imports.autoImport=true
2+
typescript.includeWorkspace=true
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
<template>
2+
<NuxtPage />
3+
</template>
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { defineCollection, defineContentConfig } from '@nuxt/content'
2+
import { defineRobotsSchema } from '../../../src/content'
3+
import { z } from 'zod'
4+
5+
export default defineContentConfig({
6+
collections: {
7+
content: defineCollection({
8+
type: 'page',
9+
source: '**/*.md',
10+
schema: z.object({
11+
date: z.string().optional(),
12+
robots: defineRobotsSchema(),
13+
}),
14+
}),
15+
},
16+
})
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
path: /bar
3+
robots: "test"
4+
---
5+
6+
# bar
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
path: '/foo'
3+
robots: false
4+
date: 2026-10-10
5+
---
6+
7+
# foo
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
---
3+
4+
# index
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import NuxtRobots from '../../../src/module'
2+
3+
export default defineNuxtConfig({
4+
modules: [
5+
NuxtRobots,
6+
'@nuxt/content',
7+
],
8+
9+
site: {
10+
url: 'https://nuxtseo.com',
11+
},
12+
compatibilityDate: '2024-12-06',
13+
})

0 commit comments

Comments
 (0)