Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 56 additions & 27 deletions pages/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,13 @@

The Payload Pages plugin simplifies website building by adding essential fields to your collections. These fields enable hierarchical page structures and dynamic URL management.

## Requirements

- Payload CMS `^3.65.0` (required for type-safe `custom` field support via module augmentation)

## Setup

First, add the plugin to your payload config. The `generatePageURL` function is required and must provide a function that returns the full URL to the frontend page.
First, add the plugin to your payload config. The `generatePageURL` function is required and must provide a function that returns the full URL to the frontend page.

```ts
import { payloadPagesPlugin } from '@jhb.software/payload-pages-plugin'
Expand All @@ -23,7 +27,9 @@ plugins: [
]
```

Next, create a page collections using the `PageCollectionConfig` type. This type extends Payload's `CollectionConfig` type with a `page` field that contains configurations for the page collection. The `page` field must be specified as follows:
Next, create page collections using Payload's standard `CollectionConfig` with the `custom.pagesPlugin.page` property. The plugin extends Payload's `CollectionCustom` interface via module augmentation, providing full type-safety for the page configuration.

The `custom.pagesPlugin.page` field must be specified as follows:

- `parent.collection`: The slug of the collection that will be used as the parent of the current collection.
- `parent.name`: The name of the field on the parent collection that will be used to relate to the current collection.
Expand All @@ -35,19 +41,23 @@ Next, create a page collections using the `PageCollectionConfig` type. This type
Here is an example of the page collection config of the root collection:

```ts
import { PageCollectionConfig } from '@jhb.software/payload-pages-plugin'
import type { CollectionConfig } from 'payload'

const Pages: PageCollectionConfig = {
const Pages: CollectionConfig = {
slug: 'pages',
admin: {
useAsTitle: 'title',
},
page: {
parent: {
collection: 'pages',
name: 'parent',
custom: {
pagesPlugin: {
page: {
parent: {
collection: 'pages',
name: 'parent',
},
isRootCollection: true,
},
},
isRootCollection: true,
},
fields: [
{
Expand All @@ -63,15 +73,19 @@ const Pages: PageCollectionConfig = {
Then additional collections can be created. Documents in these collections will be nested under documents in the root collection.

```ts
import { PageCollectionConfig } from '@jhb.software/payload-pages-plugin'
import type { CollectionConfig } from 'payload'

const Posts: PageCollectionConfig = {
const Posts: CollectionConfig = {
slug: 'posts',
page: {
parent: {
collection: 'pages',
name: 'parent',
sharedDocument: true,
custom: {
pagesPlugin: {
page: {
parent: {
collection: 'pages',
name: 'parent',
sharedDocument: true,
},
},
},
},
fields: [
Expand All @@ -80,18 +94,22 @@ const Posts: PageCollectionConfig = {
}
```

The plugin also includes a `RedirectsCollectionConfig` type that can be used to create a redirects collection. This type extends Payload's `CollectionConfig` type with a `redirects` field that contains configurations for the redirects collection.
The plugin also supports a redirects collection. Use the `custom.pagesPlugin.redirects` property to enable it:

```ts
import { RedirectsCollectionConfig } from '@jhb.software/payload-pages-plugin'
import type { CollectionConfig } from 'payload'

const Redirects: RedirectsCollectionConfig = {
const Redirects: CollectionConfig = {
slug: 'redirects',
admin: {
defaultColumns: ['sourcePath', 'destinationPath', 'permanent', 'createdAt'],
listSearchableFields: ['sourcePath', 'destinationPath'],
},
redirects: {},
custom: {
pagesPlugin: {
redirects: {},
},
},
fields: [
// the fields are added by the plugin automatically
],
Expand Down Expand Up @@ -140,15 +158,26 @@ The plugin supports multi-tenant setups via the official [Multi-tenant plugin](h

By default the plugin adds a unique constraint to the slug field of all page collections. In a multi-tenant setup you can disable this constraint by setting the `unique` field to `false` in the page collection config. To ensure uniqueness for a tenant to now have pages with multiple slugs, you can create a compound unique index.

Example:
Example:

```ts
export const Pages: PageCollectionConfig = {
import type { CollectionConfig } from 'payload'

export const Pages: CollectionConfig = {
slug: 'pages',
page: {
slug: {
// Disable the slug uniqueness because of the multi-tenant setup (see indexes below)
unique: false,
custom: {
pagesPlugin: {
page: {
parent: {
collection: 'pages',
name: 'parent',
},
isRootCollection: true,
slug: {
// Disable the slug uniqueness because of the multi-tenant setup (see indexes below)
unique: false,
},
},
},
},
indexes: [
Expand All @@ -158,7 +187,7 @@ export const Pages: PageCollectionConfig = {
},
],
fields: [ /* your fields */],
}
}
```

Some features (e.g. the parent and isRootPage fields) internally fetch documents from the database. To ensure only documents from the current tenant are fetched, you need to pass the `baseFilter` function to the plugin config. It receives the current request object and should return a `Where` object which will be added to the query.
Expand Down
12 changes: 6 additions & 6 deletions pages/dev/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,13 @@
},
"dependencies": {
"@jhb.software/payload-pages-plugin": "workspace:*",
"@payloadcms/db-mongodb": "^3.62.1",
"@payloadcms/db-sqlite": "^3.62.1",
"@payloadcms/next": "^3.62.1",
"@payloadcms/translations": "^3.62.1",
"@payloadcms/ui": "^3.62.1",
"@payloadcms/db-mongodb": "^3.65.0",
"@payloadcms/db-sqlite": "^3.65.0",
"@payloadcms/next": "^3.65.0",
"@payloadcms/translations": "^3.65.0",
"@payloadcms/ui": "^3.65.0",
"next": "15.5.6",
"payload": "^3.62.1",
"payload": "^3.65.0",
"react": "19.2.0",
"react-dom": "19.2.0"
},
Expand Down
4 changes: 2 additions & 2 deletions pages/dev/src/app/(payload)/admin/importMap.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { IsRootPageField as IsRootPageField_817212d6f65b4eb37176541413db3f8c } from '@jhb.software/payload-pages-plugin/server'
import { SlugField as SlugField_817212d6f65b4eb37176541413db3f8c } from '@jhb.software/payload-pages-plugin/server'
import { ParentField as ParentField_817212d6f65b4eb37176541413db3f8c } from '@jhb.software/payload-pages-plugin/server'
import { PathField as PathField_e6458422044c3374e7ca411c92428566 } from '@jhb.software/payload-pages-plugin/client'
import { PathField as PathField_817212d6f65b4eb37176541413db3f8c } from '@jhb.software/payload-pages-plugin/server'
import { BreadcrumbsField as BreadcrumbsField_e6458422044c3374e7ca411c92428566 } from '@jhb.software/payload-pages-plugin/client'

export const importMap = {
"@jhb.software/payload-pages-plugin/server#IsRootPageField": IsRootPageField_817212d6f65b4eb37176541413db3f8c,
"@jhb.software/payload-pages-plugin/server#SlugField": SlugField_817212d6f65b4eb37176541413db3f8c,
"@jhb.software/payload-pages-plugin/server#ParentField": ParentField_817212d6f65b4eb37176541413db3f8c,
"@jhb.software/payload-pages-plugin/client#PathField": PathField_e6458422044c3374e7ca411c92428566,
"@jhb.software/payload-pages-plugin/server#PathField": PathField_817212d6f65b4eb37176541413db3f8c,
"@jhb.software/payload-pages-plugin/client#BreadcrumbsField": BreadcrumbsField_e6458422044c3374e7ca411c92428566
}
32 changes: 19 additions & 13 deletions pages/dev/src/collections/authors.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,28 @@
import { alternatePathsField, PageCollectionConfig } from '@jhb.software/payload-pages-plugin'
import type { CollectionConfig } from 'payload'

export const Authors: PageCollectionConfig = {
import { alternatePathsField } from '@jhb.software/payload-pages-plugin'

export const Authors: CollectionConfig = {
slug: 'authors',
admin: {
useAsTitle: 'name',
},
page: {
parent: {
collection: 'pages',
name: 'parent',
sharedDocument: true,
},
breadcrumbs: {
labelField: 'name',
custom: {
pagesPlugin: {
page: {
parent: {
collection: 'pages',
name: 'parent',
sharedDocument: true,
},
breadcrumbs: {
labelField: 'name',
},
// Example: a collection where preview and live preview are disabled:
livePreview: false,
preview: false,
},
},
// Example: a collection where preview and live preview are disabled:
livePreview: false,
preview: false,
},
fields: [
{
Expand Down
24 changes: 14 additions & 10 deletions pages/dev/src/collections/blogposts.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,22 @@
import { PageCollectionConfig } from '@jhb.software/payload-pages-plugin'
import type { CollectionConfig } from 'payload'

export const Blogposts: PageCollectionConfig = {
export const Blogposts: CollectionConfig = {
slug: 'blogposts',
admin: {
useAsTitle: 'title',
},
page: {
parent: {
collection: 'pages',
name: 'parent',
sharedDocument: true,
},
breadcrumbs: {
labelField: 'shortTitle',
custom: {
pagesPlugin: {
page: {
parent: {
collection: 'pages',
name: 'parent',
sharedDocument: true,
},
breadcrumbs: {
labelField: 'shortTitle',
},
},
},
},
fields: [
Expand Down
20 changes: 13 additions & 7 deletions pages/dev/src/collections/countries.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,21 @@
import { alternatePathsField, PageCollectionConfig } from '@jhb.software/payload-pages-plugin'
import type { CollectionConfig } from 'payload'

export const Countries: PageCollectionConfig = {
import { alternatePathsField } from '@jhb.software/payload-pages-plugin'

export const Countries: CollectionConfig = {
slug: 'countries',
admin: {
useAsTitle: 'title',
},
page: {
parent: {
collection: 'pages',
name: 'parent',
sharedDocument: true,
custom: {
pagesPlugin: {
page: {
parent: {
collection: 'pages',
name: 'parent',
sharedDocument: true,
},
},
},
},
versions: {
Expand Down
30 changes: 18 additions & 12 deletions pages/dev/src/collections/country-travel-tips.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,26 @@
import { alternatePathsField, PageCollectionConfig } from '@jhb.software/payload-pages-plugin'
import type { CollectionConfig } from 'payload'

export const CountryTravelTips: PageCollectionConfig = {
import { alternatePathsField } from '@jhb.software/payload-pages-plugin'

export const CountryTravelTips: CollectionConfig = {
slug: 'country-travel-tips',
admin: {
useAsTitle: 'title',
},
page: {
parent: {
collection: 'countries',
name: 'country',
},
slug: {
unique: false,
staticValue: {
de: 'reisetipps',
en: 'travel-tips',
custom: {
pagesPlugin: {
page: {
parent: {
collection: 'countries',
name: 'country',
},
slug: {
unique: false,
staticValue: {
de: 'reisetipps',
en: 'travel-tips',
},
},
},
},
},
Expand Down
20 changes: 13 additions & 7 deletions pages/dev/src/collections/pages.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,22 @@
import { alternatePathsField, PageCollectionConfig } from '@jhb.software/payload-pages-plugin'
import type { CollectionConfig } from 'payload'

export const Pages: PageCollectionConfig = {
import { alternatePathsField } from '@jhb.software/payload-pages-plugin'

export const Pages: CollectionConfig = {
slug: 'pages',
admin: {
useAsTitle: 'title',
},
page: {
parent: {
collection: 'pages',
name: 'parent',
custom: {
pagesPlugin: {
page: {
parent: {
collection: 'pages',
name: 'parent',
},
isRootCollection: true,
},
},
isRootCollection: true,
},
versions: {
drafts: true,
Expand Down
10 changes: 7 additions & 3 deletions pages/dev/src/collections/redirects.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
import { RedirectsCollectionConfig } from '@jhb.software/payload-pages-plugin'
import type { CollectionConfig } from 'payload'

export const Redirects: RedirectsCollectionConfig = {
export const Redirects: CollectionConfig = {
slug: 'redirects',
admin: {
defaultColumns: ['sourcePath', 'destinationPath', 'permanent', 'createdAt'],
listSearchableFields: ['sourcePath', 'destinationPath'],
},
redirects: {},
custom: {
pagesPlugin: {
redirects: {},
},
},
fields: [
// the fields are added by the plugin automatically
],
Expand Down
1 change: 1 addition & 0 deletions pages/dev/src/payload-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ export interface Config {
db: {
defaultIDType: number;
};
fallbackLocale: ('false' | 'none' | 'null') | false | null | ('de' | 'en') | ('de' | 'en')[];
globals: {};
globalsSelect: {};
locale: 'de' | 'en';
Expand Down
Loading