304 lines
5.9 KiB
Markdown
304 lines
5.9 KiB
Markdown
# Payload CMS Collections Reference
|
|
|
|
Complete reference for collection configurations and patterns.
|
|
|
|
## Basic Collection
|
|
|
|
```ts
|
|
import type { CollectionConfig } from 'payload'
|
|
|
|
export const Posts: CollectionConfig = {
|
|
slug: 'posts',
|
|
labels: {
|
|
singular: 'Post',
|
|
plural: 'Posts',
|
|
},
|
|
admin: {
|
|
useAsTitle: 'title',
|
|
defaultColumns: ['title', 'author', 'status', 'createdAt'],
|
|
group: 'Content', // Organize in admin sidebar
|
|
description: 'Blog posts and articles',
|
|
listSearchableFields: ['title', 'slug'],
|
|
},
|
|
fields: [
|
|
{
|
|
name: 'title',
|
|
type: 'text',
|
|
required: true,
|
|
index: true,
|
|
},
|
|
{
|
|
name: 'slug',
|
|
type: 'text',
|
|
unique: true,
|
|
index: true,
|
|
admin: { position: 'sidebar' },
|
|
},
|
|
{
|
|
name: 'status',
|
|
type: 'select',
|
|
options: ['draft', 'published'],
|
|
defaultValue: 'draft',
|
|
},
|
|
],
|
|
defaultSort: '-createdAt',
|
|
timestamps: true,
|
|
}
|
|
```
|
|
|
|
## Auth Collection
|
|
|
|
```ts
|
|
export const Users: CollectionConfig = {
|
|
slug: 'users',
|
|
auth: {
|
|
tokenExpiration: 7200, // 2 hours
|
|
verify: true,
|
|
maxLoginAttempts: 5,
|
|
lockTime: 600000, // 10 minutes
|
|
useAPIKey: true,
|
|
},
|
|
admin: {
|
|
useAsTitle: 'email',
|
|
},
|
|
fields: [
|
|
{
|
|
name: 'roles',
|
|
type: 'select',
|
|
hasMany: true,
|
|
options: ['admin', 'editor', 'user'],
|
|
required: true,
|
|
defaultValue: ['user'],
|
|
saveToJWT: true,
|
|
},
|
|
{
|
|
name: 'name',
|
|
type: 'text',
|
|
required: true,
|
|
},
|
|
],
|
|
}
|
|
```
|
|
|
|
## Upload Collection
|
|
|
|
```ts
|
|
export const Media: CollectionConfig = {
|
|
slug: 'media',
|
|
upload: {
|
|
staticDir: 'media',
|
|
mimeTypes: ['image/*'],
|
|
imageSizes: [
|
|
{
|
|
name: 'thumbnail',
|
|
width: 400,
|
|
height: 300,
|
|
position: 'centre',
|
|
},
|
|
{
|
|
name: 'card',
|
|
width: 768,
|
|
height: 1024,
|
|
},
|
|
],
|
|
adminThumbnail: 'thumbnail',
|
|
focalPoint: true,
|
|
crop: true,
|
|
},
|
|
access: {
|
|
read: () => true,
|
|
},
|
|
fields: [
|
|
{
|
|
name: 'alt',
|
|
type: 'text',
|
|
required: true,
|
|
},
|
|
{
|
|
name: 'caption',
|
|
type: 'text',
|
|
localized: true,
|
|
},
|
|
],
|
|
}
|
|
```
|
|
|
|
## Live Preview
|
|
|
|
Enable real-time content preview during editing.
|
|
|
|
```ts
|
|
import type { CollectionConfig } from 'payload'
|
|
|
|
const generatePreviewPath = ({
|
|
slug,
|
|
collection,
|
|
req,
|
|
}: {
|
|
slug: string
|
|
collection: string
|
|
req: any
|
|
}) => {
|
|
const baseUrl = process.env.NEXT_PUBLIC_SERVER_URL
|
|
return `${baseUrl}/api/preview?slug=${slug}&collection=${collection}`
|
|
}
|
|
|
|
export const Pages: CollectionConfig = {
|
|
slug: 'pages',
|
|
admin: {
|
|
useAsTitle: 'title',
|
|
// Live preview during editing
|
|
livePreview: {
|
|
url: ({ data, req }) =>
|
|
generatePreviewPath({
|
|
slug: data?.slug as string,
|
|
collection: 'pages',
|
|
req,
|
|
}),
|
|
},
|
|
// Static preview button
|
|
preview: (data, { req }) =>
|
|
generatePreviewPath({
|
|
slug: data?.slug as string,
|
|
collection: 'pages',
|
|
req,
|
|
}),
|
|
},
|
|
fields: [
|
|
{ name: 'title', type: 'text' },
|
|
{ name: 'slug', type: 'text' },
|
|
],
|
|
}
|
|
```
|
|
|
|
## Versioning & Drafts
|
|
|
|
Payload maintains version history and supports draft/publish workflows.
|
|
|
|
```ts
|
|
import type { CollectionConfig } from 'payload'
|
|
|
|
// Basic versioning (audit log only)
|
|
export const Users: CollectionConfig = {
|
|
slug: 'users',
|
|
versions: true, // or { maxPerDoc: 100 }
|
|
fields: [{ name: 'name', type: 'text' }],
|
|
}
|
|
|
|
// Drafts enabled (draft/publish workflow)
|
|
export const Posts: CollectionConfig = {
|
|
slug: 'posts',
|
|
versions: {
|
|
drafts: true, // Enables _status field
|
|
maxPerDoc: 50,
|
|
},
|
|
fields: [{ name: 'title', type: 'text' }],
|
|
}
|
|
|
|
// Full configuration with autosave and scheduled publish
|
|
export const Pages: CollectionConfig = {
|
|
slug: 'pages',
|
|
versions: {
|
|
drafts: {
|
|
autosave: true, // Auto-save while editing
|
|
schedulePublish: true, // Schedule future publish/unpublish
|
|
validate: false, // Don't validate drafts (default)
|
|
},
|
|
maxPerDoc: 100, // Keep last 100 versions (0 = unlimited)
|
|
},
|
|
fields: [{ name: 'title', type: 'text' }],
|
|
}
|
|
```
|
|
|
|
### Draft API Usage
|
|
|
|
```ts
|
|
// Create draft
|
|
await payload.create({
|
|
collection: 'posts',
|
|
data: { title: 'Draft Post' },
|
|
draft: true, // Saves as draft, skips required field validation
|
|
})
|
|
|
|
// Update as draft
|
|
await payload.update({
|
|
collection: 'posts',
|
|
id: '123',
|
|
data: { title: 'Updated Draft' },
|
|
draft: true,
|
|
})
|
|
|
|
// Read with drafts (returns newest draft if available)
|
|
const post = await payload.findByID({
|
|
collection: 'posts',
|
|
id: '123',
|
|
draft: true, // Returns draft version if exists
|
|
})
|
|
|
|
// Query only published (REST API)
|
|
// GET /api/posts (returns only _status: 'published')
|
|
|
|
// Access control for drafts
|
|
export const Posts: CollectionConfig = {
|
|
slug: 'posts',
|
|
versions: { drafts: true },
|
|
access: {
|
|
read: ({ req: { user } }) => {
|
|
// Public can only see published
|
|
if (!user) return { _status: { equals: 'published' } }
|
|
// Authenticated can see all
|
|
return true
|
|
},
|
|
},
|
|
fields: [{ name: 'title', type: 'text' }],
|
|
}
|
|
```
|
|
|
|
### Document Status
|
|
|
|
The `_status` field is auto-injected when drafts are enabled:
|
|
|
|
- `draft` - Never published
|
|
- `published` - Published with no newer drafts
|
|
- `changed` - Published but has newer unpublished drafts
|
|
|
|
## Globals
|
|
|
|
Globals are single-instance documents (not collections).
|
|
|
|
```ts
|
|
import type { GlobalConfig } from 'payload'
|
|
|
|
export const Header: GlobalConfig = {
|
|
slug: 'header',
|
|
label: 'Header',
|
|
admin: {
|
|
group: 'Settings',
|
|
},
|
|
fields: [
|
|
{
|
|
name: 'logo',
|
|
type: 'upload',
|
|
relationTo: 'media',
|
|
required: true,
|
|
},
|
|
{
|
|
name: 'nav',
|
|
type: 'array',
|
|
maxRows: 8,
|
|
fields: [
|
|
{
|
|
name: 'link',
|
|
type: 'relationship',
|
|
relationTo: 'pages',
|
|
},
|
|
{
|
|
name: 'label',
|
|
type: 'text',
|
|
},
|
|
],
|
|
},
|
|
],
|
|
}
|
|
```
|