diff --git a/packages/next/src/lib/metadata/generate/basic.tsx b/packages/next/src/lib/metadata/generate/basic.tsx
index b64e6a5e74..d2b799ccc8 100644
--- a/packages/next/src/lib/metadata/generate/basic.tsx
+++ b/packages/next/src/lib/metadata/generate/basic.tsx
@@ -1,7 +1,7 @@
import type { ResolvedMetadata } from '../types/metadata-interface'
import React from 'react'
-import { Meta } from './meta'
+import { Meta, MultiMeta } from './meta'
export function BasicMetadata({ metadata }: { metadata: ResolvedMetadata }) {
return (
@@ -100,9 +100,7 @@ export function AppleWebAppMeta({
{capable ? (
) : null}
- {title ? (
-
- ) : null}
+
{startupImage
? startupImage.map((image, index) => (
)
}
+
+export function VerificationMeta({
+ verification,
+}: {
+ verification: ResolvedMetadata['verification']
+}) {
+ if (!verification) return null
+
+ return (
+ <>
+
+
+
+
+ {verification.other
+ ? Object.entries(verification.other).map(([key, value], index) => (
+
+ ))
+ : null}
+ >
+ )
+}
diff --git a/packages/next/src/lib/metadata/generate/meta.tsx b/packages/next/src/lib/metadata/generate/meta.tsx
index 90a6fb00f3..a0e6a12677 100644
--- a/packages/next/src/lib/metadata/generate/meta.tsx
+++ b/packages/next/src/lib/metadata/generate/meta.tsx
@@ -91,6 +91,7 @@ export function MultiMeta({
} else {
return (
+
diff --git a/packages/next/src/lib/metadata/resolve-metadata.ts b/packages/next/src/lib/metadata/resolve-metadata.ts
index 3163435efc..e3f77f4664 100644
--- a/packages/next/src/lib/metadata/resolve-metadata.ts
+++ b/packages/next/src/lib/metadata/resolve-metadata.ts
@@ -10,6 +10,7 @@ import type {
Icon,
IconDescriptor,
Icons,
+ ResolvedVerification,
} from './types/metadata-types'
import { createDefaultMetadata } from './default-metadata'
import { resolveOpenGraph } from './resolve-opengraph'
@@ -76,22 +77,26 @@ const resolveViewport: FieldResolver<'viewport'> = (viewport) => {
return resolved
}
+const VerificationKeys = ['google', 'yahoo', 'yandex', 'me', 'other'] as const
const resolveVerification: FieldResolver<'verification'> = (verification) => {
- const google = resolveAsArrayOrUndefined(verification?.google)
- const yahoo = resolveAsArrayOrUndefined(verification?.yahoo)
- let other: Record | undefined
- if (verification?.other) {
- other = {}
- for (const key in verification.other) {
- const value = resolveAsArrayOrUndefined(verification.other[key])
- if (value) other[key] = value
+ if (!verification) return null
+ const res = {} as ResolvedVerification
+
+ for (const key of VerificationKeys) {
+ const value = verification[key]
+ if (value) {
+ if (key === 'other') {
+ res.other = {}
+ for (const otherKey in verification.other) {
+ const otherValue = resolveAsArrayOrUndefined(
+ verification.other[otherKey]
+ )
+ if (otherValue) res.other[otherKey] = otherValue
+ }
+ } else res[key] = resolveAsArrayOrUndefined(value) as (string | number)[]
}
}
- return {
- google,
- yahoo,
- other,
- }
+ return res
}
function isStringOrURL(icon: any): icon is string | URL {
@@ -203,23 +208,39 @@ const resolveAppLinks: FieldResolver<'appLinks'> = (appLinks) => {
return appLinks as ResolvedMetadata['appLinks']
}
+const robotsKeys = [
+ 'noarchive',
+ 'nosnippet',
+ 'noimageindex',
+ 'nocache',
+ 'notranslate',
+ 'indexifembedded',
+ 'nositelinkssearchbox',
+ 'unavailable_after',
+ 'max-video-preview',
+ 'max-image-preview',
+ 'max-snippet',
+] as const
const resolveRobotsValue: (robots: Metadata['robots']) => string | null = (
robots
) => {
if (!robots) return null
if (typeof robots === 'string') return robots
- const values = []
+ const values: string[] = []
if (robots.index) values.push('index')
else if (typeof robots.index === 'boolean') values.push('noindex')
if (robots.follow) values.push('follow')
else if (typeof robots.follow === 'boolean') values.push('nofollow')
- if (robots.noarchive) values.push('noarchive')
- if (robots.nosnippet) values.push('nosnippet')
- if (robots.noimageindex) values.push('noimageindex')
- if (robots.nocache) values.push('nocache')
+
+ for (const key of robotsKeys) {
+ const value = robots[key]
+ if (typeof value !== 'undefined' && value !== false) {
+ values.push(typeof value === 'boolean' ? key : `${key}:${value}`)
+ }
+ }
return values.join(', ')
}
diff --git a/packages/next/src/lib/metadata/types/metadata-types.ts b/packages/next/src/lib/metadata/types/metadata-types.ts
index b098018f0a..71fc3f2f72 100644
--- a/packages/next/src/lib/metadata/types/metadata-types.ts
+++ b/packages/next/src/lib/metadata/types/metadata-types.ts
@@ -59,6 +59,13 @@ type RobotsInfo = {
nosnippet?: boolean
noimageindex?: boolean
nocache?: boolean
+ notranslate?: boolean
+ indexifembedded?: boolean
+ nositelinkssearchbox?: boolean
+ unavailable_after?: string
+ 'max-video-preview'?: number | string
+ 'max-image-preview'?: 'none' | 'standard' | 'large'
+ 'max-snippet'?: number
}
export type Robots = RobotsInfo & {
// if you want to specify an alternate robots just for google
@@ -93,6 +100,8 @@ export type Icons = {
export type Verification = {
google?: null | string | number | (string | number)[]
yahoo?: null | string | number | (string | number)[]
+ yandex?: null | string | number | (string | number)[]
+ me?: null | string | number | (string | number)[]
// if you ad-hoc additional verification
other?: {
[name: string]: string | number | (string | number)[]
@@ -102,6 +111,8 @@ export type Verification = {
export type ResolvedVerification = {
google?: null | (string | number)[]
yahoo?: null | (string | number)[]
+ yandex?: null | (string | number)[]
+ me?: null | (string | number)[]
other?: {
[name: string]: (string | number)[]
}
diff --git a/test/e2e/app-dir/metadata/app/robots/page.tsx b/test/e2e/app-dir/metadata/app/robots/page.tsx
index 14170a7322..00ccf80b85 100644
--- a/test/e2e/app-dir/metadata/app/robots/page.tsx
+++ b/test/e2e/app-dir/metadata/app/robots/page.tsx
@@ -12,6 +12,10 @@ export const metadata = {
index: true,
follow: false,
noimageindex: true,
+
+ 'max-video-preview': 'standard',
+ 'max-image-preview': -1,
+ 'max-snippet': -1,
},
},
}
diff --git a/test/e2e/app-dir/metadata/app/verification/page.tsx b/test/e2e/app-dir/metadata/app/verification/page.tsx
new file mode 100644
index 0000000000..3a39a2e97f
--- /dev/null
+++ b/test/e2e/app-dir/metadata/app/verification/page.tsx
@@ -0,0 +1,14 @@
+export default function page() {
+ return 'verification'
+}
+
+export const metadata = {
+ verification: {
+ google: 'google',
+ yandex: 'yandex',
+ yahoo: 'yahoo',
+ other: {
+ me: ['my-email', 'my-link'],
+ },
+ },
+}
diff --git a/test/e2e/app-dir/metadata/metadata.test.ts b/test/e2e/app-dir/metadata/metadata.test.ts
index 716f6e6ef7..1106fdfe73 100644
--- a/test/e2e/app-dir/metadata/metadata.test.ts
+++ b/test/e2e/app-dir/metadata/metadata.test.ts
@@ -235,10 +235,27 @@ createNextDescribe(
await checkMetaNameContentPair(
browser,
'googlebot',
- 'index, nofollow, noimageindex'
+ 'index, nofollow, noimageindex, max-video-preview:standard, max-image-preview:-1, max-snippet:-1'
)
})
+ it('should support verification tags', async () => {
+ const browser = await next.browser('/verification')
+
+ await checkMetaNameContentPair(
+ browser,
+ 'google-site-verification',
+ 'google'
+ )
+ await checkMetaNameContentPair(browser, 'y_key', 'yahoo')
+ await checkMetaNameContentPair(
+ browser,
+ 'yandex-verification',
+ 'yandex'
+ )
+ await checkMetaNameContentPair(browser, 'me', ['my-email', 'my-link'])
+ })
+
it('should support appLinks tags', async () => {
const browser = await next.browser('/app-links')
await checkMetaPropertyContentPair(