Update robots meta and add verification rendering (#45409)
Follow up for: #45237 * Adding more fields for robots meta, most related to googlebot * Add `me` and `yandex` field and render for verification field
This commit is contained in:
parent
d3a9f5a54a
commit
41e2613aca
8 changed files with 119 additions and 23 deletions
|
@ -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 ? (
|
||||
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||
) : null}
|
||||
{title ? (
|
||||
<meta name="apple-mobile-web-app-title" content={title} />
|
||||
) : null}
|
||||
<Meta name="apple-mobile-web-app-title" content={title} />
|
||||
{startupImage
|
||||
? startupImage.map((image, index) => (
|
||||
<link
|
||||
|
@ -122,3 +120,31 @@ export function AppleWebAppMeta({
|
|||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export function VerificationMeta({
|
||||
verification,
|
||||
}: {
|
||||
verification: ResolvedMetadata['verification']
|
||||
}) {
|
||||
if (!verification) return null
|
||||
|
||||
return (
|
||||
<>
|
||||
<MultiMeta
|
||||
namePrefix="google-site-verification"
|
||||
contents={verification.google}
|
||||
/>
|
||||
<MultiMeta namePrefix="y_key" contents={verification.yahoo} />
|
||||
<MultiMeta
|
||||
namePrefix="yandex-verification"
|
||||
contents={verification.yandex}
|
||||
/>
|
||||
<MultiMeta namePrefix="me" contents={verification.me} />
|
||||
{verification.other
|
||||
? Object.entries(verification.other).map(([key, value], index) => (
|
||||
<MultiMeta key={key + index} namePrefix={key} contents={value} />
|
||||
))
|
||||
: null}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -91,6 +91,7 @@ export function MultiMeta({
|
|||
} else {
|
||||
return (
|
||||
<ExtendMeta
|
||||
key={keyPrefix + '_' + index}
|
||||
namePrefix={namePrefix}
|
||||
propertyPrefix={propertyPrefix}
|
||||
content={content}
|
||||
|
|
|
@ -6,6 +6,7 @@ import {
|
|||
FormatDetectionMeta,
|
||||
ItunesMeta,
|
||||
BasicMetadata,
|
||||
VerificationMeta,
|
||||
} from './generate/basic'
|
||||
import { AlternatesMetadata } from './generate/alternate'
|
||||
import {
|
||||
|
@ -27,6 +28,7 @@ export async function Metadata({ metadata }: { metadata: any }) {
|
|||
<AlternatesMetadata alternates={resolved.alternates} />
|
||||
<ItunesMeta itunes={resolved.itunes} />
|
||||
<FormatDetectionMeta formatDetection={resolved.formatDetection} />
|
||||
<VerificationMeta verification={resolved.verification} />
|
||||
<AppleWebAppMeta appleWebApp={resolved.appleWebApp} />
|
||||
<OpenGraphMetadata openGraph={resolved.openGraph} />
|
||||
<TwitterMetadata twitter={resolved.twitter} />
|
||||
|
|
|
@ -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<string, (string | number)[]> | 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(', ')
|
||||
}
|
||||
|
|
|
@ -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)[]
|
||||
}
|
||||
|
|
|
@ -12,6 +12,10 @@ export const metadata = {
|
|||
index: true,
|
||||
follow: false,
|
||||
noimageindex: true,
|
||||
|
||||
'max-video-preview': 'standard',
|
||||
'max-image-preview': -1,
|
||||
'max-snippet': -1,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
14
test/e2e/app-dir/metadata/app/verification/page.tsx
Normal file
14
test/e2e/app-dir/metadata/app/verification/page.tsx
Normal file
|
@ -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'],
|
||||
},
|
||||
},
|
||||
}
|
|
@ -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(
|
||||
|
|
Loading…
Reference in a new issue