Files
ipal-kit/docs/hooks.md
T

4.5 KiB

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, seo.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.

// 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.

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.

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).

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).

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:

// 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:

hooks: {
  beforeOperation: [normalizeFilenameHook],   // czyste nazwy
  afterChange: [afterChange],                  // revalidate
  afterDelete: [afterDelete],
}

Typowa Pages:

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).