fix(plugin-seo)!: data types plugin seo (#6979)

Changed the data to correctly match type generic being sent to the
generate functions. So now you can type your generateTitle etc.
functions like this

```ts
// before
const generateTitle: GenerateTitle = async <Page>({ doc, locale }) => {
  return `Website.com — ${doc?.title?.value}`
}


// curent
import type { GenerateDescription, GenerateTitle, GenerateURL } from '@payloadcms/plugin-seo/types'
import type { Page } from './payload-types'

const generateTitle: GenerateTitle<Page> = async ({ doc, locale }) => {
  return `Website.com — ${doc?.title}`
}

const generateDescription: GenerateDescription<Page> = async ({ doc, locale }) => {
  return doc?.excerpt || 'generated description'
}

const generateURL: GenerateURL<Page> = async ({ doc, locale }) => {
  return `https://yoursite.com/${locale ? locale + '/' : ''}${doc?.slug || ''}`
}
```

Breaking change because it was previously a FormState value.
This commit is contained in:
Paul
2024-06-28 12:58:36 -04:00
committed by GitHub
parent 75a3040029
commit 559c0646fa
7 changed files with 48 additions and 25 deletions

View File

@@ -5,10 +5,10 @@ import type { FieldType, FormFieldBase, Options } from '@payloadcms/ui'
import { import {
FieldLabel, FieldLabel,
TextareaInput, TextareaInput,
useAllFormFields,
useDocumentInfo, useDocumentInfo,
useField, useField,
useFieldProps, useFieldProps,
useForm,
useLocale, useLocale,
useTranslation, useTranslation,
} from '@payloadcms/ui' } from '@payloadcms/ui'
@@ -35,7 +35,7 @@ export const MetaDescription: React.FC<MetaDescriptionProps> = (props) => {
const { t } = useTranslation<PluginSEOTranslations, PluginSEOTranslationKeys>() const { t } = useTranslation<PluginSEOTranslations, PluginSEOTranslationKeys>()
const locale = useLocale() const locale = useLocale()
const [fields] = useAllFormFields() const { getData } = useForm()
const docInfo = useDocumentInfo() const docInfo = useDocumentInfo()
const field: FieldType<string> = useField({ const field: FieldType<string> = useField({
@@ -50,7 +50,7 @@ export const MetaDescription: React.FC<MetaDescriptionProps> = (props) => {
const genDescriptionResponse = await fetch('/api/plugin-seo/generate-description', { const genDescriptionResponse = await fetch('/api/plugin-seo/generate-description', {
body: JSON.stringify({ body: JSON.stringify({
...docInfo, ...docInfo,
doc: { ...fields }, doc: { ...getData() },
locale: typeof locale === 'object' ? locale?.code : locale, locale: typeof locale === 'object' ? locale?.code : locale,
} satisfies Parameters<GenerateDescription>[0]), } satisfies Parameters<GenerateDescription>[0]),
credentials: 'include', credentials: 'include',
@@ -63,7 +63,7 @@ export const MetaDescription: React.FC<MetaDescriptionProps> = (props) => {
const { result: generatedDescription } = await genDescriptionResponse.json() const { result: generatedDescription } = await genDescriptionResponse.json()
setValue(generatedDescription || '') setValue(generatedDescription || '')
}, [fields, setValue, hasGenerateDescriptionFn, locale, docInfo]) }, [hasGenerateDescriptionFn, docInfo, getData, locale, setValue])
return ( return (
<div <div

View File

@@ -5,10 +5,10 @@ import type { FieldType, Options, UploadInputProps } from '@payloadcms/ui'
import { import {
FieldLabel, FieldLabel,
UploadInput, UploadInput,
useAllFormFields,
useConfig, useConfig,
useDocumentInfo, useDocumentInfo,
useField, useField,
useForm,
useLocale, useLocale,
useTranslation, useTranslation,
} from '@payloadcms/ui' } from '@payloadcms/ui'
@@ -32,7 +32,7 @@ export const MetaImage: React.FC<MetaImageProps> = (props) => {
const { t } = useTranslation<PluginSEOTranslations, PluginSEOTranslationKeys>() const { t } = useTranslation<PluginSEOTranslations, PluginSEOTranslationKeys>()
const locale = useLocale() const locale = useLocale()
const [fields] = useAllFormFields() const { getData } = useForm()
const docInfo = useDocumentInfo() const docInfo = useDocumentInfo()
const { errorMessage, setValue, showError, value } = field const { errorMessage, setValue, showError, value } = field
@@ -43,7 +43,7 @@ export const MetaImage: React.FC<MetaImageProps> = (props) => {
const genImageResponse = await fetch('/api/plugin-seo/generate-image', { const genImageResponse = await fetch('/api/plugin-seo/generate-image', {
body: JSON.stringify({ body: JSON.stringify({
...docInfo, ...docInfo,
doc: { ...fields }, doc: { ...getData() },
locale: typeof locale === 'object' ? locale?.code : locale, locale: typeof locale === 'object' ? locale?.code : locale,
} satisfies Parameters<GenerateImage>[0]), } satisfies Parameters<GenerateImage>[0]),
credentials: 'include', credentials: 'include',
@@ -56,7 +56,7 @@ export const MetaImage: React.FC<MetaImageProps> = (props) => {
const { result: generatedImage } = await genImageResponse.json() const { result: generatedImage } = await genImageResponse.json()
setValue(generatedImage || '') setValue(generatedImage || '')
}, [fields, setValue, hasGenerateImageFn, locale, docInfo]) }, [hasGenerateImageFn, docInfo, getData, locale, setValue])
const hasImage = Boolean(value) const hasImage = Boolean(value)

View File

@@ -5,10 +5,10 @@ import type { FieldType, FormFieldBase, Options } from '@payloadcms/ui'
import { import {
FieldLabel, FieldLabel,
TextInput, TextInput,
useAllFormFields,
useDocumentInfo, useDocumentInfo,
useField, useField,
useFieldProps, useFieldProps,
useForm,
useLocale, useLocale,
useTranslation, useTranslation,
} from '@payloadcms/ui' } from '@payloadcms/ui'
@@ -39,7 +39,7 @@ export const MetaTitle: React.FC<MetaTitleProps> = (props) => {
} as Options) } as Options)
const locale = useLocale() const locale = useLocale()
const [fields] = useAllFormFields() const { getData } = useForm()
const docInfo = useDocumentInfo() const docInfo = useDocumentInfo()
const { errorMessage, setValue, showError, value } = field const { errorMessage, setValue, showError, value } = field
@@ -50,7 +50,7 @@ export const MetaTitle: React.FC<MetaTitleProps> = (props) => {
const genTitleResponse = await fetch('/api/plugin-seo/generate-title', { const genTitleResponse = await fetch('/api/plugin-seo/generate-title', {
body: JSON.stringify({ body: JSON.stringify({
...docInfo, ...docInfo,
doc: { ...fields }, doc: { ...getData() },
locale: typeof locale === 'object' ? locale?.code : locale, locale: typeof locale === 'object' ? locale?.code : locale,
} satisfies Parameters<GenerateTitle>[0]), } satisfies Parameters<GenerateTitle>[0]),
credentials: 'include', credentials: 'include',
@@ -63,7 +63,7 @@ export const MetaTitle: React.FC<MetaTitleProps> = (props) => {
const { result: generatedTitle } = await genTitleResponse.json() const { result: generatedTitle } = await genTitleResponse.json()
setValue(generatedTitle || '') setValue(generatedTitle || '')
}, [fields, setValue, hasGenerateTitleFn, locale, docInfo]) }, [hasGenerateTitleFn, docInfo, getData, locale, setValue])
return ( return (
<div <div

View File

@@ -1,22 +1,22 @@
import type { DocumentInfoContext } from '@payloadcms/ui' import type { DocumentInfoContext } from '@payloadcms/ui'
import type { Field, TextField, TextareaField, UploadField } from 'payload' import type { Field, TextField, TextareaField, UploadField } from 'payload'
export type GenerateTitle = <T = any>( export type GenerateTitle<T = any> = (
args: DocumentInfoContext & { doc: T; locale?: string }, args: DocumentInfoContext & { doc: T; locale?: string },
) => Promise<string> | string ) => Promise<string> | string
export type GenerateDescription = <T = any>( export type GenerateDescription<T = any> = (
args: DocumentInfoContext & { args: DocumentInfoContext & {
doc: T doc: T
locale?: string locale?: string
}, },
) => Promise<string> | string ) => Promise<string> | string
export type GenerateImage = <T = any>( export type GenerateImage<T = any> = (
args: DocumentInfoContext & { doc: T; locale?: string }, args: DocumentInfoContext & { doc: T; locale?: string },
) => Promise<string> | string ) => Promise<string> | string
export type GenerateURL = <T = any>( export type GenerateURL<T = any> = (
args: DocumentInfoContext & { doc: T; locale?: string }, args: DocumentInfoContext & { doc: T; locale?: string },
) => Promise<string> | string ) => Promise<string> | string

View File

@@ -2,7 +2,13 @@
import type { FormField, UIField } from 'payload' import type { FormField, UIField } from 'payload'
import { useAllFormFields, useDocumentInfo, useLocale, useTranslation } from '@payloadcms/ui' import {
useAllFormFields,
useDocumentInfo,
useForm,
useLocale,
useTranslation,
} from '@payloadcms/ui'
import React, { useEffect, useState } from 'react' import React, { useEffect, useState } from 'react'
import type { PluginSEOTranslationKeys, PluginSEOTranslations } from '../translations/index.js' import type { PluginSEOTranslationKeys, PluginSEOTranslations } from '../translations/index.js'
@@ -17,6 +23,7 @@ export const Preview: React.FC<PreviewProps> = ({ hasGenerateURLFn }) => {
const locale = useLocale() const locale = useLocale()
const [fields] = useAllFormFields() const [fields] = useAllFormFields()
const { getData } = useForm()
const docInfo = useDocumentInfo() const docInfo = useDocumentInfo()
const { const {
@@ -31,7 +38,7 @@ export const Preview: React.FC<PreviewProps> = ({ hasGenerateURLFn }) => {
const genURLResponse = await fetch('/api/plugin-seo/generate-url', { const genURLResponse = await fetch('/api/plugin-seo/generate-url', {
body: JSON.stringify({ body: JSON.stringify({
...docInfo, ...docInfo,
doc: { ...fields }, doc: { ...getData() },
locale: typeof locale === 'object' ? locale?.code : locale, locale: typeof locale === 'object' ? locale?.code : locale,
} satisfies Parameters<GenerateURL>[0]), } satisfies Parameters<GenerateURL>[0]),
credentials: 'include', credentials: 'include',
@@ -49,7 +56,7 @@ export const Preview: React.FC<PreviewProps> = ({ hasGenerateURLFn }) => {
if (hasGenerateURLFn && !href) { if (hasGenerateURLFn && !href) {
void getHref() void getHref()
} }
}, [fields, href, locale, docInfo, hasGenerateURLFn]) }, [fields, href, locale, docInfo, hasGenerateURLFn, getData])
return ( return (
<div> <div>

View File

@@ -2,6 +2,9 @@ import { fileURLToPath } from 'node:url'
import path from 'path' import path from 'path'
const filename = fileURLToPath(import.meta.url) const filename = fileURLToPath(import.meta.url)
const dirname = path.dirname(filename) const dirname = path.dirname(filename)
import type { GenerateDescription, GenerateTitle, GenerateURL } from '@payloadcms/plugin-seo/types'
import type { Page } from 'plugin-seo/payload-types.js'
import { seoPlugin } from '@payloadcms/plugin-seo' import { seoPlugin } from '@payloadcms/plugin-seo'
import { en } from '@payloadcms/translations/languages/en' import { en } from '@payloadcms/translations/languages/en'
import { es } from '@payloadcms/translations/languages/es' import { es } from '@payloadcms/translations/languages/es'
@@ -13,6 +16,18 @@ import { Pages } from './collections/Pages.js'
import { Users } from './collections/Users.js' import { Users } from './collections/Users.js'
import { seed } from './seed/index.js' import { seed } from './seed/index.js'
const generateTitle: GenerateTitle<Page> = ({ doc }) => {
return `Website.com — ${doc?.title}`
}
const generateDescription: GenerateDescription<Page> = ({ doc }) => {
return doc?.excerpt || 'generated description'
}
const generateURL: GenerateURL<Page> = ({ doc, locale }) => {
return `https://yoursite.com/${locale ? locale + '/' : ''}${doc?.slug || ''}`
}
export default buildConfigWithDefaults({ export default buildConfigWithDefaults({
collections: [Users, Pages, Media], collections: [Users, Pages, Media],
i18n: { i18n: {
@@ -59,10 +74,9 @@ export default buildConfigWithDefaults({
label: 'og:title', label: 'og:title',
}, },
], ],
generateDescription: ({ doc }: any) => doc?.excerpt?.value || 'generated description', generateDescription,
generateTitle: (data: any) => `Website.com — ${data?.doc?.title?.value}`, generateTitle,
generateURL: ({ doc, locale }: any) => generateURL,
`https://yoursite.com/${locale ? locale + '/' : ''}${doc?.slug?.value || ''}`,
tabbedUI: true, tabbedUI: true,
uploadsCollection: 'media', uploadsCollection: 'media',
}), }),

View File

@@ -46,9 +46,11 @@ export interface Page {
title: string; title: string;
excerpt?: string | null; excerpt?: string | null;
slug: string; slug: string;
meta?: { meta: {
title?: string | null; title: string;
description?: string | null; description?: string | null;
image?: string | Media | null;
ogTitle?: string | null;
}; };
updatedAt: string; updatedAt: string;
createdAt: string; createdAt: string;