Files
ipal-kit/docs/hooks.md
T

150 lines
4.5 KiB
Markdown

# Hooki pluginu — automatyzacja tworzenia stron
Plugin dostarcza hooki, które zdejmują z projektów powtarzalną robotę. Wpinasz je
w kolekcje; działają automatycznie. Wszystkie gotowe do użycia (import z pluginu).
Powiązane: [pages.md](./pages.md), [seo.md](./seo.md), [wymagania-prawne.md](./wymagania-prawne.md).
---
## buildRevalidateHook — ISR odświeżany po zapisie (NAJWAŻNIEJSZY)
Bez tego ISR ma haczyk: redaktor zapisuje stronę i CZEKA na revalidate (do
godziny). Z tym — zapisuje i OD RAZU widzi zmianę. To warunek, żeby ISR był
używalny dla CMS.
```ts
// kolekcja Pages — z pliku projektu, który MOŻE importować next/cache
import { revalidatePath } from 'next/cache'
import { buildRevalidateHook } from '@intecion/ipal-kit'
import { i18nConfig } from '@/i18n.config'
const { afterChange, afterDelete } = buildRevalidateHook({
revalidatePath, // wstrzykiwany — plugin NIE importuje next/cache
config: i18nConfig,
})
export const Pages: CollectionConfig = {
slug: 'pages',
hooks: { afterChange: [afterChange], afterDelete: [afterDelete] },
// ...
}
```
**Dlaczego revalidatePath wstrzykiwany:** plugin nie importuje `next/cache` (to
by wywaliło Payload przy generate:importmap / czystym Node). Projekt podaje.
Obsługuje: wszystkie języki, root (home), zmianę slug (rewaliduje stary I nowy
path — stary URL nie serwuje starej treści), delete.
---
## setPublishedAtHook — auto-data publikacji
Ustawia `publishedAt` na teraz przy pierwszej publikacji (jeśli puste). Redaktor
nie wpisuje daty ręcznie; data jest dokładna dla Article JSON-LD i sitemap.
```ts
import { setPublishedAtHook } from '@intecion/ipal-kit'
// kolekcja z draftami (blog, artykuły):
hooks: { beforeChange: [setPublishedAtHook] }
```
Ustawia tylko przy przejściu na published; nie nadpisuje istniejącej daty
(redaktor może backdatować ręcznie).
---
## buildPreventDeleteSystemPage — ochrona stron systemowych
Blokuje usunięcie strony przypisanej do roli (homepage, privacyPolicy,
cookiePolicy, termsOfService). Redaktor nie usunie przypadkiem polityki
prywatności albo strony głównej → nie rozbije routingu i linków compliance.
```ts
import { buildPreventDeleteSystemPage } from '@intecion/ipal-kit'
hooks: { beforeDelete: [buildPreventDeleteSystemPage({ settingsSlug: 'site-settings' })] }
```
Żeby usunąć — najpierw odłącz rolę w Site Settings (świadoma decyzja).
---
## buildValidateUniqueRole — jedna strona = jedna rola
Zapobiega przypisaniu tej samej strony do dwóch ról systemowych (np. homepage I
privacyPolicy naraz → niejednoznaczny routing).
```ts
import { buildValidateUniqueRole } from '@intecion/ipal-kit'
// na polu roli w SiteSettings:
{
name: 'privacyPolicy',
type: 'relationship',
relationTo: 'pages',
hooks: { beforeValidate: [buildValidateUniqueRole({
siblingFields: ['homepage', 'cookiePolicy', 'termsOfService'],
})] },
}
```
---
## trackSlugHistoryHook — auto-redirect 301 przy zmianie slug
Gdy slug się zmienia, zapisuje STARY slug do pola `slugHistory`. Projekt czyta to
i robi 301 ze starego URL na nowy → zmiana adresu nie daje 404 (realna strata SEO
z audytu).
```ts
import { trackSlugHistoryHook } from '@intecion/ipal-kit'
export const Pages: CollectionConfig = {
fields: [
// ...
{ name: 'slugHistory', type: 'array', admin: { readOnly: true },
fields: [{ name: 'slug', type: 'text' }] },
],
hooks: { beforeChange: [trackSlugHistoryHook] },
}
```
Projekt w resolveRoute / sprawdzeniu redirectów: jeśli żądany slug jest w
slugHistory jakiejś strony → 301 na jej aktualny slug. Przykład:
```ts
// w page.tsx, gdy resolveRoute nie znajdzie strony po slug:
const byHistory = await payload.find({
collection: 'pages',
where: { 'slugHistory.slug': { equals: requestedSlug } },
limit: 1,
})
if (byHistory.docs[0]) {
redirect(`/${locale}/${byHistory.docs[0].slug}`) // 301 na aktualny
}
```
---
## KOLEJNOŚĆ hooków (ważne)
W jednej kolekcji hooki tej samej fazy uruchamiają się po kolei. Typowa Media:
```ts
hooks: {
beforeOperation: [normalizeFilenameHook], // czyste nazwy
afterChange: [afterChange], // revalidate
afterDelete: [afterDelete],
}
```
Typowa Pages:
```ts
hooks: {
beforeChange: [setPublishedAtHook, trackSlugHistoryHook],
beforeDelete: [buildPreventDeleteSystemPage(...)],
afterChange: [afterChange], // revalidate
afterDelete: [afterDelete],
}
```
Które hooki wpiąć zależy od kolekcji — nie każda potrzebuje wszystkich (blog:
setPublishedAt; wszystkie z URL: revalidate + slugHistory; Pages: + preventDelete).