init commit for iPAL-kit plugin
This commit is contained in:
+95
@@ -0,0 +1,95 @@
|
||||
# seo
|
||||
|
||||
Wpina `@payloadcms/plugin-seo` (pola meta w kolekcjach) i dodaje warstwę
|
||||
logiki: składanie tytułów, budowanie `Metadata` dla Next.js z canonical i
|
||||
hreflang, auto-fill pustych meta z treści dokumentu.
|
||||
|
||||
## Zależność
|
||||
|
||||
Dodaj do `dependencies` (pin do wersji payload):
|
||||
|
||||
```json
|
||||
"dependencies": { "@payloadcms/plugin-seo": "3.84.1" }
|
||||
```
|
||||
|
||||
## Config (payload.config.ts)
|
||||
|
||||
```ts
|
||||
ipalKit({
|
||||
seo: {
|
||||
collections: ['pages', 'posts'], // które kolekcje dostają meta
|
||||
// generateTitle: ({ doc }) => `${doc.title}`, // opcjonalne
|
||||
// generateDescription: ({ doc }) => doc.excerpt ?? '',
|
||||
// fields: [...], // extra pola w grupie SEO
|
||||
// autoFill: { title: 'title', description: 'excerpt' }, // mapowanie auto-fill
|
||||
// autoFill: false, // wyłącz auto-fill
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
Dodaje tab **SEO** (title, description, image) do wskazanych kolekcji.
|
||||
Auto-fill: hook `beforeChange` wypełnia puste `meta.title` z pola dokumentu
|
||||
(domyślnie `title`). Nigdy nie nadpisuje tego, co edytor wpisał ręcznie.
|
||||
|
||||
## Front — generateMetadata (factory)
|
||||
|
||||
Najprościej: factory redukuje boilerplate. Klient podaje resolvery (bo zna
|
||||
swoje kolekcje/routing), plugin składa metadata.
|
||||
|
||||
```ts
|
||||
// app/(frontend)/[locale]/[[...segments]]/page.tsx
|
||||
import { createMetadataGenerator } from 'ipal-kit'
|
||||
import { getSiteSettings } from 'ipal-kit'
|
||||
|
||||
const gen = createMetadataGenerator({
|
||||
config: i18nConfig,
|
||||
baseUrl: process.env.NEXT_PUBLIC_SERVER_URL,
|
||||
resolveDocument: async ({ payload, params, locale }) => {
|
||||
const slug = /* z params */ ''
|
||||
const res = await payload.find({
|
||||
collection: 'pages',
|
||||
where: { slug: { equals: slug } },
|
||||
locale: 'all', depth: 1, limit: 1,
|
||||
})
|
||||
return res.docs[0] ?? null // musi mieć .meta i .slug (locale:'all')
|
||||
},
|
||||
resolveSiteName: async ({ payload, locale }) =>
|
||||
(await getSiteSettings(payload, { locale })).siteName ?? null,
|
||||
})
|
||||
|
||||
export async function generateMetadata({ params }) {
|
||||
const payload = await getPayload({ config })
|
||||
const { locale } = await params
|
||||
return gen({ payload, params: await params, locale })
|
||||
}
|
||||
```
|
||||
|
||||
## Front — niżej: buildMetadata bezpośrednio
|
||||
|
||||
Jeśli chcesz pełną kontrolę zamiast factory:
|
||||
|
||||
```ts
|
||||
import { buildMetadata, getLocalizedSlugs } from 'ipal-kit'
|
||||
|
||||
const doc = await payload.findByID({ collection: 'pages', id, locale: 'all', depth: 1 })
|
||||
|
||||
return buildMetadata({
|
||||
meta: doc.meta, // z plugin-seo
|
||||
siteName: settings.siteName,
|
||||
imageUrl: /* url OG image */,
|
||||
locale: 'pl',
|
||||
slugs: getLocalizedSlugs({ slugField: doc.slug, config }),
|
||||
config,
|
||||
baseUrl: 'https://example.com',
|
||||
})
|
||||
// → { title, description, openGraph, alternates: { canonical, languages } }
|
||||
```
|
||||
|
||||
## Pomocnicze
|
||||
|
||||
```ts
|
||||
import { composeTitle, buildHreflangAlternates } from 'ipal-kit'
|
||||
|
||||
composeTitle({ pageTitle: 'O nas', siteName: 'Acme' }) // 'O nas | Acme'
|
||||
buildHreflangAlternates({ slugs, config, baseUrl }) // { pl: '...', en: '...' }
|
||||
```
|
||||
Reference in New Issue
Block a user