Compare commits
32 Commits
v3.0.0-bet
...
v3.0.0-bet
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ed1dc4b129 | ||
|
|
f3eb5b2f05 | ||
|
|
03d854ed18 | ||
|
|
c359c34ee8 | ||
|
|
6578b85057 | ||
|
|
b750ebf166 | ||
|
|
31b7a7046b | ||
|
|
c019969271 | ||
|
|
1c8bed5c35 | ||
|
|
10336ba6a8 | ||
|
|
43b971c40b | ||
|
|
fac5425ec0 | ||
|
|
840e07577e | ||
|
|
1baf775aa4 | ||
|
|
588b84a967 | ||
|
|
e5d5126d14 | ||
|
|
ebcfc2d284 | ||
|
|
29205cd209 | ||
|
|
926c87e912 | ||
|
|
83fd4c6622 | ||
|
|
7a7f93c066 | ||
|
|
e9adeecc7a | ||
|
|
f8ab5a9f1e | ||
|
|
45ada0d3bb | ||
|
|
f86e0edf9e | ||
|
|
e4eb5eb37e | ||
|
|
fb6956328f | ||
|
|
a1bb661a1a | ||
|
|
e2b06abb60 | ||
|
|
7be80e31c3 | ||
|
|
d99bff9ec3 | ||
|
|
edf743ef70 |
@@ -19,3 +19,6 @@ fb7d1be2f3325d076b7c967b1730afcef37922c2
|
||||
|
||||
# 3.0 prettier & lint everywhere
|
||||
6789e61488a1d3de56f472ac3214faf344030005
|
||||
|
||||
# 3.0 prettier & lint everywhere again
|
||||
83fd4c66222d7846eeb5cc332dfa99bf1e830831
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
title: Field-level Access Control
|
||||
label: Fields
|
||||
order: 30
|
||||
order: 40
|
||||
desc: Field-level Access Control is specified within a field's config, and allows you to define which users can create, read or update Fields.
|
||||
keywords: fields, access control, permissions, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
|
||||
---
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
title: Globals Access Control
|
||||
label: Globals
|
||||
order: 40
|
||||
order: 30
|
||||
desc: Global-level Access Control is specified within each Global's `access` property and allows you to define which users can read or update Globals.
|
||||
keywords: globals, access control, permissions, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
|
||||
---
|
||||
|
||||
@@ -6,7 +6,7 @@ desc: Manage your data and customize the Payload Admin Panel by swapping in your
|
||||
keywords: admin, components, custom, customize, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
|
||||
---
|
||||
|
||||
Payload dynamically generates a beautiful, [fully type-safe](../typescript/overview) admin panel to manage your users and data. It is highly performant, even with 100+ fields, and is translated in over 30 languages. Within the Admin Panel you can manage content, [render your site](../live-preview/overview), preview drafts, [diff versions](../versions/overview), and so much more.
|
||||
Payload dynamically generates a beautiful, [fully type-safe](../typescript/overview) Admin Panel to manage your users and data. It is highly performant, even with 100+ fields, and is translated in over 30 languages. Within the Admin Panel you can manage content, [render your site](../live-preview/overview), preview drafts, [diff versions](../versions/overview), and so much more.
|
||||
|
||||
The Admin Panel is designed to [white-label your brand](https://payloadcms.com/blog/white-label-admin-ui). You can endlessly customize and extend the Admin UI by swapping in your own [Custom Components](./components)—everything from simple field labels to entire views can be modified or replaced to perfectly tailor the interface for your editors.
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ keywords:
|
||||
|
||||
Views are the individual pages that make up the [Admin Panel](./overview), such as the Dashboard, List, and Edit views. One of the most powerful ways to customize the Admin Panel is to create Custom Views. These are [Custom Components](./components) that can either replace built-in views or can be entirely new.
|
||||
|
||||
Within the Admin Panel, there are four types of views:
|
||||
There are four types of views within the Admin Panel:
|
||||
|
||||
- [Root Views](#root-views)
|
||||
- [Collection Views](#collection-views)
|
||||
|
||||
@@ -45,7 +45,7 @@ Function that accepts one argument, containing `{ req, token, user }`, that allo
|
||||
Example:
|
||||
|
||||
```ts
|
||||
import { CollectionConfig } from 'payload/types'
|
||||
import { CollectionConfig } from 'payload'
|
||||
|
||||
export const Customers: CollectionConfig = {
|
||||
slug: 'customers',
|
||||
@@ -117,7 +117,7 @@ Function that accepts one argument, containing `{ req, token, user }`, that allo
|
||||
Example:
|
||||
|
||||
```ts
|
||||
import { CollectionConfig } from 'payload/types'
|
||||
import { CollectionConfig } from 'payload'
|
||||
|
||||
export const Customers: CollectionConfig = {
|
||||
slug: 'customers',
|
||||
@@ -169,7 +169,7 @@ Example:
|
||||
### Admin autologin
|
||||
|
||||
For testing and demo purposes you may want to skip forcing the admin user to login in order to access the panel.
|
||||
The `admin.autologin` property is used to configure the how visitors are handled when accessing the admin panel.
|
||||
The `admin.autologin` property is used to configure the how visitors are handled when accessing the Admin Panel.
|
||||
The default is that all users will have to login and this should not be enabled for environments where data needs to protected.
|
||||
|
||||
#### autoLogin Options
|
||||
|
||||
@@ -65,7 +65,7 @@ In this scenario, if your cookie was still valid, malicious-intent.com would be
|
||||
|
||||
### CSRF Prevention
|
||||
|
||||
Define domains that your trust and are willing to accept Payload HTTP-only cookie based requests from. Use the `csrf` option on the base Payload config to do this:
|
||||
Define domains that your trust and are willing to accept Payload HTTP-only cookie based requests from. Use the `csrf` option on the base Payload Config to do this:
|
||||
|
||||
```ts
|
||||
// payload.config.ts
|
||||
|
||||
@@ -18,7 +18,7 @@ keywords: authentication, config, configuration, overview, documentation, Conten
|
||||
|
||||
Authentication is used within the [Admin Panel](../admin/overview) itself as well as throughout your app(s) themselves however you determine necessary.
|
||||
|
||||

|
||||

|
||||
_Admin Panel screenshot depicting an Admins Collection with Auth enabled_
|
||||
|
||||
**Here are some common use cases of Authentication outside of Payload's dashboard itself:**
|
||||
@@ -39,7 +39,7 @@ Every Payload Collection can opt-in to supporting Authentication by specifying t
|
||||
Simple example collection:
|
||||
|
||||
```ts
|
||||
import { CollectionConfig } from 'payload/types'
|
||||
import { CollectionConfig } from 'payload'
|
||||
|
||||
export const Admins: CollectionConfig = {
|
||||
slug: 'admins',
|
||||
@@ -73,7 +73,7 @@ Once enabled, each document that is created within the Collection can be thought
|
||||
|
||||
## Authentication Strategies
|
||||
|
||||
Out of the box Payload ships with a few powerful authentication strategies. HTTP-Only Cookies, JWT's and API-Keys, they can work together or individually. You can also have multiple collections that have auth enabled, but only 1 of them can be used to log into the admin panel.
|
||||
Out of the box Payload ships with a few powerful authentication strategies. HTTP-Only Cookies, JWT's and API-Keys, they can work together or individually. You can also have multiple collections that have auth enabled, but only 1 of them can be used to log into the Admin Panel.
|
||||
|
||||
### HTTP-Only Cookies
|
||||
|
||||
|
||||
@@ -98,13 +98,13 @@ From there, you are ready to make updates to your project. When you are ready to
|
||||
|
||||
## Cloud Plugin
|
||||
|
||||
Projects generated from a template will come pre-configured with the official Cloud Plugin, but if you are using your own repository you will need to add this into your project. To do so, add the plugin to your Payload config:
|
||||
Projects generated from a template will come pre-configured with the official Cloud Plugin, but if you are using your own repository you will need to add this into your project. To do so, add the plugin to your Payload Config:
|
||||
|
||||
`yarn add @payloadcms/plugin-cloud`
|
||||
|
||||
```js
|
||||
import { payloadCloud } from '@payloadcms/plugin-cloud'
|
||||
import { buildConfig } from 'payload/config'
|
||||
import { buildConfig } from 'payload'
|
||||
|
||||
export default buildConfig({
|
||||
plugins: [payloadCloud()],
|
||||
@@ -113,7 +113,7 @@ export default buildConfig({
|
||||
```
|
||||
|
||||
<Banner type="warning">
|
||||
**Note:** If your Payload config already has an email with transport, this will take precedence
|
||||
**Note:** If your Payload Config already has an email with transport, this will take precedence
|
||||
over Payload Cloud's email service.
|
||||
</Banner>
|
||||
|
||||
|
||||
@@ -6,11 +6,13 @@ desc: Structure your Collections for your needs by defining fields, adding slugs
|
||||
keywords: collections, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
|
||||
---
|
||||
|
||||
Payload Collections are defined through configs of their own. You can define as many Collections as your application needs. Each Collection will automatically scaffold a new collection / table in your database of choice, based on fields that you define.
|
||||
A Collection is a group of records, called Documents, that all share a common schema. You can define as many Collections as your application needs. Each Collection saves to the [Database](../database/overview) based on the [Fields](../fields/overview) that you define, and automatically generates the [Local API](../local-api/overview), [REST API](../rest-api/overview), and [GraphQL API](../graphql/overview) to manage your Documents.
|
||||
|
||||
## Config Options
|
||||
Collections are also the primary way to achieve [Authentication](../authentication/overview) in Payload. By defining a Collection with `auth` options, that Collection receives additional operations to support user authentication.
|
||||
|
||||
To define a Collection Config, use the `collection` property in your [Payload Config](./overview).
|
||||
Collections are the primary way to structure recurring data in your application, such as users, products, pages, posts, and other types of content that you might want to manage. Each Collection can have its own unique [Access Control](../access-control/overview), [Hooks](../hooks/overview), [Admin Options](#admin-options), and more.
|
||||
|
||||
To define a Collection Config, use the `collection` property in your [Payload Config](./overview):
|
||||
|
||||
```ts
|
||||
import { buildConfig } from 'payload'
|
||||
@@ -18,12 +20,19 @@ import { buildConfig } from 'payload'
|
||||
export default buildConfig({
|
||||
// ...
|
||||
collections: [ // highlight-line
|
||||
// Your Collection Configs go here
|
||||
// Your Collections go here
|
||||
],
|
||||
})
|
||||
```
|
||||
|
||||
It's often best practice to write your Collections in separate files and then import them into the main Payload Config.
|
||||
<Banner type="success">
|
||||
<strong>Tip:</strong>
|
||||
If your Collection is only ever meant to contain a single Document, consider using a [Global](./globals) instead.
|
||||
</Banner>
|
||||
|
||||
## Config Options
|
||||
|
||||
It's often best practice to write your Collections in separate files and then import them into the main [Payload Config](../overview).
|
||||
|
||||
Here is what a simple Collection Config might look like:
|
||||
|
||||
@@ -43,7 +52,7 @@ export const Posts: CollectionConfig = {
|
||||
|
||||
<Banner type="success">
|
||||
<strong>Reminder:</strong>
|
||||
For a more complex example, see the [Public Demo](https://github.com/payloadcms/public-demo) source code on GitHub.
|
||||
For a more complex example, see the [Public Demo](https://github.com/payloadcms/public-demo) source code on GitHub, or the [Templates](https://github.com/payloadcms/payload/tree/main/templates) and [Examples](https://github.com/payloadcms/payload/tree/main/examples) directories in the Payload repository.
|
||||
</Banner>
|
||||
|
||||
The following options are available:
|
||||
@@ -56,11 +65,11 @@ The following options are available:
|
||||
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
|
||||
| **`disableDuplicate`** | When true, do not show the "Duplicate" button while editing documents within this Collection and prevent `duplicate` from all APIs. |
|
||||
| **`defaultSort`** | Pass a top-level field to sort by default in the Collection List View. Prefix the name of the field with a minus symbol ("-") to sort in descending order. |
|
||||
| **`dbName`** | Custom table or Collection name depending on the database adapter. Auto-generated from slug if not defined. |
|
||||
| **`dbName`** | Custom table or Collection name depending on the Database Adapter. Auto-generated from slug if not defined. |
|
||||
| **`endpoints`** | Add custom routes to the REST API. Set to `false` to disable routes. [More details](../rest-api/overview#custom-endpoints). |
|
||||
| **`fields`** \* | Array of field types that will determine the structure and functionality of the data stored within this Collection. [Click here](../fields/overview) for a full list of field types as well as how to configure them. |
|
||||
| **`graphQL`** | An object with `singularName` and `pluralName` strings used in schema generation. Auto-generated from slug if not defined. Set to `false` to disable GraphQL. |
|
||||
| **`hooks`** | Entry points to "tie in" to Collection actions at specific points. [More details](../hooks/overview#collection-hooks). |
|
||||
| **`hooks`** | Entry point for Hooks. [More details](../hooks/overview#collection-hooks). |
|
||||
| **`labels`** | Singular and plural labels for use in identifying this Collection throughout Payload. Auto-generated from slug if not defined. |
|
||||
| **`slug`** \* | Unique, URL-friendly string that will act as an identifier for this Collection. |
|
||||
| **`timestamps`** | Set to false to disable documents' automatically generated `createdAt` and `updatedAt` timestamps. |
|
||||
@@ -70,11 +79,23 @@ The following options are available:
|
||||
|
||||
_\* An asterisk denotes that a property is required._
|
||||
|
||||
## Admin Options
|
||||
### Fields
|
||||
|
||||
Fields define the schema of the Documents within a Collection. To learn more, go to the [Fields](../fields/overview) documentation.
|
||||
|
||||
### Access Control
|
||||
|
||||
Access Control determines what a user can and cannot do with any given Document. To learn more, go to the [Access Control](../access-control/overview) docs.
|
||||
|
||||
### Hooks
|
||||
|
||||
Hooks allow you to tie into the lifecycle of your Documents so you can execute your own logic during specific events. To learn more, go to the [Hooks](../hooks/overview) documentation.
|
||||
|
||||
### Admin Options
|
||||
|
||||
You can customize the way that the [Admin Panel](../admin/overview) behaves on a Collection-by-Collection basis.
|
||||
|
||||
To configure Collection Admin Options, use the `admin` property in your Collection Config:
|
||||
To configure Admin Options for Collections, use the `admin` property in your Collection Config:
|
||||
|
||||
```ts
|
||||
import { CollectionConfig } from 'payload'
|
||||
@@ -144,7 +165,7 @@ The preview function receives two arguments:
|
||||
For fully working example of this, check of the official [Draft Preview Example](https://github.com/payloadcms/payload/tree/main/examples/draft-preview) in the [Examples Directory](https://github.com/payloadcms/payload/tree/main/examples).
|
||||
</Banner>
|
||||
|
||||
### Pagination
|
||||
#### Pagination
|
||||
|
||||
All Collections receive their own List View which displays a paginated list of documents that can be sorted and filtered. The pagination behavior of the List View can be customized on a per-Collection basis.
|
||||
|
||||
@@ -173,17 +194,7 @@ The following options are available:
|
||||
| `defaultLimit` | Integer that specifies the default per-page limit that should be used. Defaults to 10. |
|
||||
| `limits` | Provide an array of integers to use as per-page options for admins to choose from in the List View. |
|
||||
|
||||
### Access Control
|
||||
|
||||
You can specify extremely granular access control (what users can do with documents in a Collection) on a Collection by
|
||||
Collection basis. To learn more, go to the [Access Control](../access-control/overview) docs.
|
||||
|
||||
### Hooks
|
||||
|
||||
Hooks are a powerful way to extend Collection functionality and execute your own logic, and can be defined on a
|
||||
Collection by Collection basis. To learn more, go to the [Hooks](../hooks/overview) documentation.
|
||||
|
||||
### List Searchable Fields
|
||||
#### List Searchable Fields
|
||||
|
||||
In the List View, there is a "search" box that allows you to quickly find a document through a simple text search. By default, it searches on the ID field. If defined, the `admin.useAsTitle` field is used. Or, you can explicitly define which fields to search based on the needs of your application.
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ SERVER_URL=localhost:3000
|
||||
DATABASE_URI=mongodb://localhost:27017/my-database
|
||||
```
|
||||
|
||||
To use Environment Variables in your Payload config, you can access them directly from `process.env`:
|
||||
To use Environment Variables in your Payload Config, you can access them directly from `process.env`:
|
||||
|
||||
```ts
|
||||
import { buildConfig } from 'payload'
|
||||
|
||||
@@ -6,9 +6,9 @@ desc: Set up your Global config for your needs by defining fields, adding slugs
|
||||
keywords: globals, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
|
||||
---
|
||||
|
||||
Payload Globals are in many ways similar to [Collections](../configuration/collections). The big difference is that Collections will potentially contain _many_ documents, while a Global is a "one-off". Globals are perfect for things like header nav, site-wide banner alerts, app-wide localized strings, and other "global" data that your site or app might rely on.
|
||||
Globals are in many ways similar to [Collections](../configuration/collections), except they correspond to only a single Document. You can define as many Globals as your application needs. Each Global saves to the [Database](../database/overview) based on the [Fields](../fields/overview) that you define, and automatically generates the [Local API](../local-api/overview), [REST API](../rest-api/overview), and [GraphQL API](../graphql/overview) to manage your Documents.
|
||||
|
||||
## Config Options
|
||||
Globals are the primary way to structure singletons in Payload, such as a header navigation, site-wide banner alerts, or app-wide localized strings. Each Global can have its own unique [Access Control](../access-control/overview), [Hooks](../hooks/overview), [Admin Options](#admin-options), and more.
|
||||
|
||||
To define a Global Config, use the `globals` property in your [Payload Config](./overview):
|
||||
|
||||
@@ -18,12 +18,19 @@ import { buildConfig } from 'payload'
|
||||
export default buildConfig({
|
||||
// ...
|
||||
globals: [ // highlight-line
|
||||
// Your Global Configs go here
|
||||
// Your Globals go here
|
||||
],
|
||||
})
|
||||
```
|
||||
|
||||
It's often best practice to write your Globals in separate files and then import them into the main Payload Config.
|
||||
<Banner type="success">
|
||||
<strong>Tip:</strong>
|
||||
If you have more than one Global that share the same structure, consider using a [Collection](../configuration/collections) instead.
|
||||
</Banner>
|
||||
|
||||
## Config Options
|
||||
|
||||
It's often best practice to write your Globals in separate files and then import them into the main [Payload Config](./overview).
|
||||
|
||||
Here is what a simple Global Config might look like:
|
||||
|
||||
@@ -53,7 +60,7 @@ export const Nav: GlobalConfig = {
|
||||
|
||||
<Banner type="success">
|
||||
<strong>Reminder:</strong>
|
||||
For a more complex example, see the [Public Demo](https://github.com/payloadcms/public-demo) source code on GitHub.
|
||||
For a more complex example, see the [Public Demo](https://github.com/payloadcms/public-demo) source code on GitHub, or the [Templates](https://github.com/payloadcms/payload/tree/main/templates) and [Examples](https://github.com/payloadcms/payload/tree/main/examples) directories in the Payload repository.
|
||||
</Banner>
|
||||
|
||||
The following options are available:
|
||||
@@ -63,12 +70,12 @@ The following options are available:
|
||||
| **`access`** | Provide access control functions to define exactly who should be able to do what with this Global. [More details](../access-control/overview/#globals). |
|
||||
| **`admin`** | The configuration options for the Admin Panel. [More details](#admin-options). |
|
||||
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
|
||||
| **`dbName`** | Custom table or collection name for this Global depending on the database adapter. Auto-generated from slug if not defined. |
|
||||
| **`dbName`** | Custom table or collection name for this Global depending on the Database Adapter. Auto-generated from slug if not defined. |
|
||||
| **`description`** | Text or React component to display below the Global header to give editors more information. |
|
||||
| **`endpoints`** | Add custom routes to the REST API. [More details](../rest-api/overview#custom-endpoints). |
|
||||
| **`fields`** \* | Array of field types that will determine the structure and functionality of the data stored within this Global. [Click here](../fields/overview) for a full list of field types as well as how to configure them. |
|
||||
| **`graphQL.name`** | Text used in schema generation. Auto-generated from slug if not defined. |
|
||||
| **`hooks`** | Entry points to "tie in" to collection actions at specific points. [More details](../hooks/overview#global-hooks). |
|
||||
| **`hooks`** | Entry point for Hooks. [More details](../hooks/overview#global-hooks). |
|
||||
| **`label`** | Text for the name in the Admin Panel or an object with keys for each language. Auto-generated from slug if not defined. |
|
||||
| **`slug`** \* | Unique, URL-friendly string that will act as an identifier for this Global. |
|
||||
| **`typescript`** | An object with property `interface` as the text used in schema generation. Auto-generated from slug if not defined. |
|
||||
@@ -76,20 +83,23 @@ The following options are available:
|
||||
|
||||
_\* An asterisk denotes that a property is required._
|
||||
|
||||
### Fields
|
||||
|
||||
Fields define the schema of the Global. To learn more, go to the [Fields](../fields/overview) documentation.
|
||||
|
||||
### Access Control
|
||||
|
||||
As with Collections, you can specify extremely granular access control (what users can do with this Global) on a Global-by-Global basis. However, Globals only have `update` and `read` access control due to their nature of only having one document. To learn more, go to the [Access Control](../access-control/overview) docs.
|
||||
Access Control determines what a user can and cannot do with any given Document. To learn more, go to the [Access Control](../access-control/overview) docs.
|
||||
|
||||
### Hooks
|
||||
|
||||
Globals also fully support a smaller subset of Hooks. To learn more, go to the [Hooks](../hooks/overview) documentation.
|
||||
Hooks allow you to tie into the lifecycle of your Documents so you can execute your own logic during specific events. To learn more, go to the [Hooks](../hooks/overview) documentation.
|
||||
|
||||
### Admin Options
|
||||
|
||||
You can customize the way that the [Admin Panel](../admin/overview) behaves on a Global-by-Global basis.
|
||||
|
||||
To configure Collection Admin Options, use the `admin` property in your Global Config:
|
||||
To configure Admin Options for Globals, use the `admin` property in your Global Config:
|
||||
|
||||
```ts
|
||||
import { GlobalConfig } from 'payload'
|
||||
@@ -163,7 +173,7 @@ import { GlobalConfig } from 'payload'
|
||||
```
|
||||
|
||||
```ts
|
||||
import { SanitizedGlobalConfig } from 'payload/types'
|
||||
import { SanitizedGlobalConfig } from 'payload'
|
||||
|
||||
// This is the type used after an incoming Global config is fully sanitized.
|
||||
// Generally, this is only used internally by Payload.
|
||||
|
||||
@@ -6,9 +6,22 @@ desc: Manage and customize internationalization support in your CMS editor exper
|
||||
keywords: internationalization, i18n, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
|
||||
---
|
||||
|
||||
The [Admin Panel](../admin/overview) is translated in over [30 languages and counting](https://github.com/payloadcms/payload/tree/beta/packages/translations). With i18n, editors can navigate the interface and read API error messages in their preferred language. Users can easily select a language from the Account View and have their preference saved for future visits.
|
||||
The [Admin Panel](../admin/overview) is translated in over [30 languages and counting](https://github.com/payloadcms/payload/tree/beta/packages/translations). With I18n, editors can navigate the interface and read API error messages in their preferred language. This is similar to [Localization](./localization), but instead of managing translations for the data itself, you are managing translations for your application's interface.
|
||||
|
||||
By default, Payload comes with preinstalled with English, but you can easily load other languages into your own application. Languages are automatically detected based on the user's browser. If no language was detected, or if the user's language is not yet supported by your application, English will be chosen.
|
||||
By default, Payload comes with preinstalled with English, but you can easily load other languages into your own application. Languages are automatically detected based on the request. If no language was detected, or if the user's language is not yet supported by your application, English will be chosen.
|
||||
|
||||
To configure I18n, use the `i18n` key in your [Payload Config](./overview):
|
||||
|
||||
```ts
|
||||
import { buildConfig } from 'payload'
|
||||
|
||||
export default buildConfig({
|
||||
// ...
|
||||
i18n: { // highlight-line
|
||||
// ...
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
<Banner type="success">
|
||||
<strong>Note:</strong>
|
||||
@@ -19,19 +32,44 @@ By default, Payload comes with preinstalled with English, but you can easily loa
|
||||
|
||||
You can easily customize and override any of the i18n settings that Payload provides by default. Payload will use your custom options and merge them in with its own.
|
||||
|
||||
To add a new language, use the `i18n` key in your [Payload Config](./overview):
|
||||
|
||||
```ts
|
||||
import { buildConfig } from 'payload'
|
||||
import { en } from 'payload/i18n/en'
|
||||
import { de } from 'payload/i18n/de'
|
||||
|
||||
export default buildConfig({
|
||||
// ...
|
||||
// highlight-start
|
||||
i18n: {
|
||||
// Payload will support either English or German,
|
||||
// able to be specified in preferences on a user-by-user basis
|
||||
fallbackLanguage: 'en', // default
|
||||
debug: false, // default
|
||||
}
|
||||
// highlight-end
|
||||
})
|
||||
```
|
||||
|
||||
The following options are available:
|
||||
|
||||
| Option | Description |
|
||||
| --------------------- | --------------------------------|
|
||||
| **`fallbackLanguage`** | The language to fall back to if the user's preferred language is not supported. Default is `'en'`. |
|
||||
| **`debug`** | Whether to log debug information to the console. Default is `false`. |
|
||||
| **`translations`** | An object containing the translations. The keys are the language codes and the values are the translations. |
|
||||
| **`supportedLanguages`** | An object containing the supported languages. The keys are the language codes and the values are the translations. |
|
||||
|
||||
## Adding Languages
|
||||
|
||||
You can easily add new languages to your Payload app by providing the translations for the new language. Payload maintains a number of built-in translations that can be imported from `@payloadcms/translations`, but you can also provide your own [Custom Translations](#custom-translations) to support any language.
|
||||
|
||||
To add a new language, use the `i18n.supportedLanguages` key in your [Payload Config](./overview):
|
||||
|
||||
```ts
|
||||
import { buildConfig } from 'payload'
|
||||
import { en } from '@payloadcms/translations/languages/en'
|
||||
import { de } from '@payloadcms/translations/languages/de'
|
||||
|
||||
export default buildConfig({
|
||||
// ...
|
||||
// highlight-start
|
||||
i18n: {
|
||||
supportedLanguages: { en, de },
|
||||
},
|
||||
// highlight-end
|
||||
@@ -43,27 +81,18 @@ export default buildConfig({
|
||||
It's best to only support the languages that you need so that the bundled JavaScript is kept to a minimum for your project.
|
||||
</Banner>
|
||||
|
||||
The following options are available:
|
||||
### Custom Translations
|
||||
|
||||
| Option | Description |
|
||||
| --------------------- | --------------------------------|
|
||||
| **`fallbackLanguage`** | The language to fall back to if the user's preferred language is not supported. Default is `'en'`. |
|
||||
| **`debug`** | Whether to log debug information to the console. Default is `false`. |
|
||||
| **`translations`** | An object containing the translations. The keys are the language codes and the values are the translations. |
|
||||
| **`supportedLanguages`** | An object containing the supported languages. The keys are the language codes and the values are the translations. |
|
||||
You can customize Payload's built-in translations either by extending existing languages or by adding new languages entirely. This can be done by injecting new translation strings into existing languages, or by providing an entirely new language keys altogether.
|
||||
|
||||
## Custom Translations
|
||||
|
||||
Here is an example of how you can add custom translations to your project:
|
||||
To add Custom Translations, use the `i18n.translations` key in your [Payload Config](./overview):
|
||||
|
||||
```ts
|
||||
import { buildConfig } from 'payload/config'
|
||||
import { buildConfig } from 'payload'
|
||||
|
||||
export default buildConfig({
|
||||
//...
|
||||
i18n: {
|
||||
fallbackLanguage: 'en', // default
|
||||
debug: false, // default
|
||||
// highlight-start
|
||||
translations: {
|
||||
en: {
|
||||
@@ -83,9 +112,11 @@ export default buildConfig({
|
||||
})
|
||||
```
|
||||
|
||||
While Payload's built-in features come translated, you may want to also translate parts of your project's configuration too. This is possible in places like Collections and Globals labels and groups, field labels, descriptions and input placeholder text. The admin UI will display all the correct translations you provide based on the user's language.
|
||||
### Project Translations
|
||||
|
||||
Here is an example of a simple collection supporting both English and Spanish editors:
|
||||
While Payload's built-in features come fully translated, you may also want to translate parts of your own project. This is possible in places like [Collections](./collections) and [Globals](./globals), such as on their labels and groups, field labels, descriptions or input placeholder text.
|
||||
|
||||
To do this, provide the translations wherever applicable, keyed to the language code:
|
||||
|
||||
```ts
|
||||
import { CollectionConfig } from 'payload'
|
||||
@@ -94,39 +125,45 @@ export const Articles: CollectionConfig = {
|
||||
slug: 'articles',
|
||||
labels: {
|
||||
singular: {
|
||||
// highlight-start
|
||||
en: 'Article',
|
||||
es: 'Artículo',
|
||||
// highlight-end
|
||||
},
|
||||
plural: {
|
||||
// highlight-start
|
||||
en: 'Articles',
|
||||
es: 'Artículos',
|
||||
// highlight-end
|
||||
},
|
||||
},
|
||||
admin: {
|
||||
group: { en: 'Content', es: 'Contenido' },
|
||||
group: {
|
||||
// highlight-start
|
||||
en: 'Content',
|
||||
es: 'Contenido',
|
||||
// highlight-end
|
||||
},
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: 'title',
|
||||
type: 'text',
|
||||
label: {
|
||||
// highlight-start
|
||||
en: 'Title',
|
||||
es: 'Título',
|
||||
// highlight-end
|
||||
},
|
||||
admin: {
|
||||
placeholder: { en: 'Enter title', es: 'Introduce el título' },
|
||||
placeholder: {
|
||||
// highlight-start
|
||||
en: 'Enter title',
|
||||
es: 'Introduce el título'
|
||||
// highlight-end
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'type',
|
||||
type: 'radio',
|
||||
options: [
|
||||
{
|
||||
value: 'news',
|
||||
label: { en: 'News', es: 'Noticias' },
|
||||
}, // etc...
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
||||
```
|
||||
@@ -135,7 +172,7 @@ export const Articles: CollectionConfig = {
|
||||
|
||||
Payload's backend sets the language on incoming requests before they are handled. This allows backend validation to return error messages in the user's own language or system generated emails to be sent using the correct translation. You can make HTTP requests with the `accept-language` header and Payload will use that language.
|
||||
|
||||
Anywhere in your Payload app that you have access to the `req` object, you can access payload's extensive internationalization features assigned to `req.i18n`. To access text translations you can use `req.t('namespace:key')`.
|
||||
Anywhere in your Payload app that you have access to the `req` object, you can access Payload's extensive internationalization features assigned to `req.i18n`. To access text translations you can use `req.t('namespace:key')`.
|
||||
|
||||
## TypeScript
|
||||
|
||||
@@ -169,7 +206,7 @@ export const MyComponent: React.FC = () => {
|
||||
|
||||
```
|
||||
|
||||
Additionally, payload exposes the `t` function in various places, for example in labels. Here is how you would type those:
|
||||
Additionally, Payload exposes the `t` function in various places, for example in labels. Here is how you would type those:
|
||||
|
||||
```ts
|
||||
import type {
|
||||
@@ -177,7 +214,7 @@ import type {
|
||||
NestedKeysStripped,
|
||||
TFunction,
|
||||
} from '@payloadcms/translations'
|
||||
import type { Field } from 'payload/types'
|
||||
import type { Field } from 'payload'
|
||||
|
||||
const customTranslations = {
|
||||
en: {
|
||||
|
||||
@@ -2,36 +2,45 @@
|
||||
title: Localization
|
||||
label: Localization
|
||||
order: 50
|
||||
desc: Add and maintain as many locales as you need by adding Localization to your Payload config, set options for default locale, fallbacks, fields and more.
|
||||
desc: Add and maintain as many locales as you need by adding Localization to your Payload Config, set options for default locale, fallbacks, fields and more.
|
||||
keywords: localization, internationalization, i18n, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
|
||||
---
|
||||
|
||||
Payload features deep field-based localization support. Maintaining as many locales as you need is easy. All
|
||||
localization support is opt-in by default. To do so, follow the two steps below.
|
||||
Localization is one of the most important features of a modern CMS. It allows you to manage content in multiple languages, then serve it to your users based on their requested language. This is similar to [I18n](./i18n), but instead of managing translations for your application's interface, you are managing translations for the data itself.
|
||||
|
||||
## Enabling in the Payload config
|
||||
With Localization, you can begin to serve personalized content to your users based on their specific language preferences, such as a multilingual website or multi-site application. There are no limits to the number of locales you can add to your Payload project.
|
||||
|
||||
Add the `localization` property to your Payload config to enable localization project-wide. You'll need to provide a
|
||||
list of all locales that you'd like to support as well as set a few other options.
|
||||
|
||||
**Example Payload config set up for localization:**
|
||||
To configure Localization, use the `localization` key in your [Payload Config](./overview):
|
||||
|
||||
```ts
|
||||
import { buildConfig } from 'payload'
|
||||
|
||||
export default buildConfig({
|
||||
collections: [
|
||||
// collections go here
|
||||
],
|
||||
localization: {
|
||||
locales: ['en', 'es', 'de'],
|
||||
defaultLocale: 'en',
|
||||
fallback: true,
|
||||
// ...
|
||||
localization: { // highlight-line
|
||||
// ...
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
**Example Payload config set up for localization with full locales objects:**
|
||||
## Config Options
|
||||
|
||||
Add the `localization` property to your Payload Config to enable Localization project-wide. You'll need to provide a list of all locales that you'd like to support as well as set a few other options.
|
||||
|
||||
To configure locales, use the `localization.locales` property in your [Payload Config](./overview):
|
||||
|
||||
```ts
|
||||
import { buildConfig } from 'payload'
|
||||
|
||||
export default buildConfig({
|
||||
// ...
|
||||
localization: {
|
||||
locales: ['en', 'es', 'de'] // highlight-line
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
You can also define locales using [full configuration objects](#locale-object):
|
||||
|
||||
```ts
|
||||
import { buildConfig } from 'payload'
|
||||
@@ -60,50 +69,26 @@ export default buildConfig({
|
||||
})
|
||||
```
|
||||
|
||||
**Example Payload config set up for localization with full locales objects (
|
||||
including [internationalization](/docs/configuration/i18n) support):**
|
||||
<Banner type="success">
|
||||
<strong>Tip:</strong>
|
||||
Localization works very well alongside [I18n](/docs/configuration/i18n).
|
||||
</Banner>
|
||||
|
||||
```ts
|
||||
import { buildConfig } from 'payload'
|
||||
The following options are available:
|
||||
|
||||
export default buildConfig({
|
||||
collections: [
|
||||
// collections go here
|
||||
],
|
||||
localization: {
|
||||
locales: [
|
||||
{
|
||||
label: {
|
||||
en: 'English', // English label
|
||||
nb: 'Engelsk', // Norwegian label
|
||||
},
|
||||
code: 'en',
|
||||
},
|
||||
{
|
||||
label: {
|
||||
en: 'Norwegian', // English label
|
||||
nb: 'Norsk', // Norwegian label
|
||||
},
|
||||
code: 'nb',
|
||||
},
|
||||
],
|
||||
defaultLocale: 'en',
|
||||
fallback: true,
|
||||
},
|
||||
})
|
||||
```
|
||||
| Option | Description |
|
||||
| -------------- | ------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| **`locales`** | Array of all the languages that you would like to support. [More details](#locales) |
|
||||
| **`defaultLocale`** | Required string that matches one of the locale codes from the array provided. By default, if no locale is specified, documents will be returned in this locale. |
|
||||
| **`fallback`** | Boolean enabling "fallback" locale functionality. If a document is requested in a locale, but a field does not have a localized value corresponding to the requested locale, then if this property is enabled, the document will automatically fall back to the fallback locale value. If this property is not enabled, the value will not be populated. |
|
||||
|
||||
**Here is a brief explanation of each of the options available within the `localization` property:**
|
||||
### Locales
|
||||
|
||||
**`locales`**
|
||||
The locales array is a list of all the languages that you would like to support. This can be strings for each language code, or [full configuration objects](#locale-object) for more advanced options.
|
||||
|
||||
Array-based list of all the languages that you would like to support. This can be an array containing strings for each
|
||||
language code you want your project to store and serve or objects with a `label`, a locale `code`, `rtl` (
|
||||
right-to-left), and `fallbackLocale` property. The locale codes do not need to be in any specific format. It's up to you
|
||||
to define how to represent your locales. Common patterns are to use two-letter ISO 639 language codes or four-letter
|
||||
language and country codes (ISO 3166‑1) such as `en-US`, `en-UK`, `es-MX`, etc.
|
||||
The locale codes do not need to be in any specific format. It's up to you to define how to represent your locales. Common patterns are to use two-letter ISO 639 language codes or four-letter language and country codes (ISO 3166‑1) such as `en-US`, `en-UK`, `es-MX`, etc.
|
||||
|
||||
## Locale Object Properties
|
||||
#### Locale Object
|
||||
|
||||
| Option | Description |
|
||||
| -------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
|
||||
@@ -114,23 +99,11 @@ language and country codes (ISO 3166‑1) such as `en-US`, `en-UK`, `es-MX`, etc
|
||||
|
||||
_\* An asterisk denotes that a property is required._
|
||||
|
||||
**`defaultLocale`**
|
||||
## Field Localization
|
||||
|
||||
Required string that matches one of the locale codes from the array provided. By default, if no locale is specified,
|
||||
documents will be returned in this locale.
|
||||
Payload Localization works on a **field** level—not a document level. In addition to configuring the base Payload Config to support Localization, you need to specify each field that you would like to localize.
|
||||
|
||||
**`fallback`**
|
||||
|
||||
Boolean enabling "fallback" locale functionality. If a document is requested in a locale, but a field does not have a
|
||||
localized value corresponding to the requested locale, then if this property is enabled, the document will automatically
|
||||
fall back to the fallback locale value. If this property is not enabled, the value will not be populated.
|
||||
|
||||
## Field by field localization
|
||||
|
||||
Payload localization works on a **field** level—not a document level. In addition to configuring the base Payload config
|
||||
to support localization, you need to specify each field that you would like to localize.
|
||||
|
||||
**Here is an example of how to enable localization for a field:**
|
||||
**Here is an example of how to enable Localization for a field:**
|
||||
|
||||
```js
|
||||
{
|
||||
@@ -142,31 +115,27 @@ to support localization, you need to specify each field that you would like to l
|
||||
}
|
||||
```
|
||||
|
||||
With the above configuration, the `title` field will now be saved in the database as an object of all locales instead of
|
||||
a single string.
|
||||
With the above configuration, the `title` field will now be saved in the database as an object of all locales instead of a single string.
|
||||
|
||||
All field types with a `name` property support the `localized` property—even the more complex field types like `array`s
|
||||
and `block`s.
|
||||
All field types with a `name` property support the `localized` property—even the more complex field types like `array`s and `block`s.
|
||||
|
||||
<Banner>
|
||||
<Banner type="info">
|
||||
<strong>Note:</strong>
|
||||
<br />
|
||||
Enabling localization for field types that support nested fields will automatically create
|
||||
Enabling Localization for field types that support nested fields will automatically create
|
||||
localized "sets" of all fields contained within the field. For example, if you have a page layout
|
||||
using a blocks field type, you have the choice of either localizing the full layout, by enabling
|
||||
localization on the top-level blocks field, or only certain fields within the layout.
|
||||
Localization on the top-level blocks field, or only certain fields within the layout.
|
||||
</Banner>
|
||||
|
||||
<Banner type="warning">
|
||||
<strong>Important:</strong>
|
||||
<br />
|
||||
When converting an existing field to or from `localized: true` the data structure in the document
|
||||
will change for this field and so existing data for this field will be lost. Before changing the
|
||||
localization setting on fields with existing data, you may need to consider a field migration
|
||||
Localization setting on fields with existing data, you may need to consider a field migration
|
||||
strategy.
|
||||
</Banner>
|
||||
|
||||
## Retrieving localized docs
|
||||
## Retrieving Localized Docs
|
||||
|
||||
When retrieving documents, you can specify which locale you'd like to receive as well as which fallback locale should be
|
||||
used.
|
||||
@@ -182,7 +151,7 @@ Specify your desired locale by providing the `locale` query parameter directly i
|
||||
**`?fallback-locale=`**
|
||||
|
||||
Specify fallback locale to be used by providing the `fallback-locale` query parameter. This can be provided as either a
|
||||
valid locale as provided to your base Payload config, or `'null'`, `'false'`, or `'none'` to disable falling back.
|
||||
valid locale as provided to your base Payload Config, or `'null'`, `'false'`, or `'none'` to disable falling back.
|
||||
|
||||
**Example:**
|
||||
|
||||
@@ -234,10 +203,9 @@ const posts = await payload.find({
|
||||
})
|
||||
```
|
||||
|
||||
<Banner type="alert">
|
||||
<Banner type="success">
|
||||
<strong>Tip:</strong>
|
||||
<br />
|
||||
The REST and Local APIs can return all localization data in one request by passing 'all' or '*' as
|
||||
The REST and Local APIs can return all Localization data in one request by passing 'all' or '*' as
|
||||
the <strong>locale</strong> parameter. The response will be structured so that field values come
|
||||
back as the full objects keyed for each locale instead of the single, translated value.
|
||||
</Banner>
|
||||
|
||||
@@ -6,7 +6,7 @@ desc: The Payload Config is central to everything that Payload does, from adding
|
||||
keywords: overview, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
|
||||
---
|
||||
|
||||
Payload is a _config-based_, code-first CMS and application framework. The Payload Config is central to everything that Payload does, allowing for the deep configuration of your application through a simple API.
|
||||
Payload is a _config-based_, code-first CMS and application framework. The Payload Config is central to everything that Payload does, allowing for deep configuration of your application through a simple and intuitive API. The Payload Config is a fully-typed JavaScript object that can be infinitely extended upon.
|
||||
|
||||
Everything from your [Database](../database/overview) choice, to the appearance of the [Admin Panel](../admin/overview), is fully controlled through the Payload Config. From here you can define [Fields](../fields/overview), add [Localization](./localization), enable [Authentication](../authentication/overview), configure [Access Control](../access-control/overview), and so much more.
|
||||
|
||||
@@ -58,8 +58,8 @@ export default buildConfig({
|
||||
```
|
||||
|
||||
<Banner type="success">
|
||||
<strong>More:</strong>
|
||||
For a more complex example, see the [Public Demo](https://github.com/payloadcms/public-demo) source code on GitHub.
|
||||
<strong>Reminder:</strong>
|
||||
For a more complex example, see the [Public Demo](https://github.com/payloadcms/public-demo) source code on GitHub, or the [Templates](https://github.com/payloadcms/payload/tree/main/templates) and [Examples](https://github.com/payloadcms/payload/tree/main/examples) directories in the Payload repository.
|
||||
</Banner>
|
||||
|
||||
The following options are available:
|
||||
@@ -78,7 +78,7 @@ The following options are available:
|
||||
| **`graphQL`** | Manage GraphQL-specific functionality, including custom queries and mutations, query complexity limits, etc. [More details](../graphql/overview#graphql-options). |
|
||||
| **`cookiePrefix`** | A string that will be prefixed to all cookies that Payload sets. |
|
||||
| **`csrf`** | A whitelist array of URLs to allow Payload cookies to be accepted from as a form of CSRF protection. [More details](../authentication/overview#csrf-protection). |
|
||||
| **`defaultDepth`** | If a user does not specify `depth` while requesting a resource, this depth will be used. [More details](../getting-started/concepts#depth). |
|
||||
| **`defaultDepth`** | If a user does not specify `depth` while requesting a resource, this depth will be used. [More details](../queries/depth). |
|
||||
| **`defaultMaxTextLength`** | The maximum allowed string length to be permitted application-wide. Helps to prevent malicious public document creation. |
|
||||
| **`maxDepth`** | The maximum allowed depth to be permitted application-wide. This setting helps prevent against malicious queries. Defaults to `10`. |
|
||||
| **`indexSortableFields`** | Automatically index all sortable top-level fields in the database to improve sort performance and add database compatibility for Azure Cosmos and similar. |
|
||||
@@ -104,6 +104,50 @@ _\* An asterisk denotes that a property is required._
|
||||
Some properties are removed from the client-side bundle. [More details](../admin/components#accessing-the-payload-config).
|
||||
</Banner>
|
||||
|
||||
|
||||
### TypeScript
|
||||
|
||||
Payload exposes a variety of TypeScript settings that you can leverage. These settings are used to auto-generate TypeScript interfaces for your Collections and Globals, and to ensure that Payload uses your [Generated Types](../typescript/overview) for all Local API methods.
|
||||
|
||||
To customize the TypeScript settings, use the `typescript` property in your Payload Config:
|
||||
|
||||
```ts
|
||||
import { buildConfig } from 'payload'
|
||||
|
||||
export default buildConfig({
|
||||
// ...
|
||||
typescript: { // highlight-line
|
||||
// ...
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
The following options are available:
|
||||
|
||||
| Option | Description |
|
||||
| --------------- | --------------------- |
|
||||
| **`autoGenerate`** | By default, Payload will auto-generate TypeScript interfaces for all collections and globals that your config defines. Opt out by setting `typescript.autoGenerate: false`. [More details](../typescript/overview). |
|
||||
| **`declare`** | By default, Payload adds a `declare` block to your generated types, which makes sure that Payload uses your generated types for all Local API methods. Opt out by setting `typescript.declare: false`. |
|
||||
| **`outputFile`** | Control the output path and filename of Payload's auto-generated types by defining the `typescript.outputFile` property to a full, absolute path. |
|
||||
|
||||
#### Importing Payload Config types
|
||||
|
||||
You can import config types as follows:
|
||||
|
||||
```ts
|
||||
import { Config } from 'payload'
|
||||
|
||||
// This is the type used for an incoming Payload Config.
|
||||
// Only the bare minimum properties are marked as required.
|
||||
```
|
||||
|
||||
```ts
|
||||
import { SanitizedConfig } from 'payload'
|
||||
|
||||
// This is the type used after an incoming Payload Config is fully sanitized.
|
||||
// Generally, this is only used internally by Payload.
|
||||
```
|
||||
|
||||
## Config Location
|
||||
|
||||
For Payload command-line scripts, we need to be able to locate your Payload Config. We'll check a variety of locations for the presence of `payload.config.ts` by default, including the root current working directory, your `tsconfig`'s `rootDir`, and your `tsconfig`'s `outDir`.
|
||||
@@ -130,44 +174,6 @@ In addition to the above automated detection, you can specify your own location
|
||||
|
||||
When `PAYLOAD_CONFIG_PATH` is set, Payload will use this path to load the configuration, bypassing all automated detection.
|
||||
|
||||
## TypeScript
|
||||
|
||||
Payload exposes a variety of TypeScript settings that you can leverage on your Config's `typescript` property.
|
||||
|
||||
**`autoGenerate`**
|
||||
|
||||
By default, in Next.js development mode, Payload will auto-generate TypeScript interfaces for all collections and globals that your config defines.
|
||||
|
||||
You can opt out by setting `typescript.autoGenerate: false`.
|
||||
|
||||
**`declare`**
|
||||
|
||||
By default, Payload adds a `declare` block to your generated types, which makes sure that Payload uses your generated types for all Local API methods. This promotes strong typing across all of Payload's APIs. However, if you are using your Payload Config in a monorepo sub-package, and you are using it in multiple applications, you might want to disable this automatic declaration and then manually add the `declare` block to a file that you control.
|
||||
|
||||
In these cases, you can set `typescript.declare: false` to opt out.
|
||||
|
||||
**`outputFile`**
|
||||
|
||||
You can control the output path and filename of Payload's auto-generated types by defining the `typescript.outputFile` property to a full, absolute path.
|
||||
|
||||
### Importing Payload Config types
|
||||
|
||||
You can import config types as follows:
|
||||
|
||||
```ts
|
||||
import { Config } from 'payload'
|
||||
|
||||
// This is the type used for an incoming Payload Config.
|
||||
// Only the bare minimum properties are marked as required.
|
||||
```
|
||||
|
||||
```ts
|
||||
import { SanitizedConfig } from 'payload'
|
||||
|
||||
// This is the type used after an incoming Payload Config is fully sanitized.
|
||||
// Generally, this is only used internally by Payload.
|
||||
```
|
||||
|
||||
## Telemetry
|
||||
|
||||
Payload collects **completely anonymous** telemetry data about general usage. This data is super important to us and helps us accurately understand how we're growing and what we can do to build the software into everything that it can possibly be. The telemetry that we collect also help us demonstrate our growth in an accurate manner, which helps us as we seek investment to build and scale our team. If we can accurately demonstrate our growth, we can more effectively continue to support Payload as free and open-source software. To opt out of telemetry, you can pass `telemetry: false` within your Payload Config.
|
||||
|
||||
@@ -34,8 +34,8 @@ that will be called if for some reason the migration fails to complete successfu
|
||||
all changes that you attempt to make within the migration, and the `down` should ideally revert any changes you make.
|
||||
|
||||
For an added level of safety, migrations should leverage Payload [transactions](/docs/database/transactions). Migration
|
||||
functions should make use of the `req` by adding it to the arguments of your payload local API calls such
|
||||
as `payload.create` and database adapter methods like `payload.db.create`.
|
||||
functions should make use of the `req` by adding it to the arguments of your Payload Local API calls such
|
||||
as `payload.create` and Database Adapter methods like `payload.db.create`.
|
||||
|
||||
Here is an example migration file:
|
||||
|
||||
@@ -127,7 +127,7 @@ npm run payload migrate:fresh
|
||||
|
||||
## When to run migrations
|
||||
|
||||
Depending on which database adapter you use, your migration workflow might differ subtly.
|
||||
Depending on which Database Adapter you use, your migration workflow might differ subtly.
|
||||
|
||||
In relational databases, migrations will be **required** for non-development database environments. But with MongoDB, you might only need to run migrations once in a while (or never even need them).
|
||||
|
||||
@@ -139,7 +139,7 @@ In this case, you can create a migration by running `pnpm payload migrate:create
|
||||
|
||||
#### Postgres
|
||||
|
||||
In relational databases like Postgres, migrations are a bit more important, because each time you add a new field or a new collection, you'll need to update the shape of your database to match your Payload config (otherwise you'll see errors upon trying to read / write your data).
|
||||
In relational databases like Postgres, migrations are a bit more important, because each time you add a new field or a new collection, you'll need to update the shape of your database to match your Payload Config (otherwise you'll see errors upon trying to read / write your data).
|
||||
|
||||
That means that Postgres users of Payload should become familiar with the entire migration workflow from top to bottom.
|
||||
|
||||
@@ -167,14 +167,14 @@ But importantly, you do not need to run migrations against your development data
|
||||
|
||||
**2 - create a migration**
|
||||
|
||||
Once you're done with working in your Payload config, you can create a migration. It's best practice to try and complete a specific task or fully build out a feature before you create a migration.
|
||||
Once you're done with working in your Payload Config, you can create a migration. It's best practice to try and complete a specific task or fully build out a feature before you create a migration.
|
||||
|
||||
But once you're ready, you can run `pnpm payload migrate:create`, which will perform the following steps for you:
|
||||
|
||||
- We will look for any existing migrations, and automatically generate SQL changes necessary to convert your schema from its prior state to the new state of your Payload config
|
||||
- We will look for any existing migrations, and automatically generate SQL changes necessary to convert your schema from its prior state to the new state of your Payload Config
|
||||
- We will then create a new migration file in your `/migrations` folder that contains all the SQL necessary to be run
|
||||
|
||||
We won't immediately run this migration for you, however.
|
||||
We won't immediately run this migration for you, however.
|
||||
|
||||
<Banner type="success">
|
||||
Tip: migrations created by Payload are relatively programmatic in nature, so there should not be any surprises, but before you check in the created migration it's a good idea to always double-check the contents of the migration files.
|
||||
@@ -210,4 +210,4 @@ In the example above, we've specified a `ci` script which we can use as our "bui
|
||||
|
||||
This will require that your build pipeline can connect to your database, and it will simply run the `payload migrate` command prior to starting the build process. By calling `payload migrate`, Payload will automatically execute any migrations in your `/migrations` folder that have not yet been executed against your production database, in the order that they were created.
|
||||
|
||||
If it fails, the deployment will be rejected. But now, with your build script set up to run your migrations, you will be all set! Next time you deploy, your CI will execute the required migrations for you, and your database will be caught up with the shape that your Payload config requires.
|
||||
If it fails, the deployment will be rejected. But now, with your build script set up to run your migrations, you will be all set! Next time you deploy, your CI will execute the required migrations for you, and your database will be caught up with the shape that your Payload Config requires.
|
||||
|
||||
@@ -9,7 +9,7 @@ keywords: MongoDB, documentation, typescript, Content Management System, cms, he
|
||||
To use Payload with MongoDB, install the package `@payloadcms/db-mongodb`. It will come with everything you need to
|
||||
store your Payload data in MongoDB.
|
||||
|
||||
Then from there, pass it to your Payload config as follows:
|
||||
Then from there, pass it to your Payload Config as follows:
|
||||
|
||||
```ts
|
||||
import { mongooseAdapter } from '@payloadcms/db-mongodb'
|
||||
|
||||
@@ -6,20 +6,45 @@ keywords: database, mongodb, postgres, documentation, Content Management System,
|
||||
desc: With Payload, you bring your own database and own your data. You have full control.
|
||||
---
|
||||
|
||||
Payload interacts with your database via the database adapter that you choose. Right now, Payload officially supports two database adapters:
|
||||
Payload is database agnostic, meaning you can use any type of database behind Payload's familiar APIs. Payload is designed to interact with your database through a Database Adapter, which is a thin layer that translates Payload's internal data structures into your database's native data structures.
|
||||
|
||||
1. [MongoDB](/docs/database/mongodb) w/ [Mongoose](https://mongoosejs.com/)
|
||||
1. [Postgres](/docs/database/postgres) w/ [Drizzle](https://drizzle.team/)
|
||||
Currently, Payload officially supports the following Database Adapters:
|
||||
|
||||
We will be adding support for SQLite and MySQL in the near future using Drizzle ORM.
|
||||
- [MongoDB](/docs/database/mongodb) with [Mongoose](https://mongoosejs.com/)
|
||||
- [Postgres](/docs/database/postgres) with [Drizzle](https://drizzle.team/)
|
||||
- Coming soon: SQLite and MySQL using Drizzle.
|
||||
|
||||
To use a specific database adapter, you need to install it and configure it according to its own specifications. Visit the documentation for your applicable database adapter to learn more.
|
||||
To configure a Database Adapter, use the `db` property in your [Payload Config](../configuration/overview):
|
||||
|
||||
## Selecting a database
|
||||
```ts
|
||||
import { buildConfig } from 'payload'
|
||||
import { mongooseAdapter } from '@payloadcms/db-mongodb'
|
||||
|
||||
export default buildConfig({
|
||||
// ...
|
||||
// highlight-start
|
||||
db: mongooseAdapter({
|
||||
url: process.env.DATABASE_URI,
|
||||
}),
|
||||
// highlight-end
|
||||
})
|
||||
```
|
||||
|
||||
<Banner type="warning">
|
||||
<strong>Reminder:</strong>
|
||||
The Database Adapter is an external dependency and must be installed in your project separately from Payload. You can find the installation instructions for each Database Adapter in their respective documentation.
|
||||
</Banner>
|
||||
|
||||
## Selecting a Database
|
||||
|
||||
There are several factors to consider when choosing which database technology and hosting option is right for your project and workload. Payload can theoretically support any database, but it's up to you to decide which database to use.
|
||||
|
||||
### When to use MongoDB
|
||||
There are two main categories of databases to choose from:
|
||||
|
||||
- [Non-Relational Databases](#non-relational-databases)
|
||||
- [Relational Databases](#relational-databases)
|
||||
|
||||
### Non-Relational Databases
|
||||
|
||||
If your project has a lot of dynamic fields, and you are comfortable with allowing Payload to enforce data integrity across your documents, MongoDB is a great choice. With it, your Payload documents are stored as _one_ document in your database—no matter if you have localization enabled, how many block or array fields you have, etc. This means that the shape of your data in your database will very closely reflect your field schema, and there is minimal complexity involved in storing or retrieving your data.
|
||||
|
||||
@@ -27,47 +52,21 @@ You should prefer MongoDB if:
|
||||
|
||||
- You prefer simplicity within your database
|
||||
- You don't want to deal with keeping production / staging databases in sync via [DDL changes](https://en.wikipedia.org/wiki/Data_definition_language)
|
||||
- Most (or everything) in your project is localized
|
||||
- You leverage a lot of array fields, block fields, or `hasMany` select fields and similar
|
||||
- Most (or everything) in your project is [Localized](../configuration/localization)
|
||||
- You leverage a lot of [Arrays](../fields/array), [Blocks](../fields/blocks), or `hasMany` [Select](../fields/select) fields
|
||||
|
||||
### When to use a relational DB
|
||||
### Relational Databases
|
||||
|
||||
Many projects might call for more rigid database architecture where the shape of your data is strongly enforced at the database level. For example, if you know the shape of your data and it's relatively "flat", and you don't anticipate it to change often, your workload might suit relational databases like Postgres very well.
|
||||
|
||||
You should prefer a relational DB like Postgres if:
|
||||
|
||||
- You are comfortable with migration workflows
|
||||
- You are comfortable with [Migrations](./migrations)
|
||||
- You require enforced data consistency at the database level
|
||||
- You have a lot of relationships between collections and require relationships to be enforced
|
||||
|
||||
### Differences in Payload features
|
||||
## Payload Differences
|
||||
|
||||
It's important to note that almost everything Payload does is available in all of our officially supported database adapters, including localization, arrays, blocks, etc.
|
||||
It's important to note that nearly every Payload feature is available in all of our officially supported Database Adapters, including [Localization](../configuration/localization), [Arrays](../fields/array), [Blocks](../fields/blocks), etc. The only thing that is not supported in Postgres yet is the [Point Field](/docs/fields/point), but that should be added soon.
|
||||
|
||||
The only thing that is not supported in Postgres yet is the [Point field](/docs/fields/point), but that should be added soon.
|
||||
|
||||
It's up to you to choose which database you would like to use.
|
||||
|
||||
## Configuration
|
||||
|
||||
To configure the database for your Payload application, an adapter can be assigned to `config.db`. This property is required within your Payload config.
|
||||
|
||||
Here's an example:
|
||||
|
||||
```ts
|
||||
import { postgresAdapter } from '@payloadcms/db-postgres'
|
||||
|
||||
export default buildConfig({
|
||||
// Your config goes here
|
||||
collections: [
|
||||
// Collections go here
|
||||
],
|
||||
// Here is where you pass your database adapter
|
||||
// and the adapter will require options specific to itself
|
||||
db: postgresAdapter({
|
||||
pool: {
|
||||
connectionString: process.env.DATABASE_URI,
|
||||
},
|
||||
}),
|
||||
})
|
||||
```
|
||||
It's up to you to choose which database you would like to use based on the requirements of your project. Payload has no opinion on which database you should ultimately choose.
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
title: Postgres
|
||||
label: Postgres
|
||||
order: 50
|
||||
desc: Payload supports Postgres through an officially supported Drizzle database adapter.
|
||||
desc: Payload supports Postgres through an officially supported Drizzle Database Adapter.
|
||||
keywords: Postgres, documentation, typescript, Content Management System, cms, headless, javascript, node, react, nextjs
|
||||
---
|
||||
|
||||
@@ -10,7 +10,7 @@ To use Payload with Postgres, install the package `@payloadcms/db-postgres`. It
|
||||
|
||||
It automatically manages changes to your database for you in development mode, and exposes a full suite of migration controls for you to leverage in order to keep other database environments in sync with your schema. DDL transformations are automatically generated.
|
||||
|
||||
To configure Payload to use Postgres, pass the `postgresAdapter` to your Payload config as follows:
|
||||
To configure Payload to use Postgres, pass the `postgresAdapter` to your Payload Config as follows:
|
||||
|
||||
```ts
|
||||
import { postgresAdapter } from '@payloadcms/db-postgres'
|
||||
@@ -68,11 +68,11 @@ In addition to exposing Drizzle directly, all of the tables, Drizzle relations,
|
||||
|
||||
Drizzle exposes two ways to work locally in development mode.
|
||||
|
||||
The first is [`db push`](https://orm.drizzle.team/kit-docs/overview#prototyping-with-db-push), which automatically pushes changes you make to your Payload config (and therefore, Drizzle schema) to your database so you don't have to manually migrate every time you change your Payload config. This only works in development mode, and should not be mixed with manually running [`migrate`](/docs/database/migrations) commands.
|
||||
The first is [`db push`](https://orm.drizzle.team/kit-docs/overview#prototyping-with-db-push), which automatically pushes changes you make to your Payload Config (and therefore, Drizzle schema) to your database so you don't have to manually migrate every time you change your Payload Config. This only works in development mode, and should not be mixed with manually running [`migrate`](/docs/database/migrations) commands.
|
||||
|
||||
You will be warned if any changes that you make will entail data loss while in development mode. Push is enabled by default, but you can opt out if you'd like.
|
||||
|
||||
Alternatively, you can disable `push` and rely solely on migrations to keep your local database in sync with your Payload config.
|
||||
Alternatively, you can disable `push` and rely solely on migrations to keep your local database in sync with your Payload Config.
|
||||
|
||||
## Migration workflows
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ keywords: email, overview, config, configuration, documentation, Content Managem
|
||||
|
||||
Payload has a few email adapters that can be imported to enable email functionality. The [@payloadcms/email-nodemailer](https://www.npmjs.com/package/@payloadcms/email-nodemailer) package will be the package most will want to install. This package provides an easy way to use [Nodemailer](https://nodemailer.com) for email and won't get in your way for those already familiar.
|
||||
|
||||
The email adapter should be passed into the `email` property of the Payload config. This will allow Payload to send emails for things like password resets, new user verification, and any other email sending needs you may have.
|
||||
The email adapter should be passed into the `email` property of the Payload Config. This will allow Payload to send emails for things like password resets, new user verification, and any other email sending needs you may have.
|
||||
|
||||
## Configuration
|
||||
|
||||
@@ -49,7 +49,7 @@ Simple Mail Transfer Protocol (SMTP) options can be passed in using the `transpo
|
||||
**Example email options using SMTP:**
|
||||
|
||||
```ts
|
||||
import { buildConfig } from 'payload/config'
|
||||
import { buildConfig } from 'payload'
|
||||
import { nodemailerAdapter } from '@payloadcms/email-nodemailer'
|
||||
|
||||
export default buildConfig({
|
||||
@@ -72,7 +72,7 @@ export default buildConfig({
|
||||
**Example email options using nodemailer.createTransport:**
|
||||
|
||||
```ts
|
||||
import { buildConfig } from 'payload/config'
|
||||
import { buildConfig } from 'payload'
|
||||
import { nodemailerAdapter } from '@payloadcms/email-nodemailer'
|
||||
import nodemailer from 'nodemailer'
|
||||
|
||||
@@ -99,7 +99,7 @@ You also have the ability to bring your own nodemailer transport. This is an exa
|
||||
|
||||
|
||||
```ts
|
||||
import { buildConfig } from 'payload/config'
|
||||
import { buildConfig } from 'payload'
|
||||
import { nodemailerAdapter } from '@payloadcms/email-nodemailer'
|
||||
import nodemailerSendgrid from 'nodemailer-sendgrid'
|
||||
|
||||
@@ -136,7 +136,7 @@ The Resend adapter requires an API key to be passed in the options. This can be
|
||||
| apiKey | The API key for the Resend service. |
|
||||
|
||||
```ts
|
||||
import { buildConfig } from 'payload/config'
|
||||
import { buildConfig } from 'payload'
|
||||
import { resendAdapter } from '@payloadcms/email-resend'
|
||||
|
||||
export default buildConfig({
|
||||
@@ -150,7 +150,7 @@ export default buildConfig({
|
||||
|
||||
## Sending Mail
|
||||
|
||||
With a working transport you can call it anywhere you have access to payload by calling `payload.sendEmail(message)`. The `message` will contain the `to`, `subject` and `html` or `text` for the email being sent. Other options are also available and can be seen in the sendEmail args. Support for these will depend on the adapter being used.
|
||||
With a working transport you can call it anywhere you have access to Payload by calling `payload.sendEmail(message)`. The `message` will contain the `to`, `subject` and `html` or `text` for the email being sent. Other options are also available and can be seen in the sendEmail args. Support for these will depend on the adapter being used.
|
||||
|
||||
```ts
|
||||
// Example of sending an email
|
||||
|
||||
@@ -14,7 +14,7 @@ keywords: array, fields, config, configuration, documentation, Content Managemen
|
||||
<LightDarkImage
|
||||
srcLight="https://payloadcms.com/images/docs/fields/array.png"
|
||||
srcDark="https://payloadcms.com/images/docs/fields/array-dark.png"
|
||||
alt="Array field with two Rows in Payload admin panel"
|
||||
alt="Array field with two Rows in Payload Admin Panel"
|
||||
caption="Admin Panel screenshot of an Array field with two Rows"
|
||||
/>
|
||||
|
||||
@@ -45,7 +45,7 @@ keywords: array, fields, config, configuration, documentation, Content Managemen
|
||||
| **`admin`** | Admin-specific configuration. See below for [more detail](#admin-config). |
|
||||
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
|
||||
| **`interfaceName`** | Create a top level, reusable [Typescript interface](/docs/typescript/generating-types#custom-field-interfaces) & [GraphQL type](/docs/graphql/graphql-schema#custom-field-schemas). |
|
||||
| **`dbName`** | Custom table name for the field when using SQL database adapter ([Postgres](/docs/database/postgres)). Auto-generated from name if not defined. |
|
||||
| **`dbName`** | Custom table name for the field when using SQL Database Adapter ([Postgres](/docs/database/postgres)). Auto-generated from name if not defined. |
|
||||
| **`typescriptSchema`** | Override field type generation with providing a JSON schema |
|
||||
|
||||
_\* An asterisk denotes that a property is required._
|
||||
@@ -65,7 +65,7 @@ In addition to the default [field admin config](/docs/fields/overview#admin-conf
|
||||
`collections/ExampleCollection.ts`
|
||||
|
||||
```ts
|
||||
import { CollectionConfig } from 'payload/types'
|
||||
import { CollectionConfig } from 'payload'
|
||||
|
||||
export const ExampleCollection: CollectionConfig = {
|
||||
slug: 'example-collection',
|
||||
|
||||
@@ -82,7 +82,7 @@ Blocks are defined as separate configs of their own.
|
||||
| **`imageAltText`** | Customize this block's image thumbnail alt text. |
|
||||
| **`interfaceName`** | Create a top level, reusable [Typescript interface](/docs/typescript/generating-types#custom-field-interfaces) & [GraphQL type](/docs/graphql/graphql-schema#custom-field-schemas). |
|
||||
| **`graphQL.singularName`** | Text to use for the GraphQL schema name. Auto-generated from slug if not defined. NOTE: this is set for deprecation, prefer `interfaceName`. |
|
||||
| **`dbName`** | Custom table name for this block type when using SQL database adapter ([Postgres](/docs/database/postgres)). Auto-generated from slug if not defined.
|
||||
| **`dbName`** | Custom table name for this block type when using SQL Database Adapter ([Postgres](/docs/database/postgres)). Auto-generated from slug if not defined.
|
||||
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
|
||||
|
||||
### Auto-generated data per block
|
||||
@@ -102,7 +102,7 @@ The Admin Panel provides each block with a `blockName` field which optionally al
|
||||
`collections/ExampleCollection.js`
|
||||
|
||||
```ts
|
||||
import { Block, CollectionConfig } from 'payload/types'
|
||||
import { Block, CollectionConfig } from 'payload'
|
||||
|
||||
const QuoteBlock: Block = {
|
||||
slug: 'Quote', // required
|
||||
@@ -145,5 +145,5 @@ export const ExampleCollection: CollectionConfig = {
|
||||
As you build your own Block configs, you might want to store them in separate files but retain typing accordingly. To do so, you can import and use Payload's `Block` type:
|
||||
|
||||
```ts
|
||||
import type { Block } from 'payload/types'
|
||||
import type { Block } from 'payload'
|
||||
```
|
||||
|
||||
@@ -11,7 +11,7 @@ keywords: checkbox, fields, config, configuration, documentation, Content Manage
|
||||
<LightDarkImage
|
||||
srcLight="https://payloadcms.com/images/docs/fields/checkbox.png"
|
||||
srcDark="https://payloadcms.com/images/docs/fields/checkbox-dark.png"
|
||||
alt="Checkbox field with text field in Payload admin panel"
|
||||
alt="Checkbox field with text field in Payload Admin Panel"
|
||||
caption="Admin Panel screenshot of Checkbox field with Text field below"
|
||||
/>
|
||||
|
||||
@@ -41,7 +41,7 @@ _\* An asterisk denotes that a property is required._
|
||||
`collections/ExampleCollection.ts`
|
||||
|
||||
```ts
|
||||
import { CollectionConfig } from 'payload/types'
|
||||
import { CollectionConfig } from 'payload'
|
||||
|
||||
export const ExampleCollection: CollectionConfig = {
|
||||
slug: 'example-collection',
|
||||
|
||||
@@ -15,7 +15,7 @@ keywords: code, fields, config, configuration, documentation, Content Management
|
||||
<LightDarkImage
|
||||
srcLight="https://payloadcms.com/images/docs/fields/code.png"
|
||||
srcDark="https://payloadcms.com/images/docs/fields/code-dark.png"
|
||||
alt="Shows a Code field in the Payload admin panel"
|
||||
alt="Shows a Code field in the Payload Admin Panel"
|
||||
caption="Admin Panel screenshot of a Code field"
|
||||
/>
|
||||
|
||||
@@ -59,7 +59,7 @@ In addition to the default [field admin config](/docs/fields/overview#admin-conf
|
||||
`collections/ExampleCollection.ts
|
||||
|
||||
```ts
|
||||
import { CollectionConfig } from 'payload/types'
|
||||
import { CollectionConfig } from 'payload'
|
||||
|
||||
export const ExampleCollection: CollectionConfig = {
|
||||
slug: 'example-collection',
|
||||
|
||||
@@ -14,7 +14,7 @@ keywords: row, fields, config, configuration, documentation, Content Management
|
||||
<LightDarkImage
|
||||
srcLight="https://payloadcms.com/images/docs/fields/collapsible.png"
|
||||
srcDark="https://payloadcms.com/images/docs/fields/collapsible-dark.png"
|
||||
alt="Shows a Collapsible field in the Payload admin panel"
|
||||
alt="Shows a Collapsible field in the Payload Admin Panel"
|
||||
caption="Admin Panel screenshot of a Collapsible field"
|
||||
/>
|
||||
|
||||
@@ -42,7 +42,7 @@ In addition to the default [field admin config](/docs/fields/overview#admin-conf
|
||||
`collections/ExampleCollection.ts`
|
||||
|
||||
```ts
|
||||
import { CollectionConfig } from 'payload/types'
|
||||
import { CollectionConfig } from 'payload'
|
||||
|
||||
export const ExampleCollection: CollectionConfig = {
|
||||
slug: 'example-collection',
|
||||
|
||||
@@ -14,7 +14,7 @@ keywords: date, fields, config, configuration, documentation, Content Management
|
||||
<LightDarkImage
|
||||
srcLight="https://payloadcms.com/images/docs/fields/date.png"
|
||||
srcDark="https://payloadcms.com/images/docs/fields/date-dark.png"
|
||||
alt="Shows a Date field in the Payload admin panel"
|
||||
alt="Shows a Date field in the Payload Admin Panel"
|
||||
caption="Admin Panel screenshot of a Date field"
|
||||
/>
|
||||
|
||||
@@ -43,7 +43,7 @@ _\* An asterisk denotes that a property is required._
|
||||
|
||||
## Admin Config
|
||||
|
||||
In addition to the default [field admin config](/docs/fields/overview#admin-config), you can customize the following fields that will adjust how the component displays in the admin panel via the `date` property.
|
||||
In addition to the default [field admin config](/docs/fields/overview#admin-config), you can customize the following fields that will adjust how the component displays in the Admin Panel via the `date` property.
|
||||
|
||||
| Property | Description |
|
||||
| ------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
@@ -77,7 +77,7 @@ When only `pickerAppearance` is set, an equivalent format will be rendered in th
|
||||
`collections/ExampleCollection.ts`
|
||||
|
||||
```ts
|
||||
import { CollectionConfig } from 'payload/types'
|
||||
import { CollectionConfig } from 'payload'
|
||||
|
||||
export const ExampleCollection: CollectionConfig = {
|
||||
slug: 'example-collection',
|
||||
|
||||
@@ -11,7 +11,7 @@ keywords: email, fields, config, configuration, documentation, Content Managemen
|
||||
<LightDarkImage
|
||||
srcLight="https://payloadcms.com/images/docs/fields/email.png"
|
||||
srcDark="https://payloadcms.com/images/docs/fields/email-dark.png"
|
||||
alt="Shows an Email field in the Payload admin panel"
|
||||
alt="Shows an Email field in the Payload Admin Panel"
|
||||
caption="Admin Panel screenshot of an Email field"
|
||||
/>
|
||||
|
||||
@@ -54,7 +54,7 @@ Set this property to a string that will be used for browser autocomplete.
|
||||
`collections/ExampleCollection.ts`
|
||||
|
||||
```ts
|
||||
import { CollectionConfig } from 'payload/types'
|
||||
import { CollectionConfig } from 'payload'
|
||||
|
||||
export const ExampleCollection: CollectionConfig = {
|
||||
slug: 'example-collection',
|
||||
|
||||
@@ -14,7 +14,7 @@ keywords: group, fields, config, configuration, documentation, Content Managemen
|
||||
<LightDarkImage
|
||||
srcLight="https://payloadcms.com/images/docs/fields/group.png"
|
||||
srcDark="https://payloadcms.com/images/docs/fields/group-dark.png"
|
||||
alt="Shows a Group field in the Payload admin panel"
|
||||
alt="Shows a Group field in the Payload Admin Panel"
|
||||
caption="Admin Panel screenshot of a Group field"
|
||||
/>
|
||||
|
||||
@@ -45,14 +45,14 @@ In addition to the default [field admin config](/docs/fields/overview#admin-conf
|
||||
|
||||
**`hideGutter`**
|
||||
|
||||
Set this property to `true` to hide this field's gutter within the admin panel. The field gutter is rendered as a vertical line and padding, but often if this field is nested within a Group, Block, or Array, you may want to hide the gutter.
|
||||
Set this property to `true` to hide this field's gutter within the Admin Panel. The field gutter is rendered as a vertical line and padding, but often if this field is nested within a Group, Block, or Array, you may want to hide the gutter.
|
||||
|
||||
## Example
|
||||
|
||||
`collections/ExampleCollection.ts`
|
||||
|
||||
```ts
|
||||
import { CollectionConfig } from 'payload/types'
|
||||
import { CollectionConfig } from 'payload'
|
||||
|
||||
export const ExampleCollection: CollectionConfig = {
|
||||
slug: 'example-collection',
|
||||
|
||||
@@ -15,7 +15,7 @@ keywords: json, jsonSchema, schema, validation, fields, config, configuration, d
|
||||
<LightDarkImage
|
||||
srcLight="https://payloadcms.com/images/docs/fields/json.png"
|
||||
srcDark="https://payloadcms.com/images/docs/fields/json-dark.png"
|
||||
alt="Shows a JSON field in the Payload admin panel"
|
||||
alt="Shows a JSON field in the Payload Admin Panel"
|
||||
caption="Admin Panel screenshot of a JSON field"
|
||||
/>
|
||||
|
||||
@@ -57,7 +57,7 @@ In addition to the default [field admin config](/docs/fields/overview#admin-conf
|
||||
`collections/ExampleCollection.ts`
|
||||
|
||||
```ts
|
||||
import { CollectionConfig } from 'payload/types'
|
||||
import { CollectionConfig } from 'payload'
|
||||
|
||||
export const ExampleCollection: CollectionConfig = {
|
||||
slug: 'example-collection',
|
||||
@@ -82,7 +82,7 @@ If you only provide a URL to a schema, Payload will fetch the desired schema if
|
||||
`collections/ExampleCollection.ts`
|
||||
|
||||
```ts
|
||||
import { CollectionConfig } from 'payload/types'
|
||||
import { CollectionConfig } from 'payload'
|
||||
|
||||
export const ExampleCollection: CollectionConfig = {
|
||||
slug: 'example-collection',
|
||||
@@ -115,7 +115,7 @@ export const ExampleCollection: CollectionConfig = {
|
||||
`collections/ExampleCollection.ts`
|
||||
|
||||
```ts
|
||||
import { CollectionConfig } from 'payload/types'
|
||||
import { CollectionConfig } from 'payload'
|
||||
|
||||
export const ExampleCollection: CollectionConfig = {
|
||||
slug: 'example-collection',
|
||||
|
||||
@@ -14,7 +14,7 @@ keywords: number, fields, config, configuration, documentation, Content Manageme
|
||||
<LightDarkImage
|
||||
srcLight="https://payloadcms.com/images/docs/fields/number.png"
|
||||
srcDark="https://payloadcms.com/images/docs/fields/number-dark.png"
|
||||
alt="Shows a Number field in the Payload admin panel"
|
||||
alt="Shows a Number field in the Payload Admin Panel"
|
||||
caption="Admin Panel screenshot of a Number field"
|
||||
/>
|
||||
|
||||
@@ -66,7 +66,7 @@ Set this property to a string that will be used for browser autocomplete.
|
||||
`collections/ExampleCollection.ts`
|
||||
|
||||
```ts
|
||||
import { CollectionConfig } from 'payload/types'
|
||||
import { CollectionConfig } from 'payload'
|
||||
|
||||
export const ExampleCollection: CollectionConfig = {
|
||||
slug: 'example-collection',
|
||||
|
||||
@@ -6,9 +6,22 @@ desc: Fields are the building blocks of Payload, find out how to add or remove a
|
||||
keywords: overview, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
|
||||
---
|
||||
|
||||
Fields are the building blocks of Payload. Both [Collections](../configuration/collections) and [Globals](../configuration/globals) use fields to define the shape of the data that will be stored in the [Database](../database/overview), as well as automatically generate the corresponding UI within the [Admin Panel](../admin/overview).
|
||||
Fields are the building blocks of Payload. They define the schema of the Documents that will be stored in the [Database](../database/overview), as well as automatically generate the corresponding UI within the [Admin Panel](../admin/overview).
|
||||
|
||||
There are many [Field Types](#field-types) to choose from, ranging anywhere from simple text strings to nested arrays and blocks. Most fields save data to the database, while others are strictly presentational. Fields can have [Custom Validations](#validations), [Conditional Logic](../admin/fields#conditional-logic), [Access Control](#field-level-access-control), [Hooks](#field-level-hooks), and so much more.
|
||||
There are many [Field Types](#field-types) to choose from, ranging anywhere from simple text strings to nested arrays and blocks. Most fields save data to the database, while others are strictly presentational. Fields can have [Custom Validations](#validation), [Conditional Logic](../admin/fields#conditional-logic), [Access Control](#field-level-access-control), [Hooks](#field-level-hooks), and so much more.
|
||||
|
||||
To configure fields, use the `fields` property in your [Collection](../configuration/collections) or [Global](../configuration/globals) config:
|
||||
|
||||
```ts
|
||||
import type { CollectionConfig } from 'payload'
|
||||
|
||||
export const Page: CollectionConfig = {
|
||||
// ...
|
||||
fields: [ // highlight-line
|
||||
// ...
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
<Banner type="success">
|
||||
You can fully customize the appearance and behavior of all fields within the Admin Panel. [More details](../admin/fields).
|
||||
@@ -130,6 +143,7 @@ The following field names are forbidden and cannot be used:
|
||||
- `__v`
|
||||
- `salt`
|
||||
- `hash`
|
||||
- `file`
|
||||
|
||||
### Field-level Hooks
|
||||
|
||||
@@ -221,7 +235,7 @@ export const myField: Field = {
|
||||
You can use async `defaultValue` functions to fill fields with data from API requests.
|
||||
</Banner>
|
||||
|
||||
### Validations
|
||||
### Validation
|
||||
|
||||
Fields are automatically validated based on their [Field Type](#field-types) and other [Field Options](#field-options) such as `required` or `min` and `max` value constraints. If needed, however, field validations can be customized or entirely replaced by providing your own custom validation functions.
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ keywords: point, geolocation, geospatial, geojson, 2dsphere, config, configurati
|
||||
<LightDarkImage
|
||||
srcLight="https://payloadcms.com/images/docs/fields/point.png"
|
||||
srcDark="https://payloadcms.com/images/docs/fields/point-dark.png"
|
||||
alt="Shows a Point field in the Payload admin panel"
|
||||
alt="Shows a Point field in the Payload Admin Panel"
|
||||
caption="Admin Panel screenshot of a Point field"
|
||||
/>
|
||||
|
||||
@@ -56,7 +56,7 @@ _\* An asterisk denotes that a property is required._
|
||||
`collections/ExampleCollection.ts`
|
||||
|
||||
```ts
|
||||
import { CollectionConfig } from 'payload/types'
|
||||
import { CollectionConfig } from 'payload'
|
||||
|
||||
export const ExampleCollection: CollectionConfig = {
|
||||
slug: 'example-collection',
|
||||
|
||||
@@ -14,7 +14,7 @@ keywords: radio, fields, config, configuration, documentation, Content Managemen
|
||||
<LightDarkImage
|
||||
srcLight="https://payloadcms.com/images/docs/fields/radio.png"
|
||||
srcDark="https://payloadcms.com/images/docs/fields/radio-dark.png"
|
||||
alt="Shows a Radio field in the Payload admin panel"
|
||||
alt="Shows a Radio field in the Payload Admin Panel"
|
||||
caption="Admin Panel screenshot of a Radio field"
|
||||
/>
|
||||
|
||||
@@ -36,7 +36,7 @@ keywords: radio, fields, config, configuration, documentation, Content Managemen
|
||||
| **`required`** | Require this field to have a value. |
|
||||
| **`admin`** | Admin-specific configuration. See below for [more detail](#admin-config). |
|
||||
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
|
||||
| **`enumName`** | Custom enum name for this field when using SQL database adapter ([Postgres](/docs/database/postgres)). Auto-generated from name if not defined. |
|
||||
| **`enumName`** | Custom enum name for this field when using SQL Database Adapter ([Postgres](/docs/database/postgres)). Auto-generated from name if not defined. |
|
||||
| **`typescriptSchema`** | Override field type generation with providing a JSON schema |
|
||||
|
||||
_\* An asterisk denotes that a property is required._
|
||||
@@ -63,7 +63,7 @@ The `layout` property allows for the radio group to be styled as a horizonally o
|
||||
`collections/ExampleCollection.ts`
|
||||
|
||||
```ts
|
||||
import { CollectionConfig } from 'payload/types'
|
||||
import { CollectionConfig } from 'payload'
|
||||
|
||||
export const ExampleCollection: CollectionConfig = {
|
||||
slug: 'example-collection',
|
||||
|
||||
@@ -14,7 +14,7 @@ keywords: relationship, fields, config, configuration, documentation, Content Ma
|
||||
<LightDarkImage
|
||||
srcLight="https://payloadcms.com/images/docs/fields/relationship.png"
|
||||
srcDark="https://payloadcms.com/images/docs/fields/relationship-dark.png"
|
||||
alt="Shows a relationship field in the Payload admin panel"
|
||||
alt="Shows a relationship field in the Payload Admin Panel"
|
||||
caption="Admin Panel screenshot of a Relationship field"
|
||||
/>
|
||||
|
||||
@@ -55,7 +55,7 @@ _\* An asterisk denotes that a property is required._
|
||||
<Banner type="success">
|
||||
<strong>Tip:</strong>
|
||||
<br />
|
||||
The [Depth](/docs/getting-started/concepts#depth) parameter can be used to automatically populate
|
||||
The [Depth](../queries/depth) parameter can be used to automatically populate
|
||||
related documents that are returned by the API.
|
||||
</Banner>
|
||||
|
||||
@@ -143,7 +143,7 @@ called with an argument object with the following properties:
|
||||
## Example
|
||||
|
||||
```ts
|
||||
import { CollectionConfig } from 'payload/types'
|
||||
import { CollectionConfig } from 'payload'
|
||||
|
||||
export const ExampleCollection: CollectionConfig = {
|
||||
slug: 'example-collection',
|
||||
|
||||
@@ -14,7 +14,7 @@ keywords: rich text, fields, config, configuration, documentation, Content Manag
|
||||
<LightDarkImage
|
||||
srcLight="https://payloadcms.com/images/docs/fields/richtext.png"
|
||||
srcDark="https://payloadcms.com/images/docs/fields/richtext-dark.png"
|
||||
alt="Shows a Rich Text field in the Payload admin panel"
|
||||
alt="Shows a Rich Text field in the Payload Admin Panel"
|
||||
caption="Admin Panel screenshot of a Rich Text field"
|
||||
/>
|
||||
|
||||
@@ -70,7 +70,7 @@ Set this property to define a placeholder string in the text input.
|
||||
|
||||
**`hideGutter`**
|
||||
|
||||
Set this property to `true` to hide this field's gutter within the admin panel. The field gutter is rendered as a vertical line and padding, but often if this field is nested within a Group, Block, or Array, you may want to hide the gutter.
|
||||
Set this property to `true` to hide this field's gutter within the Admin Panel. The field gutter is rendered as a vertical line and padding, but often if this field is nested within a Group, Block, or Array, you may want to hide the gutter.
|
||||
|
||||
**`rtl`**
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ keywords: row, fields, config, configuration, documentation, Content Management
|
||||
<LightDarkImage
|
||||
srcLight="https://payloadcms.com/images/docs/fields/row.png"
|
||||
srcDark="https://payloadcms.com/images/docs/fields/row-dark.png"
|
||||
alt="Shows a row field in the Payload admin panel"
|
||||
alt="Shows a row field in the Payload Admin Panel"
|
||||
caption="Admin Panel screenshot of a Row field"
|
||||
/>
|
||||
|
||||
@@ -33,7 +33,7 @@ _\* An asterisk denotes that a property is required._
|
||||
`collections/ExampleCollection.ts`
|
||||
|
||||
```ts
|
||||
import { CollectionConfig } from 'payload/types'
|
||||
import { CollectionConfig } from 'payload'
|
||||
|
||||
export const ExampleCollection: CollectionConfig = {
|
||||
slug: 'example-collection',
|
||||
|
||||
@@ -14,7 +14,7 @@ keywords: select, multi-select, fields, config, configuration, documentation, Co
|
||||
<LightDarkImage
|
||||
srcLight="https://payloadcms.com/images/docs/fields/select.png"
|
||||
srcDark="https://payloadcms.com/images/docs/fields/select-dark.png"
|
||||
alt="Shows a Select field in the Payload admin panel"
|
||||
alt="Shows a Select field in the Payload Admin Panel"
|
||||
caption="Admin Panel screenshot of a Select field"
|
||||
/>
|
||||
|
||||
@@ -38,8 +38,8 @@ keywords: select, multi-select, fields, config, configuration, documentation, Co
|
||||
| **`required`** | Require this field to have a value. |
|
||||
| **`admin`** | Admin-specific configuration. See the [default field admin config](/docs/fields/overview#admin-config) for more details. |
|
||||
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
|
||||
| **`enumName`** | Custom enum name for this field when using SQL database adapter ([Postgres](/docs/database/postgres)). Auto-generated from name if not defined. |
|
||||
| **`dbName`** | Custom table name (if `hasMany` set to `true`) for this field when using SQL database adapter ([Postgres](/docs/database/postgres)). Auto-generated from name if not defined. |
|
||||
| **`enumName`** | Custom enum name for this field when using SQL Database Adapter ([Postgres](/docs/database/postgres)). Auto-generated from name if not defined. |
|
||||
| **`dbName`** | Custom table name (if `hasMany` set to `true`) for this field when using SQL Database Adapter ([Postgres](/docs/database/postgres)). Auto-generated from name if not defined. |
|
||||
| **`typescriptSchema`** | Override field type generation with providing a JSON schema |
|
||||
|
||||
_\* An asterisk denotes that a property is required._
|
||||
@@ -70,7 +70,7 @@ Set to `true` if you'd like this field to be sortable within the Admin UI using
|
||||
`collections/ExampleCollection.ts`
|
||||
|
||||
```ts
|
||||
import { CollectionConfig } from 'payload/types'
|
||||
import { CollectionConfig } from 'payload'
|
||||
|
||||
export const ExampleCollection: CollectionConfig = {
|
||||
slug: 'example-collection',
|
||||
|
||||
@@ -15,7 +15,7 @@ keywords: tabs, fields, config, configuration, documentation, Content Management
|
||||
<LightDarkImage
|
||||
srcLight="https://payloadcms.com/images/docs/fields/tabs.png"
|
||||
srcDark="https://payloadcms.com/images/docs/fields/tabs-dark.png"
|
||||
alt="Shows a tabs field used to separate Hero and Page layout in the Payload admin panel"
|
||||
alt="Shows a tabs field used to separate Hero and Page layout in the Payload Admin Panel"
|
||||
caption="Tabs field type used to separate Hero fields from Page Layout"
|
||||
/>
|
||||
|
||||
@@ -46,7 +46,7 @@ _\* An asterisk denotes that a property is required._
|
||||
`collections/ExampleCollection.ts`
|
||||
|
||||
```ts
|
||||
import { CollectionConfig } from 'payload/types'
|
||||
import { CollectionConfig } from 'payload'
|
||||
|
||||
export const ExampleCollection: CollectionConfig = {
|
||||
slug: 'example-collection',
|
||||
|
||||
@@ -14,7 +14,7 @@ keywords: text, fields, config, configuration, documentation, Content Management
|
||||
<LightDarkImage
|
||||
srcLight="https://payloadcms.com/images/docs/fields/text.png"
|
||||
srcDark="https://payloadcms.com/images/docs/fields/text-dark.png"
|
||||
alt="Shows a text field and read-only text field in the Payload admin panel"
|
||||
alt="Shows a text field and read-only text field in the Payload Admin Panel"
|
||||
caption="Admin Panel screenshot of a Text field and read-only Text field"
|
||||
/>
|
||||
|
||||
@@ -66,7 +66,7 @@ Override the default text direction of the Admin Panel for this field. Set to `t
|
||||
`collections/ExampleCollection.ts`
|
||||
|
||||
```ts
|
||||
import { CollectionConfig } from 'payload/types'
|
||||
import { CollectionConfig } from 'payload'
|
||||
|
||||
export const ExampleCollection: CollectionConfig = {
|
||||
slug: 'example-collection',
|
||||
|
||||
@@ -14,7 +14,7 @@ keywords: textarea, fields, config, configuration, documentation, Content Manage
|
||||
<LightDarkImage
|
||||
srcLight="https://payloadcms.com/images/docs/fields/textarea.png"
|
||||
srcDark="https://payloadcms.com/images/docs/fields/textarea-dark.png"
|
||||
alt="Shows a textarea field and read-only textarea field in the Payload admin panel"
|
||||
alt="Shows a textarea field and read-only textarea field in the Payload Admin Panel"
|
||||
caption="Admin Panel screenshot of a Textarea field and read-only Textarea field"
|
||||
/>
|
||||
|
||||
@@ -63,7 +63,7 @@ Override the default text direction of the Admin Panel for this field. Set to `t
|
||||
`collections/ExampleCollection.ts`
|
||||
|
||||
```ts
|
||||
import { CollectionConfig } from 'payload/types'
|
||||
import { CollectionConfig } from 'payload'
|
||||
|
||||
export const ExampleCollection: CollectionConfig = {
|
||||
slug: 'example-collection',
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
title: UI Field
|
||||
label: UI
|
||||
order: 200
|
||||
desc: UI fields are purely presentational and allow developers to customize the admin panel to a very fine degree, including adding actions and other functions.
|
||||
desc: UI fields are purely presentational and allow developers to customize the Admin Panel to a very fine degree, including adding actions and other functions.
|
||||
keywords: custom field, react component, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
|
||||
---
|
||||
|
||||
@@ -41,7 +41,7 @@ _\* An asterisk denotes that a property is required._
|
||||
`collections/ExampleCollection.ts`
|
||||
|
||||
```ts
|
||||
import { CollectionConfig } from 'payload/types'
|
||||
import { CollectionConfig } from 'payload'
|
||||
|
||||
export const ExampleCollection: CollectionConfig = {
|
||||
slug: 'example-collection',
|
||||
|
||||
@@ -22,7 +22,7 @@ keywords: upload, images media, fields, config, configuration, documentation, Co
|
||||
<LightDarkImage
|
||||
srcLight="https://payloadcms.com/images/docs/fields/upload.png"
|
||||
srcDark="https://payloadcms.com/images/docs/fields/upload-dark.png"
|
||||
alt="Shows an upload field in the Payload admin panel"
|
||||
alt="Shows an upload field in the Payload Admin Panel"
|
||||
caption="Admin Panel screenshot of an Upload field"
|
||||
/>
|
||||
|
||||
@@ -39,7 +39,7 @@ keywords: upload, images media, fields, config, configuration, documentation, Co
|
||||
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
|
||||
| **`*relationTo`** \* | Provide a single collection `slug` to allow this field to accept a relation to. <strong>Note: the related collection must be configured to support Uploads.</strong> |
|
||||
| **`filterOptions`** | A query to filter which options appear in the UI and validate against. [More](#filtering-upload-options). |
|
||||
| **`maxDepth`** | Sets a number limit on iterations of related documents to populate when queried. [Depth](/docs/getting-started/concepts#depth) |
|
||||
| **`maxDepth`** | Sets a number limit on iterations of related documents to populate when queried. [Depth](../queries/depth) |
|
||||
| **`label`** | Text used as a field label in the Admin Panel or an object with keys for each language. |
|
||||
| **`unique`** | Enforce that each entry in the Collection has a unique value for this field. |
|
||||
| **`validate`** | Provide a custom validation function that will be executed on both the Admin Panel and the backend. [More](/docs/fields/overview#validation) |
|
||||
@@ -62,7 +62,7 @@ _\* An asterisk denotes that a property is required._
|
||||
`collections/ExampleCollection.ts`
|
||||
|
||||
```ts
|
||||
import { CollectionConfig } from 'payload/types'
|
||||
import { CollectionConfig } from 'payload'
|
||||
|
||||
export const ExampleCollection: CollectionConfig = {
|
||||
slug: 'example-collection',
|
||||
|
||||
@@ -6,72 +6,62 @@ desc: Payload is based around a small and intuitive set of concepts. Key concept
|
||||
keywords: documentation, getting started, guide, Content Management System, cms, headless, javascript, node, react, nextjs
|
||||
---
|
||||
|
||||
Payload is based around a small and intuitive set of concepts. Before starting to work with Payload, it's a good idea to familiarize yourself with the following:
|
||||
Payload is based around a small and intuitive set of high-level concepts. Before starting to work with Payload, it's a good idea to familiarize yourself with these concepts in order to establish a common language and understanding when discussing Payload.
|
||||
|
||||
## Config
|
||||
|
||||
<Banner type="info">The Payload config is where you configure everything that Payload does.</Banner>
|
||||
The Payload Config is central to everything that Payload does. It allows for the deep configuration of your application through a simple and intuitive API. The Payload Config is a fully-typed JavaScript object that can be infinitely extended upon. [More details](../configuration/overview).
|
||||
|
||||
By default, the Payload config lives in the root folder of your code and is named `payload.config.ts`, but you can customize its name and where you store it. You can write full functions and even full React components right into your config.
|
||||
## Database
|
||||
|
||||
Payload is database agnostic, meaning you can use any type of database behind Payload's familiar APIs through a Database Adapter. [More details](../database/overview).
|
||||
|
||||
## Collections
|
||||
|
||||
<Banner type="info">
|
||||
A Collection represents a type of content that Payload will store and can contain many documents.
|
||||
</Banner>
|
||||
|
||||
Collections define the shape of your data as well as all functionalities attached to that data. They will contain one or many "documents", all corresponding with the same fields and functionalities that you define.
|
||||
|
||||
They can represent anything you can store in a database - for example - pages, posts, users, people, orders, categories, events, customers, transactions, and anything else your app needs.
|
||||
A Collection is a group of records, called Documents, that all share a common schema. Each Collection saves to the [Database](../database/overview) based on the [Fields](../fields/overview) that you define. [More details](../configuration/collections).
|
||||
|
||||
## Globals
|
||||
|
||||
<Banner type="info">
|
||||
A Global is a "one-off" piece of content that is perfect for storing navigational structures,
|
||||
themes, top-level meta data, and more.
|
||||
</Banner>
|
||||
|
||||
Globals are in many ways similar to Collections, but there is only ever **one** instance of a Global, whereas Collections can contain many documents.
|
||||
Globals are in many ways similar to [Collections](../configuration/collections), except they correspond to only a single Document. Each Global saves to the [Database](../database/overview) based on the [Fields](../fields/overview) that you define. [More details](../configuration/globals).
|
||||
|
||||
## Fields
|
||||
|
||||
<Banner type="info">
|
||||
Fields are the building blocks of Payload. Collections and Globals both use Fields to define the
|
||||
shape of the data that they store.
|
||||
</Banner>
|
||||
|
||||
Payload comes with [many different field types](../fields/overview) that give you a ton of flexibility while designing your API. Each Field type has its own potential properties that allow you to customize how they work.
|
||||
Fields are the building blocks of Payload. They define the schema of the Documents that will be stored in the [Database](../database/overview), as well as automatically generate the corresponding UI within the Admin Panel. [More details](../fields/overview).
|
||||
|
||||
## Hooks
|
||||
|
||||
<Banner type="info">
|
||||
Hooks are where you can "tie in" to existing Payload actions to perform your own additional logic
|
||||
or modify how Payload operates altogether.
|
||||
</Banner>
|
||||
|
||||
Hooks are an extremely powerful concept and are central to extending and customizing your app. Payload provides a wide variety of hooks which you can utilize. For example, imagine if you'd like to send an email every time a document is created in your Orders collection. To do so, you can add an `afterChange` hook function to your Orders collection that receives the Order data and allows you to send an email accordingly.
|
||||
|
||||
There are many more potential reasons to use Hooks. For more, visit the [Hooks documentation](/docs/hooks/overview).
|
||||
Hooks allow you to execute your own logic during specific events of the Document lifecycle, such as read or update. [More details](../hooks/overview).
|
||||
|
||||
## Access Control
|
||||
|
||||
<Banner type="info">
|
||||
Access Control refers to Payload's system of defining who can do what to your API.
|
||||
</Banner>
|
||||
Access Control determines what a user can and cannot do with any given Document. [More details](../access-control/overview).
|
||||
|
||||
Access Control is extremely powerful but easy and intuitive to manage. You can easily define your own full-blown RBAC (role-based access control) or any other access control pattern that your scenario requires. No conventions or structure is forced on you whatsoever.
|
||||
## Admin Panel
|
||||
|
||||
For more, visit the [Access Control documentation](/docs/access-control/overview).
|
||||
Payload dynamically generates a beautiful, fully type-safe interface to manage your users and data. The Admin Panel is a React application built using the Next.js App Router. [More details](../admin/overview).
|
||||
|
||||
## Retrieving Payload data
|
||||
## Plugins
|
||||
|
||||
Plugins allow for developers to easily inject custom—sometimes complex—functionality into Payload apps from a very small touch-point. [More details](../plugins/overview).
|
||||
|
||||
## Retrieving Data
|
||||
|
||||
Everything Payload does (create, read, update, delete, login, logout, etc) is exposed to you via three APIs:
|
||||
|
||||
**1 - Payload's Local API**
|
||||
- [Local API](#local-api) - Extremely fast, direct-to-database access
|
||||
- [REST API](#rest-api) - Standard HTTP endpoints for querying and mutating data
|
||||
- [GraphQL](#graphql) - A full GraphQL API with a GraphQL Playground
|
||||
|
||||
By far one of the most powerful aspects of Payload is the fact that it gives you direct-to-database access to your data. It's _extremely_ fast and does not incur any typical REST API / GraphQL / HTTP overhead - you query your database directly in Node.js / TypeScript.
|
||||
<Banner type="success">
|
||||
<strong>Note:</strong>
|
||||
All of these APIs share the exact same query language. [More details](../queries/overview).
|
||||
</Banner>
|
||||
|
||||
Everything is strongly typed and it's extremely nice to use. It works anywhere on the server, including custom Next.js route handlers, Payload hooks, Payload access control, and React Server Components.
|
||||
### Local API
|
||||
|
||||
By far one of the most powerful aspects of Payload is the fact that it gives you direct-to-database access to your data through the [Local API](../local-api/overview). It's _extremely_ fast and does not incur any typical REST API / GraphQL / HTTP overhead—you query your database directly in Node.js.
|
||||
|
||||
The Local API is written in TypeScript, and so it is strongly typed and extremely nice to use. It works anywhere on the server, including custom Next.js Routes, Payload Hooks, Payload Access Control, and React Server Components.
|
||||
|
||||
Here's a quick example of a React Server Component fetching page data with Payload's Local API:
|
||||
|
||||
@@ -104,28 +94,29 @@ const MyServerComponent: React.FC = () => {
|
||||
}
|
||||
```
|
||||
|
||||
For more docs about the Payload Local API, [click here](/docs/beta/local-api/overview).
|
||||
<Banner type="info">
|
||||
For more information about the Local API, [click here](../local-api/overview).
|
||||
</Banner>
|
||||
|
||||
**2 - The REST API**
|
||||
### REST API
|
||||
|
||||
By default, the Payload REST API will be mounted automatically for you at the `/api` path of your app.
|
||||
By default, the Payload [REST API](../rest-api/overview) will be mounted automatically for you at the `/api` path of your app.
|
||||
|
||||
For example, if you have a collection with the `slug` as `pages`, you'd fetch pages via `http://localhost:3000/api/pages`.
|
||||
|
||||
Here's an example:
|
||||
For example, if you have a [Collection](../configuration/collections) called `pages`:
|
||||
|
||||
```ts
|
||||
const pages = await fetch('http://localhost:3000/api/pages', {
|
||||
// Include cookies, like the Payload auth token
|
||||
credentials: 'include',
|
||||
}).then((res) => res.json())
|
||||
fetch('https://localhost:3000/api/pages') // highlight-line
|
||||
.then((res) => res.json())
|
||||
.then((data) => console.log(data))
|
||||
```
|
||||
|
||||
For a full list of REST API endpoints, including examples, [click here](/docs/beta/rest-api/overview).
|
||||
<Banner type="info">
|
||||
For more information about the REST API, [click here](../rest-api/overview).
|
||||
</Banner>
|
||||
|
||||
**3 - GraphQL**
|
||||
### GraphQL API
|
||||
|
||||
Payload automatically exposes GraphQL queries and mutations for everything it does.
|
||||
Payload automatically exposes GraphQL queries and mutations for everything it does through a dedicated [GraphQL API](../graphql/overview).
|
||||
|
||||
By default, you'll find the GraphQL route handler in your `/app/(payload)/api/graphql` folder, which makes the GraphQL endpoint available by default at `http://localhost:3000/api/graphql`.
|
||||
|
||||
@@ -138,157 +129,40 @@ You can use any GraphQL client with Payload's GraphQL endpoint. Here are a few p
|
||||
|
||||
If you don't use GraphQL, you can delete those files! But if you do, you'll find that GraphQL is a first-class API in Payload. Either way, the overhead of GraphQL is completely constrained to these endpoints, and will not slow down / affect Payload outside of those endpoints themselves.
|
||||
|
||||
For more docs on GraphQL, [click here](/docs/beta/graphql/overview).
|
||||
|
||||
## Depth
|
||||
|
||||
<Banner type="info">
|
||||
"Depth" gives you control over how many levels down related documents should be automatically
|
||||
populated when retrieved.
|
||||
For more information about the GraphQL API, [click here](../graphql/overview).
|
||||
</Banner>
|
||||
|
||||
You can specify population `depth` via query parameter in the REST API and by an option in the local API. _Depth has no effect in the GraphQL API, because there, depth is based on the shape of your queries._
|
||||
It is also possible to limit the depth for specific `relation` and `upload` fields using the `maxDepth` property in your configuration.
|
||||
**For example, let's look at the following Collections:** `departments`, `users`, `posts`
|
||||
### Depth
|
||||
|
||||
```
|
||||
// type: 'relationship' fields are equal to 1 depth level
|
||||
Documents can be related to other Documents through a concept called "relationships". When you query a Document, you can specify these relationships are populated. [More details](../queries/depth).
|
||||
|
||||
{
|
||||
slug: 'posts',
|
||||
fields: [
|
||||
{
|
||||
name: 'title',
|
||||
type: 'text',
|
||||
},
|
||||
{
|
||||
name: 'author',
|
||||
label: 'Post Author',
|
||||
type: 'relationship',
|
||||
relationTo: 'users',
|
||||
}
|
||||
]
|
||||
}
|
||||
## Package Structure
|
||||
|
||||
{
|
||||
slug: 'users',
|
||||
fields: [
|
||||
{
|
||||
name: 'email',
|
||||
type: 'email',
|
||||
},
|
||||
{
|
||||
name: 'department'
|
||||
type: 'relationship',
|
||||
relationTo: 'departments'
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
{
|
||||
slug: 'departments',
|
||||
fields: [
|
||||
{
|
||||
name: 'name'
|
||||
type: 'text',
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
If you were to query the Posts endpoint at, say, `http://localhost:3000/api/posts?depth=1`, you will retrieve Posts with populations one level deep. This depth parameter can be thought of as N, where N is the number of levels you want to populate. To populate one level further, you would simply specify N+1 as the depth. A returned result may look like the following:
|
||||
|
||||
```
|
||||
// ?depth=1
|
||||
|
||||
{
|
||||
id: '5ae8f9bde69e394e717c8832',
|
||||
title: 'This post sucks',
|
||||
author: {
|
||||
id: '5f7dd05cd50d4005f8bcab17',
|
||||
email: 'spiderman@superheroes.gov',
|
||||
department: '5e3ca05cd50d4005f8bdab15'
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Notice how the `user.author` is fully populated, but `user.author.department` is left as a document ID? That's because the User collection counted as the first level of `depth` and got populated—but then prevented any further populations from taking place.
|
||||
|
||||
To populate `user.author.department` in it's entirety you could specify `?depth=2` or _higher_.
|
||||
|
||||
```
|
||||
// ?depth=2
|
||||
|
||||
{
|
||||
id: '5ae8f9bde69e394e717c8832',
|
||||
title: 'This post sucks',
|
||||
author: {
|
||||
id: '5f7dd05cd50d4005f8bcab17',
|
||||
email: 'spiderman@superheroes.gov',
|
||||
department: {
|
||||
id: '5e3ca05cd50d4005f8bdab15',
|
||||
name: 'Marvel'
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Field-level max depth
|
||||
|
||||
Fields like relationships or uploads can have a `maxDepth` property that limits the depth of the population for that field. Here are some examples:
|
||||
|
||||
Depth: 10
|
||||
Current depth when field is accessed: 1
|
||||
`maxDepth`: undefined
|
||||
|
||||
In this case, the field would be populated to 9 levels of population.
|
||||
|
||||
Depth: 10
|
||||
Current depth when field is accessed: 0
|
||||
`maxDepth`: 2
|
||||
|
||||
In this case, the field would be populated to 2 levels of population, despite there being a remaining depth of 8.
|
||||
|
||||
Depth: 10
|
||||
Current depth when field is accessed: 2
|
||||
`maxDepth`: 1
|
||||
|
||||
In this case, the field would not be populated, as the current depth (2) has exceeded the `maxDepth` for this field (1).
|
||||
Payload is abstracted into a set of dedicated packages to keep the core `payload` package as lightweight as possible. This allows you to only install the parts of Payload based on your unique project requirements.
|
||||
|
||||
<Banner type="warning">
|
||||
<strong>Note:</strong>
|
||||
<br />
|
||||
When access control on collections prevents relationship fields from populating, the API response
|
||||
will contain the relationship id instead of the full document.
|
||||
</Banner>
|
||||
|
||||
## Package organization
|
||||
|
||||
Payload is abstracted into a set of dedicated packages, and it's a good idea to familiarize yourself with what each one is responsible for.
|
||||
|
||||
<Banner type="success">
|
||||
<strong>Note:</strong>
|
||||
<br/>
|
||||
Version numbers of all official Payload packages are kept in sync - and you should always make sure that you use matching versions for all official Payload packages.
|
||||
<strong>Important:</strong>
|
||||
Version numbers of all official Payload packages are always published in sync. You should make sure that you always use matching versions for all official Payload packages.
|
||||
</Banner>
|
||||
|
||||
`payload`
|
||||
|
||||
The `payload` package is where core business logic for Payload lives. You can think of Payload as an ORM with superpowers - it contains the logic for all Payload "operations" like `find`, `create`, `update`, and `delete`. It executes access control, hooks, validation, and more.
|
||||
The `payload` package is where core business logic for Payload lives. You can think of Payload as an ORM with superpowers—it contains the logic for all Payload "operations" like `find`, `create`, `update`, and `delete` and exposes a [Local API](../local-api/overview). It executes [Access Control](../access-control/overview), [Hooks](../hooks/overview), [Validation](../fields/overview#validation), and more.
|
||||
|
||||
Payload itself is extremely compact, and can be used in any Node environment. As long as you have `payload` installed and you have access to your Payload config, you can query and mutate your database directly without going through an unnecessary HTTP layer.
|
||||
Payload itself is extremely compact, and can be used in any Node environment. As long as you have `payload` installed and you have access to your Payload Config, you can query and mutate your database directly without going through an unnecessary HTTP layer.
|
||||
|
||||
Payload also contains all TypeScript definitions, which can be imported from `payload` directly.
|
||||
|
||||
Here's how to import some common Payload types:
|
||||
|
||||
```ts
|
||||
import { CollectionConfig, Field, GlobalConfig, Config } from 'payload'
|
||||
import { Config, CollectionConfig, GlobalConfig, Field } from 'payload'
|
||||
```
|
||||
|
||||
`@payloadcms/next`
|
||||
|
||||
Whereas Payload itself is responsible for direct database access, and control over Payload business logic, the `@payloadcms/next` package is responsible for the admin panel and the entire HTTP layer (REST, GraphQL) that Payload exposes.
|
||||
Whereas Payload itself is responsible for direct database access, and control over Payload business logic, the `@payloadcms/next` package is responsible for the Admin Panel and the entire HTTP layer that Payload exposes, including the [REST API](../rest-api/overview) and [GraphQL API](../graphql/overview).
|
||||
|
||||
`@payloadcms/graphql`
|
||||
|
||||
@@ -296,11 +170,11 @@ All of Payload's GraphQL functionality is abstracted into a separate package. Pa
|
||||
|
||||
`@payloadcms/ui`
|
||||
|
||||
This is the UI library that Payload's admin panel uses. All components are exported from this package and can be re-used as you build extensions to the Payload admin UI, or want to use Payload components in your own React apps. Some exports are server components and some are client components.
|
||||
This is the UI library that Payload's Admin Panel uses. All components are exported from this package and can be re-used as you build extensions to the Payload admin UI, or want to use Payload components in your own React apps. Some exports are server components and some are client components.
|
||||
|
||||
`@payloadcms/db-postgres`, `@payloadcms/db-mongodb`
|
||||
|
||||
You can choose which database adapter you'd like to use for your project, and no matter which you choose, the entire data layer for Payload is contained within these packages. You can only use one at a time for any given project.
|
||||
You can choose which Database Adapter you'd like to use for your project, and no matter which you choose, the entire data layer for Payload is contained within these packages. You can only use one at a time for any given project.
|
||||
|
||||
`@payloadcms/richtext-lexical`, `@payloadcms/richtext-slate`
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ Payload requires the following software:
|
||||
- Any [compatible database](/docs/database/overview) (MongoDB or Postgres)
|
||||
|
||||
<Banner type="warning">
|
||||
<strong>Important:</strong>
|
||||
Before proceeding any further, please ensure that you have the above requirements met.
|
||||
</Banner>
|
||||
|
||||
@@ -26,7 +27,7 @@ To quickly scaffold a new Payload app in the fastest way possible, you can use [
|
||||
npx create-payload-app@beta
|
||||
```
|
||||
|
||||
Then just follow the prompts! You'll get set up with a new folder and a functioning Payload app inside.
|
||||
Then just follow the prompts! You'll get set up with a new folder and a functioning Payload app inside. You can then start [configuring your application](../configuration/overview).
|
||||
|
||||
## Adding to an existing app
|
||||
|
||||
@@ -34,21 +35,43 @@ Adding Payload to an existing Next.js app is super straightforward. You can eith
|
||||
|
||||
If you don't have a Next.js app already, but you still want to start a project from a blank Next.js app, you can create a new Next.js app using `npx create-next-app` - and then just follow the steps below to install Payload.
|
||||
|
||||
#### 1 - install the relevant packages
|
||||
#### 1. Install the relevant packages
|
||||
|
||||
First, you'll want to add the required Payload packages to your project and can do so by running the command below (swap out `pnpm` for your package manager). Note that if you are using NPM, you might need to install using legacy peer deps (`npm i --legacy-peer-deps`).
|
||||
First, you'll want to add the required Payload packages to your project and can do so by running the command below:
|
||||
|
||||
```
|
||||
```bash
|
||||
pnpm i payload@beta @payloadcms/next@beta @payloadcms/richtext-lexical@beta sharp graphql
|
||||
```
|
||||
|
||||
You'll also need to install the database adapter that you'd like to use. You have the option of Postgres (`@payloadcms/db-postgres`) or MongoDB (`@payloadcms/db-mongodb`).
|
||||
<Banner type="warning">
|
||||
<strong>Note:</strong>
|
||||
Swap out `pnpm` for your package manager. If you are using NPM, you might need to install using legacy peer deps: `npm i --legacy-peer-deps`.
|
||||
</Banner>
|
||||
|
||||
#### 2 - copy Payload files into your Next.js app folder
|
||||
Next, install a [Database Adapter](/docs/database/overview). Payload requires a Database Adapter to establish a database connection. Payload works with all types of databases, but the most common are MongoDB and Postgres.
|
||||
|
||||
To install a Database Adapter, you can run **one** of the following commands:
|
||||
|
||||
- To install the [MongoDB Adapter](../database/mongodb), run:
|
||||
```bash
|
||||
pnpm i @payloadcms/db-mongodb
|
||||
```
|
||||
|
||||
- To install the [Postgres Adapter](../database/postgres), run:
|
||||
```bash
|
||||
pnpm i @payloadcms/db-postgres
|
||||
```
|
||||
|
||||
<Banner type="success">
|
||||
<strong>Reminder:</strong>
|
||||
New [Database Adapters](/docs/database/overview) are becoming available every day. Check the docs for the most up-to-date list of what's available.
|
||||
</Banner>
|
||||
|
||||
#### 2. Copy Payload files into your Next.js app folder
|
||||
|
||||
Payload installs directly in your Next.js `/app` folder, and you'll need to place some files into that folder for Payload to run.
|
||||
|
||||
The files that Payload needs to have in your `/app` folder do not regenerate, and will never change. Once you slot them in, you never have to revisit them. They are not meant to be edited and simply import Payload dependencies from `@payloadcms/next` for the REST / GraphQL API and Payload admin UI.
|
||||
The files that Payload needs to have in your `/app` folder do not regenerate, and will never change. Once you slot them in, you never have to revisit them. They are not meant to be edited and simply import Payload dependencies from `@payloadcms/next` for the REST / GraphQL API and Admin Panel UI.
|
||||
|
||||
You can copy the Payload `/app` folder files from the Payload blank template on GitHub:
|
||||
|
||||
@@ -56,36 +79,27 @@ You can copy the Payload `/app` folder files from the Payload blank template on
|
||||
https://github.com/payloadcms/payload/tree/beta/templates/blank-3.0/src/app/(payload)
|
||||
```
|
||||
|
||||
Notice how the Payload files are all kept within the `(payload)` [Route Group](https://nextjs.org/docs/app/building-your-application/routing/route-groups)? That's so that the Payload admin UI can have its own separate [Root Layout](https://nextjs.org/docs/app/building-your-application/routing/pages-and-layouts#root-layout-required) which will allow it to not interfere whatsoever with an existing Next.js app if you have one.
|
||||
|
||||
<Banner type="warning">
|
||||
You may need to copy all of your existing frontend files, including your existing root layout, into its own newly created route group.
|
||||
</Banner>
|
||||
|
||||
Once you have the required Payload files in place in your `/app` folder, you should have something like this:
|
||||
|
||||
```
|
||||
/app
|
||||
-- (payload) // This is the Payload route group
|
||||
-- layout.tsx // Payload's root layout
|
||||
-- admin // The Payload admin UI
|
||||
-- api // Payload's REST / GraphQL handlers
|
||||
-- custom.scss // Define custom SCSS for the Payload admin here
|
||||
-- (my-app) // this is where your existing app goes
|
||||
-- layout.tsx // move your existing root layout here
|
||||
-- page.tsx // your existing home page
|
||||
-- ...etc // whatever else you have
|
||||
```plaintext
|
||||
app/
|
||||
├─ (payload)/
|
||||
├── // Payload files
|
||||
├─ (my-app)/
|
||||
├── // Your app files
|
||||
```
|
||||
|
||||
You can name the `(my-app)` folder anything you want. The name does not matter and will just be used to clarify your directory structure for yourself. Common names might be `(frontend)`, `(app)`, or similar. [Check out the Admin documentation](/docs/beta/admin/overview) for more information.
|
||||
<Banner type="warning">
|
||||
You may need to copy all of your existing frontend files, including your existing root layout, into its own newly created [Route Group](https://nextjs.org/docs/app/building-your-application/routing/route-groups), i.e. `(my-app)`.
|
||||
</Banner>
|
||||
|
||||
#### 3 - add the Payload plugin to your Next.js config
|
||||
You can name the `(my-app)` folder anything you want. The name does not matter and will just be used to clarify your directory structure for yourself. Common names might be `(frontend)`, `(app)`, or similar. [More details](../admin/overview).
|
||||
|
||||
Payload has a plugin that it uses to ensure Next.js compatibility with some of the packages Payload relies on, like `mongodb` or `drizzle-kit`.
|
||||
#### 3. Add the Payload Plugin to your Next.js config
|
||||
|
||||
You need to import the `withPayload` plugin in your `next.config.js` file and wrap your config with it.
|
||||
Payload has a Next.js plugin that it uses to ensure compatibility with some of the packages Payload relies on, like `mongodb` or `drizzle-kit`.
|
||||
|
||||
Here's an example of what your Next.js config should look like after you've imported the Payload plugin:
|
||||
To add the Payload Plugin, use `withPayload` in your `next.config.js`:
|
||||
|
||||
```js
|
||||
import { withPayload } from '@payloadcms/next/withPayload'
|
||||
@@ -100,12 +114,15 @@ const nextConfig = {
|
||||
|
||||
// Make sure you wrap your `nextConfig`
|
||||
// with the `withPayload` plugin
|
||||
export default withPayload(nextConfig)
|
||||
export default withPayload(nextConfig) // highlight-line
|
||||
```
|
||||
|
||||
**Important:** Payload is a fully ESM project, and that means the `withPayload` function is an EcmaScript module.
|
||||
<Banner type="warning">
|
||||
<strong>Important:</strong>
|
||||
Payload is a fully ESM project, and that means the `withPayload` function is an ECMAScript module.
|
||||
</Banner>
|
||||
|
||||
To import it, you need to make sure your `next.config` file is set up to use ESM.
|
||||
To import the Payload Plugin, you need to make sure your `next.config` file is set up to use ESM.
|
||||
|
||||
You can do this in one of two ways:
|
||||
|
||||
@@ -114,11 +131,11 @@ You can do this in one of two ways:
|
||||
|
||||
In either case, all `require`s and `export`s in your `next.config` file will need to be converted to `import` / `export` if they are not set up that way already.
|
||||
|
||||
#### 4 - create a Payload config and add it to your TypeScript config
|
||||
#### 4. Create a Payload Config and add it to your TypeScript config
|
||||
|
||||
Finally, you need to create a barebones Payload config.
|
||||
Finally, you need to create a [Payload Config](../configuration/overview). Generally the Payload Config is located at the root of your repository, or next to your `/app` folder, and is named `payload.config.ts`.
|
||||
|
||||
Generally the Payload config is located at the root of your repository, or next to your `/app` folder, and is named `payload.config.ts`. Here's what Payload needs at a bare minimum:
|
||||
Here's what Payload needs at a bare minimum:
|
||||
|
||||
```ts
|
||||
import sharp from 'sharp'
|
||||
@@ -133,18 +150,16 @@ export default buildConfig({
|
||||
// Define and configure your collections in this array
|
||||
collections: [],
|
||||
|
||||
// Your Payload secret - should be a complex and secure string, unguessable
|
||||
// Your Payload secret - should be a complex and secure string, unguessable
|
||||
secret: process.env.PAYLOAD_SECRET || '',
|
||||
|
||||
// Whichever database adapter you're using should go here
|
||||
// Mongoose is shown as an example, but you can also use Postgres
|
||||
// Whichever Database Adapter you're using should go here
|
||||
// Mongoose is shown as an example, but you can also use Postgres
|
||||
db: mongooseAdapter({
|
||||
url: process.env.DATABASE_URI || '',
|
||||
}),
|
||||
|
||||
// If you want to resize images, crop, set focal point, etc.
|
||||
// make sure to install it and pass it to the config.
|
||||
// This is optional - if you don't need to do these things,
|
||||
// This is optional - if you don't need to do these things,
|
||||
// you don't need it!
|
||||
sharp,
|
||||
})
|
||||
@@ -152,7 +167,7 @@ export default buildConfig({
|
||||
|
||||
Although this is just the bare minimum config, there are _many_ more options that you can control here. To reference the full config and all of its options, [click here](/docs/configuration/overview).
|
||||
|
||||
Once you have your config created, update your `tsconfig` to include a `path` that points to your config:
|
||||
Once you have a Payload Config, update your `tsconfig` to include a `path` that points to it:
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -166,7 +181,7 @@ Once you have your config created, update your `tsconfig` to include a `path` th
|
||||
}
|
||||
```
|
||||
|
||||
#### 5 - fire it up!
|
||||
#### 5. Fire it up!
|
||||
|
||||
After you've gotten this far, it's time to boot up Payload. Start your project in your application's folder to get going. By default, the Next.js dev script is `pnpm dev` (or `npm run dev` if using NPM).
|
||||
|
||||
|
||||
@@ -11,9 +11,9 @@ keywords: documentation, getting started, guide, Content Management System, cms,
|
||||
title="Payload Introduction - Closing the Gap Between Headless CMS and Application Frameworks"
|
||||
/>
|
||||
|
||||
**Payload is the Next.js fullstack framework.** Write a Payload config and instantly get:
|
||||
**Payload is the Next.js fullstack framework.** Write a Payload Config and instantly get:
|
||||
|
||||
- A full admin panel using React server / client components, matching the shape of your data and completely extensible with your own React components
|
||||
- A full Admin Panel using React server / client components, matching the shape of your data and completely extensible with your own React components
|
||||
- Automatic database schema, including direct DB access and ownership, with migrations, transactions, proper indexing, and more
|
||||
- Instant REST, GraphQL, and straight-to-DB Node APIs
|
||||
- Authentication which can be used in your own apps
|
||||
@@ -34,21 +34,21 @@ It's fully open source with an MIT license and you can self-host anywhere that y
|
||||
|
||||
Even in spite of how much you get out of the box, you still have full control over every aspect of your app - be it database, admin UI, or anything else. Every part of Payload has been designed to be extensible and customizable with modern TypeScript / React. And you'll fully understand the code that you write.
|
||||
|
||||
In Payload, there are no "click ops" - as in clicking around in an admin panel to define your schema. In Payload, everything is done the right way—code-first and version controlled like a proper backend. But once developers define how Payload should work, non-technical users can independently make use of its admin panel to manage whatever they need to without having to know code whatsoever.
|
||||
In Payload, there are no "click ops" - as in clicking around in an Admin Panel to define your schema. In Payload, everything is done the right way—code-first and version controlled like a proper backend. But once developers define how Payload should work, non-technical users can independently make use of its Admin Panel to manage whatever they need to without having to know code whatsoever.
|
||||
|
||||
## Use cases
|
||||
## Use Cases
|
||||
|
||||
Payload started as a headless Content Management System (CMS), but since, we've seen our community leverage Payload in ways far outside of simply managing pages and blog posts. It's grown into a full-stack TypeScript app framework.
|
||||
Payload started as a headless Content Management System (CMS), but since, we've seen our community leverage Payload in ways far outside of simply managing pages and blog posts. It's grown into a full-stack TypeScript app framework.
|
||||
|
||||
Large enterprises use Payload to power significant internal tools, retailers power their entire storefronts without the need for headless Shopify, and massive amounts of digital assets are stored + managed within Payload. Of course, websites large and small still use Payload for content management as well.
|
||||
|
||||
### As a CMS
|
||||
### Headless CMS
|
||||
|
||||
The biggest barrier in large web projects cited by marketers is engineering. On the flip side, engineers say the opposite. This is a big problem that has yet to be solved even though we have countless CMS options.
|
||||
|
||||
Payload has restored a little love back into the dev / marketer equation with features like Live Preview, redirects, form builders, visual editing, static A/B testing, and more. But even with all this focus on marketing efficiency, we aren't compromising on the developer experience. That way engineers and marketers alike can be proud of the products they build.
|
||||
|
||||
If you're building a website and your frontend is on Next.js, then Payload is a no-brainer.
|
||||
If you're building a website and your frontend is on Next.js, then Payload is a no-brainer.
|
||||
|
||||
<Banner type="success">
|
||||
Instead of going out and signing up for a SaaS vendor that makes it so you have to manage two completely separate concerns, with little to no native connection back and forth, just install Payload in your existing Next.js repo and instantly get a full CMS.
|
||||
@@ -60,7 +60,7 @@ Get started with Payload as a CMS using our official Website template:
|
||||
npx create-payload-app@latest -t website
|
||||
```
|
||||
|
||||
### For enterprise tools
|
||||
### Enterprise Tool
|
||||
|
||||
When a large organization starts up a new software initiative, there's a lot of plumbing to take care of.
|
||||
|
||||
@@ -71,7 +71,7 @@ When a large organization starts up a new software initiative, there's a lot of
|
||||
- Implement a migrations workflow for the database as it changes over time
|
||||
- Integrate with other third party solutions by crafting a system of webhooks or similar
|
||||
|
||||
And then there's the admin panel. Most enterprise tools require an admin UI, and building one from scratch can be the most time-consuming aspect of any new enterprise tool. There are off-the-shelf packages for app frameworks like Rails, but often the customization is so involved that using Material UI or similar from scratch might be better.
|
||||
And then there's the [Admin Panel](../admin/overview). Most enterprise tools require an admin UI, and building one from scratch can be the most time-consuming aspect of any new enterprise tool. There are off-the-shelf packages for app frameworks like Rails, but often the customization is so involved that using Material UI or similar from scratch might be better.
|
||||
|
||||
Then there are no-code admin builders that could be used. However, wiring up access control and the connection to the data layer, with proper version control, makes this a challenging task as well.
|
||||
|
||||
@@ -83,9 +83,9 @@ Generally, the best place to start for a new enterprise tool is with a blank can
|
||||
npx create-payload-app@latest -t blank
|
||||
```
|
||||
|
||||
### Headless commerce
|
||||
### Headless Commerce
|
||||
|
||||
Companies who prioritize UX generally run into frontend constraints with traditional commerce vendors. These companies will then opt for frontend frameworks like Next.js which allow them to fine-tune their user experience as much as possible—promoting conversions, personalizing experiences, and optimizing for SEO.
|
||||
Companies who prioritize UX generally run into frontend constraints with traditional commerce vendors. These companies will then opt for frontend frameworks like Next.js which allow them to fine-tune their user experience as much as possible—promoting conversions, personalizing experiences, and optimizing for SEO.
|
||||
|
||||
But the challenge with using something like Next.js for headless commerce is that in order for non-technical users to manage the storefront, you instantly need to pair a headless commerce product with a headless CMS. Then, your editors need to bounce back and forth between different admin UIs for different functionality. The code required to seamlessly glue them together on the frontend becomes overly complex.
|
||||
|
||||
@@ -99,7 +99,7 @@ Payload's official Ecommerce template gives you everything you need for a storef
|
||||
npx create-payload-app@latest -t ecommerce
|
||||
```
|
||||
|
||||
### Digital asset management
|
||||
### Digital Asset Management
|
||||
|
||||
Payload's API-first tagging, sorting, and querying engine lends itself perfectly to all types of content that a CMS might ordinarily store, but these strong fundamentals also make it a formidable Digital Asset Management (DAM) tool as well.
|
||||
|
||||
@@ -109,6 +109,10 @@ Payload flattens CMS and DAM into a single tool that makes no compromises on eit
|
||||
|
||||
[Click here](https://payloadcms.com/use-cases/digital-asset-management) for more information on how to get started with Payload as a DAM.
|
||||
|
||||
## Choosing a Framework
|
||||
|
||||
Payload is a great choice for applications of all sizes and types, but it might not be the right choice for every project. Here are some guidelines to help you decide if Payload is the right choice for your project.
|
||||
|
||||
### When Payload might be for you
|
||||
|
||||
- If data ownership and privacy are important to you, and you don't want to allow another proprietary SaaS vendor to host and own your data
|
||||
@@ -121,7 +125,7 @@ Payload flattens CMS and DAM into a single tool that makes no compromises on eit
|
||||
|
||||
- If you can manage your project fully with code, and don't need an admin UI
|
||||
- If you are building a website that fits within the limits a tool like Webflow or Framer
|
||||
- If you already have a full database and just need to visualize the data somehow
|
||||
- If you already have a full database and just need to visualize the data somehow
|
||||
- If you are confident that you won't need code / data ownership at any point in the future
|
||||
|
||||
Ready to get started? First, let's review some high-level concepts that are used in Payload.
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
title: Adding your own Queries and Mutations
|
||||
label: Custom Queries and Mutations
|
||||
order: 20
|
||||
desc: Payload allows you to add your own GraphQL queries and mutations, simply set up GraphQL in your main Payload config by following these instructions.
|
||||
desc: Payload allows you to add your own GraphQL queries and mutations, simply set up GraphQL in your main Payload Config by following these instructions.
|
||||
keywords: graphql, resolvers, mutations, custom, queries, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
|
||||
---
|
||||
|
||||
You can add your own GraphQL queries and mutations to Payload, making use of all the types that Payload has defined for you.
|
||||
|
||||
To do so, add your queries and mutations to the main Payload config as follows:
|
||||
To do so, add your queries and mutations to the main Payload Config as follows:
|
||||
|
||||
| Config Path | Description |
|
||||
| ------------------- | --------------------------------------------------------------------------- |
|
||||
|
||||
@@ -8,13 +8,13 @@ keywords: graphql, resolvers, mutations, config, configuration, documentation, C
|
||||
|
||||
In addition to its REST and Local APIs, Payload ships with a fully featured and extensible GraphQL API.
|
||||
|
||||
By default, the GraphQL API is exposed via `/api/graphql`, but you can customize this URL via specifying your `routes` within the main Payload config.
|
||||
By default, the GraphQL API is exposed via `/api/graphql`, but you can customize this URL via specifying your `routes` within the main Payload Config.
|
||||
|
||||
The labels you provide for your Collections and Globals are used to name the GraphQL types that are created to correspond to your config. Special characters and spaces are removed.
|
||||
|
||||
## GraphQL Options
|
||||
|
||||
At the top of your Payload config you can define all the options to manage GraphQL.
|
||||
At the top of your Payload Config you can define all the options to manage GraphQL.
|
||||
|
||||
| Option | Description |
|
||||
| ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
|
||||
@@ -93,7 +93,7 @@ const Header: GlobalConfig = {
|
||||
|
||||
## Preferences
|
||||
|
||||
User [preferences](/docs/admin/overview#preferences) for the admin panel are also available to GraphQL the same way as other collection schemas are generated. To query preferences you must supply an authorization token in the header and only the preferences of that user will be accessible.
|
||||
User [preferences](/docs/admin/overview#preferences) for the [Admin Panel](../admin/overview) are also available to GraphQL the same way as other collection schemas are generated. To query preferences you must supply an authorization token in the header and only the preferences of that user will be accessible.
|
||||
|
||||
**Payload will open the following query:**
|
||||
|
||||
@@ -110,7 +110,7 @@ User [preferences](/docs/admin/overview#preferences) for the admin panel are als
|
||||
|
||||
## GraphQL Playground
|
||||
|
||||
GraphQL Playground is enabled by default for development purposes, but disabled in production. You can enable it in production by passing `graphQL.disablePlaygroundInProduction` a `false` setting in the main Payload config.
|
||||
GraphQL Playground is enabled by default for development purposes, but disabled in production. You can enable it in production by passing `graphQL.disablePlaygroundInProduction` a `false` setting in the main Payload Config.
|
||||
|
||||
You can even log in using the `login[collection-singular-label-here]` mutation to use the Playground as an authenticated user.
|
||||
|
||||
|
||||
@@ -6,43 +6,54 @@ desc: You can add hooks to any Collection, several hook types are available incl
|
||||
keywords: hooks, collections, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
|
||||
---
|
||||
|
||||
Collections feature the ability to define the following hooks:
|
||||
Collection Hooks are [Hooks](./overview) that run on Documents within a specific [Collection](../configuration/collections). They allow you to execute your own logic during specific events of the Document lifecycle.
|
||||
|
||||
- [beforeOperation](#beforeoperation)
|
||||
- [beforeValidate](#beforevalidate)
|
||||
- [beforeChange](#beforechange)
|
||||
- [afterChange](#afterchange)
|
||||
- [beforeRead](#beforeread)
|
||||
- [afterRead](#afterread)
|
||||
- [beforeDelete](#beforedelete)
|
||||
- [afterDelete](#afterdelete)
|
||||
- [afterOperation](#afteroperation)
|
||||
|
||||
Additionally, `auth`-enabled collections feature the following hooks:
|
||||
|
||||
- [beforeLogin](#beforelogin)
|
||||
- [afterLogin](#afterlogin)
|
||||
- [afterLogout](#afterlogout)
|
||||
- [afterRefresh](#afterrefresh)
|
||||
- [afterMe](#afterme)
|
||||
- [afterForgotPassword](#afterforgotpassword)
|
||||
- [refresh](#refresh)
|
||||
- [me](#me)
|
||||
|
||||
## Config
|
||||
|
||||
All collection Hook properties accept arrays of synchronous or asynchronous functions. Each Hook type receives specific arguments and has the ability to modify specific outputs.
|
||||
|
||||
`collections/exampleHooks.js`
|
||||
To add hooks to a Collection, use the `hooks` property in your [Collection Config](../configuration/collections):
|
||||
|
||||
```ts
|
||||
import type { CollectionConfig } from 'payload';
|
||||
|
||||
export const ExampleHooks: CollectionConfig = {
|
||||
slug: 'example-hooks',
|
||||
fields: [
|
||||
{ name: 'name', type: 'text'},
|
||||
],
|
||||
export const CollectionWithHooks: CollectionConfig = {
|
||||
// ...
|
||||
hooks: { // highlight-line
|
||||
// ...
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
The following Collection Hooks are available:
|
||||
|
||||
- [`beforeOperation`](#beforeoperation)
|
||||
- [`beforeValidate`](#beforevalidate)
|
||||
- [`beforeChange`](#beforechange)
|
||||
- [`afterChange`](#afterchange)
|
||||
- [`beforeRead`](#beforeread)
|
||||
- [`afterRead`](#afterread)
|
||||
- [`beforeDelete`](#beforedelete)
|
||||
- [`afterDelete`](#afterdelete)
|
||||
- [`afterOperation`](#afteroperation)
|
||||
|
||||
Additionally, all [Auth-enabled Collections](../authentication/overview) feature the following auth-related Hooks:
|
||||
|
||||
- [`beforeLogin`](#beforelogin)
|
||||
- [`afterLogin`](#afterlogin)
|
||||
- [`afterLogout`](#afterlogout)
|
||||
- [`afterRefresh`](#afterrefresh)
|
||||
- [`afterMe`](#afterme)
|
||||
- [`afterForgotPassword`](#afterforgotpassword)
|
||||
- [`refresh`](#refresh)
|
||||
- [`me`](#me)
|
||||
|
||||
## Config Options
|
||||
|
||||
All Collection Hooks accept an array of [synchronous or asynchronous functions](./overview#async-vs-synchronous). Each Collection Hook receives specific arguments based on its own type, and has the ability to modify specific outputs.
|
||||
|
||||
```ts
|
||||
import type { CollectionConfig } from 'payload';
|
||||
|
||||
export const CollectionWithHooks: CollectionConfig = {
|
||||
// ...
|
||||
// highlight-start
|
||||
hooks: {
|
||||
beforeOperation: [(args) => {...}],
|
||||
beforeValidate: [(args) => {...}],
|
||||
@@ -54,7 +65,7 @@ export const ExampleHooks: CollectionConfig = {
|
||||
afterDelete: [(args) => {...}],
|
||||
afterOperation: [(args) => {...}],
|
||||
|
||||
// Auth-enabled hooks
|
||||
// Auth-enabled Hooks
|
||||
beforeLogin: [(args) => {...}],
|
||||
afterLogin: [(args) => {...}],
|
||||
afterLogout: [(args) => {...}],
|
||||
@@ -64,6 +75,7 @@ export const ExampleHooks: CollectionConfig = {
|
||||
refresh: [(args) => {...}],
|
||||
me: [(args) => {...}],
|
||||
},
|
||||
// highlight-end
|
||||
}
|
||||
```
|
||||
|
||||
@@ -85,6 +97,15 @@ const beforeOperationHook: CollectionBeforeOperationHook = async ({
|
||||
}
|
||||
```
|
||||
|
||||
The following arguments are passed to the `beforeOperation` hook:
|
||||
|
||||
| Option | Description |
|
||||
| ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **`collection`** | The [Collection](../configuration/collections) in which this Hook is running against. |
|
||||
| **`context`** | Custom context passed between Hooks. [More details](./context). |
|
||||
| **`operation`** | The name of the operation that this hook is running within. |
|
||||
| **`req`** | The [Web Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) object. This is mocked for [Local API](../local-api/overview) operations. |
|
||||
|
||||
### beforeValidate
|
||||
|
||||
Runs before the `create` and `update` operations. This hook allows you to add or format data before the incoming data is validated server-side.
|
||||
@@ -99,15 +120,23 @@ Please do note that this does not run before the client-side validation. If you
|
||||
import type { CollectionBeforeValidateHook } from 'payload'
|
||||
|
||||
const beforeValidateHook: CollectionBeforeValidateHook = async ({
|
||||
data, // incoming data to update or create with
|
||||
req, // full Request object
|
||||
operation, // name of the operation ie. 'create', 'update'
|
||||
originalDoc, // original document
|
||||
data,
|
||||
}) => {
|
||||
return data // Return data to either create or update a document with
|
||||
return data
|
||||
}
|
||||
```
|
||||
|
||||
The following arguments are passed to the `beforeValidate` hook:
|
||||
|
||||
| Option | Description |
|
||||
| ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **`collection`** | The [Collection](../configuration/collections) in which this Hook is running against. |
|
||||
| **`context`** | Custom context passed between Hooks. [More details](./context). |
|
||||
| **`data`** | The incoming data passed through the operation. |
|
||||
| **`operation`** | The name of the operation that this hook is running within. |
|
||||
| **`originalDoc`** | The Document before changes are applied. |
|
||||
| **`req`** | The [Web Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) object. This is mocked for [Local API](../local-api/overview) operations. |
|
||||
|
||||
### beforeChange
|
||||
|
||||
Immediately following validation, `beforeChange` hooks will run within `create` and `update` operations. At this stage, you can be confident that the data that will be saved to the document is valid in accordance to your field validations. You can optionally modify the shape of data to be saved.
|
||||
@@ -116,15 +145,23 @@ Immediately following validation, `beforeChange` hooks will run within `create`
|
||||
import type { CollectionBeforeChangeHook } from 'payload'
|
||||
|
||||
const beforeChangeHook: CollectionBeforeChangeHook = async ({
|
||||
data, // incoming data to update or create with
|
||||
req, // full Request object
|
||||
operation, // name of the operation ie. 'create', 'update'
|
||||
originalDoc, // original document
|
||||
data,
|
||||
}) => {
|
||||
return data // Return data to either create or update a document with
|
||||
return data
|
||||
}
|
||||
```
|
||||
|
||||
The following arguments are passed to the `beforeChange` hook:
|
||||
|
||||
| Option | Description |
|
||||
| ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **`collection`** | The [Collection](../configuration/collections) in which this Hook is running against. |
|
||||
| **`context`** | Custom context passed between hooks. [More details](./context). |
|
||||
| **`data`** | The incoming data passed through the operation. |
|
||||
| **`operation`** | The name of the operation that this hook is running within. |
|
||||
| **`originalDoc`** | The Document before changes are applied. |
|
||||
| **`req`** | The [Web Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) object. This is mocked for [Local API](../local-api/overview) operations. |
|
||||
|
||||
### afterChange
|
||||
|
||||
After a document is created or updated, the `afterChange` hook runs. This hook is helpful to recalculate statistics such as total sales within a global, syncing user profile changes to a CRM, and more.
|
||||
@@ -133,15 +170,23 @@ After a document is created or updated, the `afterChange` hook runs. This hook i
|
||||
import type { CollectionAfterChangeHook } from 'payload'
|
||||
|
||||
const afterChangeHook: CollectionAfterChangeHook = async ({
|
||||
doc, // full document data
|
||||
req, // full Request object
|
||||
previousDoc, // document data before updating the collection
|
||||
operation, // name of the operation ie. 'create', 'update'
|
||||
doc,
|
||||
}) => {
|
||||
return doc
|
||||
}
|
||||
```
|
||||
|
||||
The following arguments are passed to the `afterChange` hook:
|
||||
|
||||
| Option | Description |
|
||||
| ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **`collection`** | The [Collection](../configuration/collections) in which this Hook is running against. |
|
||||
| **`context`** | Custom context passed between hooks. [More details](./context). |
|
||||
| **`doc`** | The resulting Document after changes are applied. |
|
||||
| **`operation`** | The name of the operation that this hook is running within. |
|
||||
| **`previousDoc`** | The Document before changes were applied. |
|
||||
| **`req`** | The [Web Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) object. This is mocked for [Local API](../local-api/overview) operations. |
|
||||
|
||||
### beforeRead
|
||||
|
||||
Runs before `find` and `findByID` operations are transformed for output by `afterRead`. This hook fires before hidden fields are removed and before localized fields are flattened into the requested locale. Using this Hook will provide you with all locales and all hidden fields via the `doc` argument.
|
||||
@@ -150,14 +195,22 @@ Runs before `find` and `findByID` operations are transformed for output by `afte
|
||||
import type { CollectionBeforeReadHook } from 'payload'
|
||||
|
||||
const beforeReadHook: CollectionBeforeReadHook = async ({
|
||||
doc, // full document data
|
||||
req, // full Request object
|
||||
query, // JSON formatted query
|
||||
doc,
|
||||
}) => {
|
||||
return doc
|
||||
}
|
||||
```
|
||||
|
||||
The following arguments are passed to the `beforeRead` hook:
|
||||
|
||||
| Option | Description |
|
||||
| ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **`collection`** | The [Collection](../configuration/collections) in which this Hook is running against. |
|
||||
| **`context`** | Custom context passed between hooks. [More details](./context). |
|
||||
| **`doc`** | The resulting Document after changes are applied. |
|
||||
| **`query`** | The [Query](../queries/overview) of the request.
|
||||
| **`req`** | The [Web Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) object. This is mocked for [Local API](../local-api/overview) operations. |
|
||||
|
||||
### afterRead
|
||||
|
||||
Runs as the last step before documents are returned. Flattens locales, hides protected fields, and removes fields that users do not have access to.
|
||||
@@ -166,15 +219,22 @@ Runs as the last step before documents are returned. Flattens locales, hides pro
|
||||
import type { CollectionAfterReadHook } from 'payload'
|
||||
|
||||
const afterReadHook: CollectionAfterReadHook = async ({
|
||||
doc, // full document data
|
||||
req, // full Request object
|
||||
query, // JSON formatted query
|
||||
findMany, // boolean to denote if this hook is running against finding one, or finding many
|
||||
doc,
|
||||
}) => {
|
||||
return doc
|
||||
}
|
||||
```
|
||||
|
||||
The following arguments are passed to the `afterRead` hook:
|
||||
|
||||
| Option | Description |
|
||||
| ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **`collection`** | The [Collection](../configuration/collections) in which this Hook is running against. |
|
||||
| **`context`** | Custom context passed between hooks. [More details](./context). |
|
||||
| **`doc`** | The resulting Document after changes are applied. |
|
||||
| **`query`** | The [Query](../queries/overview) of the request.
|
||||
| **`req`** | The [Web Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) object. This is mocked for [Local API](../local-api/overview) operations. |
|
||||
|
||||
### beforeDelete
|
||||
|
||||
Runs before the `delete` operation. Returned values are discarded.
|
||||
@@ -183,11 +243,20 @@ Runs before the `delete` operation. Returned values are discarded.
|
||||
import type { CollectionBeforeDeleteHook } from 'payload';
|
||||
|
||||
const beforeDeleteHook: CollectionBeforeDeleteHook = async ({
|
||||
req, // full Request object
|
||||
id, // id of document to delete
|
||||
req,
|
||||
id,
|
||||
}) => {...}
|
||||
```
|
||||
|
||||
The following arguments are passed to the `beforeDelete` hook:
|
||||
|
||||
| Option | Description |
|
||||
| ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **`collection`** | The [Collection](../configuration/collections) in which this Hook is running against. |
|
||||
| **`context`** | Custom context passed between hooks. [More details](./context). |
|
||||
| **`id`** | The ID of the Document being deleted. |
|
||||
| **`req`** | The [Web Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) object. This is mocked for [Local API](../local-api/overview) operations. |
|
||||
|
||||
### afterDelete
|
||||
|
||||
Runs immediately after the `delete` operation removes records from the database. Returned values are discarded.
|
||||
@@ -196,12 +265,22 @@ Runs immediately after the `delete` operation removes records from the database.
|
||||
import type { CollectionAfterDeleteHook } from 'payload';
|
||||
|
||||
const afterDeleteHook: CollectionAfterDeleteHook = async ({
|
||||
req, // full Request object
|
||||
id, // id of document to delete
|
||||
doc, // deleted document
|
||||
req,
|
||||
id,
|
||||
doc,
|
||||
}) => {...}
|
||||
```
|
||||
|
||||
The following arguments are passed to the `afterDelete` hook:
|
||||
|
||||
| Option | Description |
|
||||
| ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **`collection`** | The [Collection](../configuration/collections) in which this Hook is running against. |
|
||||
| **`context`** | Custom context passed between hooks. [More details](./context). |
|
||||
| **`doc`** | The resulting Document after changes are applied. |
|
||||
| **`id`** | The ID of the Document that was deleted. |
|
||||
| **`req`** | The [Web Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) object. This is mocked for [Local API](../local-api/overview) operations. |
|
||||
|
||||
### afterOperation
|
||||
|
||||
The `afterOperation` hook can be used to modify the result of operations or execute side-effects that run after an operation has completed.
|
||||
@@ -212,123 +291,194 @@ Available Collection operations include `create`, `find`, `findByID`, `update`,
|
||||
import type { CollectionAfterOperationHook } from 'payload'
|
||||
|
||||
const afterOperationHook: CollectionAfterOperationHook = async ({
|
||||
args, // arguments passed into the operation
|
||||
operation, // name of the operation
|
||||
req, // full Request object
|
||||
result, // the result of the operation, before modifications
|
||||
result,
|
||||
}) => {
|
||||
return result // return modified result as necessary
|
||||
return result
|
||||
}
|
||||
```
|
||||
|
||||
The following arguments are passed to the `afterOperation` hook:
|
||||
|
||||
| Option | Description |
|
||||
| ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **`args`** | The arguments passed into the operation. |
|
||||
| **`collection`** | The [Collection](../configuration/collections) in which this Hook is running against. |
|
||||
| **`req`** | The [Web Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) object. This is mocked for [Local API](../local-api/overview) operations. |
|
||||
| **`operation`** | The name of the operation that this hook is running within. |
|
||||
| **`result`** | The result of the operation, before modifications. |
|
||||
|
||||
### beforeLogin
|
||||
|
||||
For auth-enabled Collections, this hook runs during `login` operations where a user with the provided credentials exist, but before a token is generated and added to the response. You can optionally modify the user that is returned, or throw an error in order to deny the login operation.
|
||||
For [Auth-enabled Collections](../authentication/overview), this hook runs during `login` operations where a user with the provided credentials exist, but before a token is generated and added to the response. You can optionally modify the user that is returned, or throw an error in order to deny the login operation.
|
||||
|
||||
```ts
|
||||
import type { CollectionBeforeLoginHook } from 'payload'
|
||||
|
||||
const beforeLoginHook: CollectionBeforeLoginHook = async ({
|
||||
req, // full Request object
|
||||
user, // user being logged in
|
||||
user,
|
||||
}) => {
|
||||
return user
|
||||
}
|
||||
```
|
||||
|
||||
The following arguments are passed to the `beforeLogin` hook:
|
||||
|
||||
| Option | Description |
|
||||
| ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **`collection`** | The [Collection](../configuration/collections) in which this Hook is running against. |
|
||||
| **`context`** | Custom context passed between hooks. [More details](./context). |
|
||||
| **`req`** | The [Web Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) object. This is mocked for [Local API](../local-api/overview) operations. |
|
||||
| **`user`** | The user being logged in. |
|
||||
|
||||
### afterLogin
|
||||
|
||||
For auth-enabled Collections, this hook runs after successful `login` operations. You can optionally modify the user that is returned.
|
||||
For [Auth-enabled Collections](../authentication/overview), this hook runs after successful `login` operations. You can optionally modify the user that is returned.
|
||||
|
||||
```ts
|
||||
import type { CollectionAfterLoginHook } from 'payload';
|
||||
|
||||
const afterLoginHook: CollectionAfterLoginHook = async ({
|
||||
req, // full Request object
|
||||
user, // user that was logged in
|
||||
token, // user token
|
||||
user,
|
||||
token,
|
||||
}) => {...}
|
||||
```
|
||||
|
||||
The following arguments are passed to the `afterLogin` hook:
|
||||
|
||||
| Option | Description |
|
||||
| ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **`collection`** | The [Collection](../configuration/collections) in which this Hook is running against. |
|
||||
| **`context`** | Custom context passed between hooks. [More details](./context). |
|
||||
| **`req`** | The [Web Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) object. This is mocked for [Local API](../local-api/overview) operations. |
|
||||
| **`token`** | The token generated for the user. |
|
||||
| **`user`** | The user being logged in. |
|
||||
|
||||
### afterLogout
|
||||
|
||||
For auth-enabled Collections, this hook runs after `logout` operations.
|
||||
For [Auth-enabled Collections](../authentication/overview), this hook runs after `logout` operations.
|
||||
|
||||
```ts
|
||||
import type { CollectionAfterLogoutHook } from 'payload';
|
||||
|
||||
const afterLogoutHook: CollectionAfterLogoutHook = async ({
|
||||
req, // full Request object
|
||||
req,
|
||||
}) => {...}
|
||||
```
|
||||
|
||||
### afterRefresh
|
||||
The following arguments are passed to the `afterLogout` hook:
|
||||
|
||||
For auth-enabled Collections, this hook runs after `refresh` operations.
|
||||
|
||||
```ts
|
||||
import type { CollectionAfterRefreshHook } from 'payload';
|
||||
|
||||
const afterRefreshHook: CollectionAfterRefreshHook = async ({
|
||||
req, // full Request object
|
||||
res, // full Response object
|
||||
token, // newly refreshed user token
|
||||
}) => {...}
|
||||
```
|
||||
| Option | Description |
|
||||
| ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **`collection`** | The [Collection](../configuration/collections) in which this Hook is running against. |
|
||||
| **`context`** | Custom context passed between hooks. [More details](./context). |
|
||||
| **`req`** | The [Web Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) object. This is mocked for [Local API](../local-api/overview) operations. |
|
||||
|
||||
### afterMe
|
||||
|
||||
For auth-enabled Collections, this hook runs after `me` operations.
|
||||
For [Auth-enabled Collections](../authentication/overview), this hook runs after `me` operations.
|
||||
|
||||
```ts
|
||||
import type { CollectionAfterMeHook } from 'payload';
|
||||
|
||||
const afterMeHook: CollectionAfterMeHook = async ({
|
||||
req, // full Request object
|
||||
response, // response to return
|
||||
req,
|
||||
response,
|
||||
}) => {...}
|
||||
```
|
||||
|
||||
The following arguments are passed to the `afterMe` hook:
|
||||
|
||||
| Option | Description |
|
||||
| ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **`collection`** | The [Collection](../configuration/collections) in which this Hook is running against. |
|
||||
| **`context`** | Custom context passed between hooks. [More details](./context). |
|
||||
| **`req`** | The [Web Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) object. This is mocked for [Local API](../local-api/overview) operations. |
|
||||
| **`response`** | The response to return. |
|
||||
|
||||
### afterRefresh
|
||||
|
||||
For [Auth-enabled Collections](../authentication/overview), this hook runs after `refresh` operations.
|
||||
|
||||
```ts
|
||||
import type { CollectionAfterRefreshHook } from 'payload';
|
||||
|
||||
const afterRefreshHook: CollectionAfterRefreshHook = async ({
|
||||
token,
|
||||
}) => {...}
|
||||
```
|
||||
|
||||
The following arguments are passed to the `afterRefresh` hook:
|
||||
|
||||
| Option | Description |
|
||||
| ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **`collection`** | The [Collection](../configuration/collections) in which this Hook is running against. |
|
||||
| **`context`** | Custom context passed between hooks. [More details](./context). |
|
||||
| **`exp`** | The expiration time of the token. |
|
||||
| **`req`** | The [Web Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) object. This is mocked for [Local API](../local-api/overview) operations. |
|
||||
| **`token`** | The newly refreshed user token. |
|
||||
|
||||
### afterForgotPassword
|
||||
|
||||
For auth-enabled Collections, this hook runs after successful `forgotPassword` operations. Returned values are discarded.
|
||||
For [Auth-enabled Collections](../authentication/overview), this hook runs after successful `forgotPassword` operations. Returned values are discarded.
|
||||
|
||||
```ts
|
||||
import type { CollectionAfterForgotPasswordHook } from 'payload'
|
||||
|
||||
const afterForgotPasswordHook: CollectionAfterForgotPasswordHook = async ({
|
||||
args, // arguments passed into the operation
|
||||
args,
|
||||
context,
|
||||
collection, // The collection which this hook is being run on
|
||||
collection,
|
||||
}) => {...}
|
||||
```
|
||||
|
||||
The following arguments are passed to the `afterForgotPassword` hook:
|
||||
|
||||
| Option | Description |
|
||||
| ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **`args`** | The arguments passed into the operation. |
|
||||
| **`collection`** | The [Collection](../configuration/collections) in which this Hook is running against. |
|
||||
| **`context`** | Custom context passed between hooks. [More details](./context). |
|
||||
|
||||
### refresh
|
||||
|
||||
For auth-enabled Collections, this hook allows you to optionally replace the default behavior of the `refresh` operation with your own. If you optionally return a value from your hook, the operation will not perform its own logic and continue.
|
||||
For [Auth-enabled Collections](../authentication/overview), this hook allows you to optionally replace the default behavior of the `refresh` operation with your own. If you optionally return a value from your hook, the operation will not perform its own logic and continue.
|
||||
|
||||
```ts
|
||||
import type { CollectionRefreshHook } from 'payload'
|
||||
|
||||
const myRefreshHook: CollectionRefreshHook = async ({
|
||||
args, // arguments passed into the `refresh` operation
|
||||
user, // the user as queried from the database
|
||||
args,
|
||||
user,
|
||||
}) => {...}
|
||||
```
|
||||
|
||||
The following arguments are passed to the `afterRefresh` hook:
|
||||
|
||||
| Option | Description |
|
||||
| ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **`args`** | The arguments passed into the operation. |
|
||||
| **`user`** | The user being logged in. |
|
||||
|
||||
### me
|
||||
|
||||
For auth-enabled Collections, this hook allows you to optionally replace the default behavior of the `me` operation with your own. If you optionally return a value from your hook, the operation will not perform its own logic and continue.
|
||||
For [Auth-enabled Collections](../authentication/overview), this hook allows you to optionally replace the default behavior of the `me` operation with your own. If you optionally return a value from your hook, the operation will not perform its own logic and continue.
|
||||
|
||||
```ts
|
||||
import type { CollectionMeHook } from 'payload'
|
||||
|
||||
const meHook: CollectionMeHook = async ({
|
||||
args, // arguments passed into the `me` operation
|
||||
user, // the user as queried from the database
|
||||
args,
|
||||
user,
|
||||
}) => {...}
|
||||
```
|
||||
|
||||
The following arguments are passed to the `me` hook:
|
||||
|
||||
| Option | Description |
|
||||
| ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **`args`** | The arguments passed into the operation. |
|
||||
| **`user`** | The user being logged in. |
|
||||
|
||||
## TypeScript
|
||||
|
||||
Payload exports a type for each Collection hook which can be accessed as follows:
|
||||
|
||||
@@ -120,11 +120,11 @@ const MyCollection: CollectionConfig = {
|
||||
}
|
||||
```
|
||||
|
||||
## Typing context
|
||||
## TypeScript
|
||||
|
||||
The default typescript interface for `context` is `{ [key: string]: unknown }`. If you prefer a more strict typing in your project or when authoring plugins for others, you can override this using the `declare` syntax.
|
||||
The default TypeScript interface for `context` is `{ [key: string]: unknown }`. If you prefer a more strict typing in your project or when authoring plugins for others, you can override this using the `declare` syntax.
|
||||
|
||||
This is known as "type augmentation" - a TypeScript feature which allows us to add types to existing objects. Simply put this in any .ts or .d.ts file:
|
||||
This is known as "type augmentation", a TypeScript feature which allows us to add types to existing objects. Simply put this in any `.ts` or `.d.ts` file:
|
||||
|
||||
```ts
|
||||
import { RequestContext as OriginalRequestContext } from 'payload'
|
||||
|
||||
@@ -1,38 +1,49 @@
|
||||
---
|
||||
title: Field Hooks
|
||||
label: Fields
|
||||
order: 30
|
||||
order: 40
|
||||
desc: Hooks can be added to any fields, and optionally modify the return value of the field before the operation continues.
|
||||
keywords: hooks, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
|
||||
---
|
||||
|
||||
Field-level hooks offer incredible potential for encapsulating your logic. They help to isolate concerns and package up
|
||||
functionalities to be easily reusable across your projects.
|
||||
Field Hooks are [Hooks](./overview) that run on Documents on a per-field basis. They allow you to execute your own logic during specific events of the Document lifecycle. Field Hooks offer incredible potential for isolating your logic from the rest of your [Collection Hooks](./collections) and [Global Hooks](./globals).
|
||||
|
||||
**Example use cases include:**
|
||||
|
||||
- Automatically add an `owner` relationship to a Document based on the `req.user.id`
|
||||
- Encrypt / decrypt a sensitive field using `beforeValidate` and `afterRead` hooks
|
||||
- Auto-generate field data using a `beforeValidate` hook
|
||||
- Format incoming data such as kebab-casing a document `slug` with `beforeValidate`
|
||||
- Restrict updating a document to only once every X hours using the `beforeChange` hook
|
||||
|
||||
**All field types provide the following hooks:**
|
||||
|
||||
- [beforeValidate](#beforevalidate)
|
||||
- [beforeChange](#beforechange)
|
||||
- beforeDuplicate(#beforeduplicate)
|
||||
- [afterChange](#afterchange)
|
||||
- [afterRead](#afterread)
|
||||
|
||||
## Config
|
||||
|
||||
Example field configuration:
|
||||
To add hooks to a Field, use the `hooks` property in your [Field Config](../fields/overview):
|
||||
|
||||
```ts
|
||||
import type { Field } from 'payload';
|
||||
|
||||
const ExampleField: Field = {
|
||||
export const FieldWithHooks: Field = {
|
||||
// ...
|
||||
hooks: { // highlight-line
|
||||
// ...
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
The following Field Hooks are available:
|
||||
|
||||
- [`beforeValidate`](#beforevalidate)
|
||||
- [`beforeChange`](#beforechange)
|
||||
- [`beforeDuplicate`](#beforeduplicate)
|
||||
- [`afterChange`](#afterchange)
|
||||
- [`afterRead`](#afterread)
|
||||
|
||||
## Config Options
|
||||
|
||||
All Field Hooks accept an array of synchronous or asynchronous functions. These functions can optionally modify the return value of the field before the operation continues. All Field Hooks are formatted to accept the same arguments, although some arguments may be `undefined` based the specific hook type.
|
||||
|
||||
<Banner type="warning">
|
||||
<strong>Important:</strong>
|
||||
Due to GraphQL's typed nature, changing the type of data that you return from a field will produce errors in the [GraphQL API](../graphql/overview). If you need to change the shape or type of data, consider [Collection Hooks](./collections) or [Global Hooks](./hooks) instead.
|
||||
</Banner>
|
||||
|
||||
To add hooks to a Field, use the `hooks` property in your [Field Config](../fields/overview):
|
||||
|
||||
```ts
|
||||
import type { Field } from 'payload';
|
||||
|
||||
const FieldWithHooks: Field = {
|
||||
name: 'name',
|
||||
type: 'text',
|
||||
// highlight-start
|
||||
@@ -47,64 +58,37 @@ const ExampleField: Field = {
|
||||
}
|
||||
```
|
||||
|
||||
## Arguments and return values
|
||||
|
||||
All field-level hooks are formatted to accept the same arguments, although some arguments may be `undefined` based on
|
||||
which field hook you are utilizing.
|
||||
|
||||
<Banner type="success">
|
||||
<strong>Tip:</strong>
|
||||
<br />
|
||||
It's a good idea to conditionally scope your logic based on which operation is executing. For
|
||||
example, if you are writing a <strong>beforeChange</strong> hook, you may want to perform
|
||||
different logic based on if the current <strong>operation</strong> is <strong>create</strong> or{' '}
|
||||
<strong>update</strong>.
|
||||
</Banner>
|
||||
|
||||
#### Arguments
|
||||
|
||||
Field Hooks receive one `args` argument that contains the following properties:
|
||||
The following arguments are available to all Field Hooks:
|
||||
|
||||
| Option | Description |
|
||||
| ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **`data`** | The data passed to update the document within `create` and `update` operations, and the full document itself in the `afterRead` hook. |
|
||||
| **`siblingData`** | The sibling data passed to a field that the hook is running against. |
|
||||
| **`collection`** | The [Collection](../configuration/collections) in which this Hook is running against. If the field belongs to a Global, this will be `null`. |
|
||||
| **`context`** | Custom context passed between Hooks. [More details](./context). |
|
||||
| **`data`** | In the `afterRead` hook this is the full Document. In the `create` and `update` operations, this is the incoming data passed through the operation. |
|
||||
| **`field`** | The [Field](../fields/overview) which the Hook is running against. |
|
||||
| **`findMany`** | Boolean to denote if this hook is running against finding one, or finding many within the `afterRead` hook. |
|
||||
| **`operation`** | A string relating to which operation the field type is currently executing within. Useful within `beforeValidate`, `beforeChange`, and `afterChange` hooks to differentiate between `create` and `update` operations. |
|
||||
| **`originalDoc`** | The full original document in `update` operations. In the `afterChange` hook, this is the resulting document of the operation. |
|
||||
| **`previousDoc`** | The document before changes were applied, only in `afterChange` hooks. |
|
||||
| **`previousSiblingDoc`** | The sibling data of the document before changes being applied, only in `beforeChange` and `afterChange` hook. |
|
||||
| **`req`** | The [Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) object. It is mocked for Local API operations. |
|
||||
| **`value`** | The value of the field. |
|
||||
| **`global`** | The [Global](../configuration/globals) in which this Hook is running against. If the field belongs to a Collection, this will be `null`. |
|
||||
| **`operation`** | The name of the operation that this hook is running within. Useful within `beforeValidate`, `beforeChange`, and `afterChange` hooks to differentiate between `create` and `update` operations. |
|
||||
| **`originalDoc`** | In the `update` operation, this is the Document before changes were applied. In the `afterChange` hook, this is the resulting Document. |
|
||||
| **`overrideAccess`** | A boolean to denote if the current operation is overriding [Access Control](../access-control/overview). |
|
||||
| **`path`** | The path to the [Field](../fields/overview) in the schema. |
|
||||
| **`previousDoc`** | In the `afterChange` Hook, this is the Document before changes were applied. |
|
||||
| **`previousSiblingDoc`** | The sibling data of the Document before changes being applied, only in `beforeChange` and `afterChange` hook. |
|
||||
| **`previousValue`** | The previous value of the field, before changes, only in `beforeChange` and `afterChange` hooks. |
|
||||
| **`context`** | Context passed to this hook. More info can be found under [Context](/docs/hooks/context) |
|
||||
| **`field`** | The field which the hook is running against. |
|
||||
| **`collection`** | The collection which the field belongs to. If the field belongs to a global, this will be null. |
|
||||
| **`global`** | The global which the field belongs to. If the field belongs to a collection, this will be null. |
|
||||
| **`req`** | The [Web Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) object. This is mocked for [Local API](../local-api/overview) operations. |
|
||||
| **`schemaPath`** | The path of the [Field](../fields/overview) in the schema. |
|
||||
| **`siblingData`** | The data of sibling fields adjacent to the field that the Hook is running against. |
|
||||
| **`siblingDocWithLocales`** | The sibling data of the Document with all [Locales](../configuration/localization). |
|
||||
| **`value`** | The value of the [Field](../fields/overview). |
|
||||
|
||||
#### Return value
|
||||
|
||||
All field hooks can optionally modify the return value of the field before the operation continues. Field Hooks may
|
||||
optionally return the value that should be used within the field.
|
||||
|
||||
<Banner type="warning">
|
||||
<strong>Important</strong>
|
||||
<br />
|
||||
Due to GraphQL's typed nature, you should never change the type of data that you return from a
|
||||
field, otherwise GraphQL will produce errors. If you need to change the shape or type of data,
|
||||
reconsider Field Hooks and instead evaluate if Collection / Global hooks might suit you better.
|
||||
<Banner type="success">
|
||||
<strong>Tip:</strong>
|
||||
It's a good idea to conditionally scope your logic based on which operation is executing. For example, if you are writing a `beforeChange` hook, you may want to perform different logic based on if the current `operation` is `create` or `update`.
|
||||
</Banner>
|
||||
|
||||
## Examples of Field Hooks
|
||||
|
||||
To better illustrate how field-level hooks can be applied, here are some specific examples. These demonstrate the
|
||||
flexibility and potential of field hooks in different contexts. Remember, these examples are just a starting point - the
|
||||
true potential of field-level hooks lies in their adaptability to a wide array of use cases.
|
||||
|
||||
### beforeValidate
|
||||
|
||||
Runs before the `update` operation. This hook allows you to pre-process or format field data before it undergoes
|
||||
validation.
|
||||
Runs before the `update` operation. This hook allows you to pre-process or format field data before it undergoes validation.
|
||||
|
||||
```ts
|
||||
import type { Field } from 'payload'
|
||||
|
||||
@@ -1,33 +1,44 @@
|
||||
---
|
||||
title: Global Hooks
|
||||
label: Globals
|
||||
order: 40
|
||||
order: 30
|
||||
desc: Hooks can be added to any Global and allow you to validate data, flatten locales, hide protected fields, remove fields and more.
|
||||
keywords: hooks, globals, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
|
||||
---
|
||||
|
||||
Globals feature the ability to define the following hooks:
|
||||
Global Hooks are [Hooks](./overview) that run on [Global](../configuration/globals) Documents. They allow you to execute your own logic during specific events of the Document lifecycle.
|
||||
|
||||
- [beforeValidate](#beforevalidate)
|
||||
- [beforeChange](#beforechange)
|
||||
- [afterChange](#afterchange)
|
||||
- [beforeRead](#beforeread)
|
||||
- [afterRead](#afterread)
|
||||
|
||||
## Config
|
||||
|
||||
All Global Hook properties accept arrays of synchronous or asynchronous functions. Each Hook type receives specific arguments and has the ability to modify specific outputs.
|
||||
|
||||
`globals/example-hooks.js`
|
||||
To add hooks to a Global, use the `hooks` property in your [Global Config](../configuration/globals):
|
||||
|
||||
```ts
|
||||
import type { GlobalConfig } from 'payload';
|
||||
|
||||
const ExampleHooks: GlobalConfig = {
|
||||
slug: 'header',
|
||||
fields: [
|
||||
{ name: 'title', type: 'text'},
|
||||
]
|
||||
export const GlobalWithHooks: GlobalConfig = {
|
||||
// ...
|
||||
hooks: { // highlight-line
|
||||
// ...
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
The following Global Hooks are available:
|
||||
|
||||
- [`beforeValidate`](#beforevalidate)
|
||||
- [`beforeChange`](#beforechange)
|
||||
- [`afterChange`](#afterchange)
|
||||
- [`beforeRead`](#beforeread)
|
||||
- [`afterRead`](#afterread)
|
||||
|
||||
## Config Options
|
||||
|
||||
All Global Hooks accept an array of [synchronous or asynchronous functions](./overview#async-vs-synchronous). Each Global Hook receives specific arguments based on its own type, and has the ability to modify specific outputs.
|
||||
|
||||
```ts
|
||||
import type { GlobalConfig } from 'payload';
|
||||
|
||||
const GlobalWithHooks: GlobalConfig = {
|
||||
// ...
|
||||
// highlight-start
|
||||
hooks: {
|
||||
beforeValidate: [(args) => {...}],
|
||||
beforeChange: [(args) => {...}],
|
||||
@@ -35,6 +46,7 @@ const ExampleHooks: GlobalConfig = {
|
||||
afterChange: [(args) => {...}],
|
||||
afterRead: [(args) => {...}],
|
||||
}
|
||||
// highlight-end
|
||||
}
|
||||
```
|
||||
|
||||
@@ -54,6 +66,16 @@ const beforeValidateHook: GlobalBeforeValidateHook = async ({
|
||||
}
|
||||
```
|
||||
|
||||
The following arguments are passed to the `beforeValidate` hook:
|
||||
|
||||
| Option | Description |
|
||||
| ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **`global`** | The [Global](../configuration/globals) in which this Hook is running against. |
|
||||
| **`context`** | Custom context passed between Hooks. [More details](./context). |
|
||||
| **`data`** | The incoming data passed through the operation. |
|
||||
| **`originalDoc`** | The Document before changes are applied. |
|
||||
| **`req`** | The [Web Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) object. This is mocked for [Local API](../local-api/overview) operations. |
|
||||
|
||||
### beforeChange
|
||||
|
||||
Immediately following validation, `beforeChange` hooks will run within the `update` operation. At this stage, you can be confident that the data that will be saved to the document is valid in accordance to your field validations. You can optionally modify the shape of data to be saved.
|
||||
@@ -70,6 +92,16 @@ const beforeChangeHook: GlobalBeforeChangeHook = async ({
|
||||
}
|
||||
```
|
||||
|
||||
The following arguments are passed to the `beforeChange` hook:
|
||||
|
||||
| Option | Description |
|
||||
| ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **`global`** | The [Global](../configuration/globals) in which this Hook is running against. |
|
||||
| **`context`** | Custom context passed between hooks. [More details](./context). |
|
||||
| **`data`** | The incoming data passed through the operation. |
|
||||
| **`originalDoc`** | The Document before changes are applied. |
|
||||
| **`req`** | The [Web Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) object. This is mocked for [Local API](../local-api/overview) operations. |
|
||||
|
||||
### afterChange
|
||||
|
||||
After a global is updated, the `afterChange` hook runs. Use this hook to purge caches of your applications, sync site data to CRMs, and more.
|
||||
@@ -86,6 +118,16 @@ const afterChangeHook: GlobalAfterChangeHook = async ({
|
||||
}
|
||||
```
|
||||
|
||||
The following arguments are passed to the `afterChange` hook:
|
||||
|
||||
| Option | Description |
|
||||
| ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **`global`** | The [Global](../configuration/globals) in which this Hook is running against. |
|
||||
| **`context`** | Custom context passed between hooks. [More details](./context). |
|
||||
| **`doc`** | The resulting Document after changes are applied. |
|
||||
| **`previousDoc`** | The Document before changes were applied. |
|
||||
| **`req`** | The [Web Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) object. This is mocked for [Local API](../local-api/overview) operations. |
|
||||
|
||||
### beforeRead
|
||||
|
||||
Runs before `findOne` global operation is transformed for output by `afterRead`. This hook fires before hidden fields are removed and before localized fields are flattened into the requested locale. Using this Hook will provide you with all locales and all hidden fields via the `doc` argument.
|
||||
@@ -99,6 +141,15 @@ const beforeReadHook: GlobalBeforeReadHook = async ({
|
||||
}) => {...}
|
||||
```
|
||||
|
||||
The following arguments are passed to the `beforeRead` hook:
|
||||
|
||||
| Option | Description |
|
||||
| ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **`global`** | The [Global](../configuration/globals) in which this Hook is running against. |
|
||||
| **`context`** | Custom context passed between hooks. [More details](./context). |
|
||||
| **`doc`** | The resulting Document after changes are applied. |
|
||||
| **`req`** | The [Web Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) object. This is mocked for [Local API](../local-api/overview) operations. |
|
||||
|
||||
### afterRead
|
||||
|
||||
Runs as the last step before a global is returned. Flattens locales, hides protected fields, and removes fields that users do not have access to.
|
||||
@@ -113,6 +164,17 @@ const afterReadHook: GlobalAfterReadHook = async ({
|
||||
}) => {...}
|
||||
```
|
||||
|
||||
The following arguments are passed to the `beforeRead` hook:
|
||||
|
||||
| Option | Description |
|
||||
| ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **`global`** | The [Global](../configuration/globals) in which this Hook is running against. |
|
||||
| **`context`** | Custom context passed between hooks. [More details](./context). |
|
||||
| **`findMany`** | Boolean to denote if this hook is running against finding one, or finding many (useful in versions). |
|
||||
| **`doc`** | The resulting Document after changes are applied. |
|
||||
| **`query`** | The [Query](../queries/overview) of the request.
|
||||
| **`req`** | The [Web Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) object. This is mocked for [Local API](../local-api/overview) operations. |
|
||||
|
||||
## TypeScript
|
||||
|
||||
Payload exports a type for each Global hook which can be accessed as follows:
|
||||
|
||||
@@ -6,42 +6,35 @@ desc: Hooks allow you to add your own logic to Payload, including integrating wi
|
||||
keywords: hooks, overview, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
|
||||
---
|
||||
|
||||
<Banner type="info">
|
||||
Hooks are powerful ways to tie into existing Payload actions in order to add your own logic like
|
||||
integrating with third-party APIs, adding auto-generated data, or modifing Payload's base
|
||||
functionality.
|
||||
</Banner>
|
||||
Hooks allow you to execute your own logic during specific events of the Document lifecycle. With Hooks, you can transform Payload from a traditional CMS into a fully-fledged application framework. They allow you to perform business tasks, third-party integrations, etc. during precise moments within the data lifecycle.
|
||||
|
||||
**With Hooks, you can transform Payload from a traditional CMS into a fully-fledged application framework.**
|
||||
There are many use cases for Hooks, including:
|
||||
|
||||
Example uses:
|
||||
|
||||
- Integrate user profiles with a third-party CRM such as Salesforce or Hubspot
|
||||
- Modify data before it is read or updated
|
||||
- Encrypt and decrypt sensitive data
|
||||
- Integrate with a third-party CRM like HubSpot or Salesforce
|
||||
- Send a copy of uploaded files to Amazon S3 or similar
|
||||
- Automatically add `lastModifiedBy` data to a document to track who changed what over time
|
||||
- Encrypt a field's data when it's saved and decrypt it when it's read
|
||||
- Send emails when `ContactSubmission`s are created from a public website
|
||||
- Integrate with a payment provider like Stripe to automatically process payments when an `Order` is created
|
||||
- Securely recalculate order prices on the backend to ensure that the total price for `Order`s that users submit is accurate and valid
|
||||
- Generate and store a `lastLoggedIn` date on a user by adding an `afterLogin` hook
|
||||
- Add extra data to documents before they are read such as "average scores" or similar data that needs to be calculated on the fly
|
||||
- Process orders through a payment provider like Stripe
|
||||
- Send emails when contact forms are submitted
|
||||
- Track data ownership or changes over time
|
||||
|
||||
There are many more use cases for Hooks and the sky is the limit.
|
||||
There are three main types of Hooks in Payload:
|
||||
|
||||
- [Collection Hooks](/docs/hooks/collections)
|
||||
- [Global Hooks](/docs/hooks/globals)
|
||||
- [Field Hooks](/docs/hooks/fields)
|
||||
|
||||
<Banner type="warning">
|
||||
<strong>Reminder:</strong>
|
||||
Payload also ships a set of _React_ hooks that you can use in your frontend application. Although they share a common name, these are very different things and should not be confused. [More details](../admin.hooks).
|
||||
</Banner>
|
||||
|
||||
## Async vs. synchronous
|
||||
|
||||
All hooks can be written as either synchronous or asynchronous functions. If the Hook should modify data before a document is updated or created, and it relies on asynchronous actions such as fetching data from a third party, it might make sense to define your Hook as an asynchronous function, so you can be sure that your Hook completes before the operation's lifecycle continues. Async hooks are run in series - so if you have two async hooks defined, the second hook will wait for the first to complete before it starts.
|
||||
All Hooks can be written as either synchronous or asynchronous functions. If the Hook should modify data before a document is updated or created, and it relies on asynchronous actions such as fetching data from a third party, it might make sense to define your Hook as an asynchronous function. This way you can be sure that your Hook completes before the operation's lifecycle continues. Async hooks are run in series - so if you have two async hooks defined, the second hook will wait for the first to complete before it starts.
|
||||
|
||||
If your Hook simply performs a side-effect, such as updating a CRM, it might be okay to define it synchronously, so the Payload operation does not have to wait for your hook to complete.
|
||||
|
||||
## Server-only execution
|
||||
|
||||
Payload Hooks are only triggered on the server and are automatically excluded from the Payload Admin bundle.
|
||||
|
||||
## Hook Types
|
||||
|
||||
You can specify hooks in the following contexts:
|
||||
|
||||
- [Collection Hooks](/docs/hooks/collections)
|
||||
- [Field Hooks](/docs/hooks/fields)
|
||||
- [Global Hooks](/docs/hooks/globals)
|
||||
Hooks are only triggered on the server and are automatically excluded from the client-side bundle. This means that you can safely use sensitive business logic in your Hooks without worrying about exposing it to the client.
|
||||
|
||||
@@ -6,7 +6,7 @@ desc: Payload + Vercel Content Link allows yours editors to navigate directly fr
|
||||
keywords: vercel, vercel content link, content link, visual editing, content source maps, Content Management System, cms, headless, javascript, node, react, nextjs
|
||||
---
|
||||
|
||||
[Vercel Content Link](https://vercel.com/docs/workflow-collaboration/edit-mode#content-link) will allow your editors to navigate directly from the content rendered on your front-end to the fields in Payload that control it. This requires no changes to your front-end code and very few changes to your Payload config.
|
||||
[Vercel Content Link](https://vercel.com/docs/workflow-collaboration/edit-mode#content-link) will allow your editors to navigate directly from the content rendered on your front-end to the fields in Payload that control it. This requires no changes to your front-end code and very few changes to your Payload Config.
|
||||
|
||||

|
||||
|
||||
@@ -30,7 +30,7 @@ Setting up Payload with Vercel Content Link is easy. First, install the `@payloa
|
||||
npm i @payloadcms/plugin-csm
|
||||
```
|
||||
|
||||
Then in the `plugins` array of your Payload config, call the plugin and enable any collections that require Content Source Maps.
|
||||
Then in the `plugins` array of your Payload Config, call the plugin and enable any collections that require Content Source Maps.
|
||||
|
||||
```ts
|
||||
import { buildConfig } from "payload/config"
|
||||
|
||||
@@ -165,17 +165,17 @@ While nodes in the client feature are added by themselves to the nodes array, no
|
||||
|
||||
| Option | Description |
|
||||
|---------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| **`getSubFields`** | If a node includes sub-fields (e.g. block and link nodes), passing the subFields schema here will make payload automatically populate & run hooks for them. |
|
||||
| **`getSubFields`** | If a node includes sub-fields (e.g. block and link nodes), passing the subFields schema here will make Payload automatically populate & run hooks for them. |
|
||||
| **`getSubFieldsData`** | If a node includes sub-fields, the sub-fields data needs to be returned here, alongside `getSubFields` which returns their schema. |
|
||||
| **`graphQLPopulationPromises`** | Allows you to run population logic when a node's data was requested from GraphQL. While `getSubFields` and `getSubFieldsData` automatically handle populating sub-fields (since they run hooks on them), those are only populated in the Rest API. This is because the Rest API hooks do not have access to the 'depth' property provided by GraphQL. In order for them to be populated correctly in GraphQL, the population logic needs to be provided here. |
|
||||
| **`node`** | The actual lexical node needs to be provided here. This also supports [lexical node replacements](https://lexical.dev/docs/concepts/node-replacement). |
|
||||
| **`validations`** | This allows you to provide node validations, which are run when your document is being validated, alongside other payload fields. You can use it to throw a validation error for a specific node in case its data is incorrect. |
|
||||
| **`validations`** | This allows you to provide node validations, which are run when your document is being validated, alongside other Payload fields. You can use it to throw a validation error for a specific node in case its data is incorrect. |
|
||||
| **`converters`** | Allows you to define how a node can be serialized into different formats. Currently, only supports HTML. Markdown converters are defined in `markdownTransformers` and not here. |
|
||||
| **`hooks`** | Just like payload fields, you can provide hooks which are run for this specific node. These are called Node Hooks. |
|
||||
| **`hooks`** | Just like Payload fields, you can provide hooks which are run for this specific node. These are called Node Hooks. |
|
||||
|
||||
### Feature load order
|
||||
|
||||
Server features can also accept a function as the `feature` property (useful for sanitizing props, as mentioned below). This function will be called when the feature is loaded during the payload sanitization process:
|
||||
Server features can also accept a function as the `feature` property (useful for sanitizing props, as mentioned below). This function will be called when the feature is loaded during the Payload sanitization process:
|
||||
|
||||
```ts
|
||||
import { createServerFeature } from '@payloadcms/richtext-lexical';
|
||||
@@ -836,4 +836,4 @@ The reason the client feature does not have the same props available as the serv
|
||||
|
||||
## More information
|
||||
|
||||
Have a look at the [features we've already built](https://github.com/payloadcms/payload/tree/beta/packages/richtext-lexical/src/features) - understanding how they work will help you understand how to create your own. There is no difference between the features included by default and the ones you create yourself - since those features are all isolated from the "core", you have access to the same APIs, whether the feature is part of payload or not!
|
||||
Have a look at the [features we've already built](https://github.com/payloadcms/payload/tree/beta/packages/richtext-lexical/src/features) - understanding how they work will help you understand how to create your own. There is no difference between the features included by default and the ones you create yourself - since those features are all isolated from the "core", you have access to the same APIs, whether the feature is part of Payload or not!
|
||||
|
||||
@@ -57,8 +57,8 @@ import { consolidateHTMLConverters, convertLexicalToHTML } from '@payloadcms/ric
|
||||
await convertLexicalToHTML({
|
||||
converters: consolidateHTMLConverters({ editorConfig }),
|
||||
data: editorData,
|
||||
payload, // if you have payload but no req available, pass it in here to enable server-only functionality (e.g. proper conversion of upload nodes)
|
||||
req, // if you have req available, pass it in here to enable server-only functionality (e.g. proper conversion of upload nodes). No need to pass in payload if req is passed in.
|
||||
payload, // if you have Payload but no req available, pass it in here to enable server-only functionality (e.g. proper conversion of upload nodes)
|
||||
req, // if you have req available, pass it in here to enable server-only functionality (e.g. proper conversion of upload nodes). No need to pass in Payload if req is passed in.
|
||||
})
|
||||
```
|
||||
This method employs `convertLexicalToHTML` from `@payloadcms/richtext-lexical`, which converts the serialized editor state into HTML.
|
||||
@@ -204,7 +204,7 @@ import { createHeadlessEditor } from '@lexical/headless' // <= make sure this pa
|
||||
import { getEnabledNodes, sanitizeServerEditorConfig } from '@payloadcms/richtext-lexical'
|
||||
|
||||
const yourEditorConfig // <= your editor config here
|
||||
const payloadConfig // <= your payload config here
|
||||
const payloadConfig // <= your Payload Config here
|
||||
|
||||
const headlessEditor = createHeadlessEditor({
|
||||
nodes: getEnabledNodes({
|
||||
@@ -337,7 +337,7 @@ Convert markdown content to the Lexical editor format with the following:
|
||||
import { $convertFromMarkdownString } from '@lexical/markdown'
|
||||
import { sanitizeServerEditorConfig } from '@payloadcms/richtext-lexical'
|
||||
|
||||
const yourSanitizedEditorConfig = sanitizeServerEditorConfig(yourEditorConfig, payloadConfig) // <= your editor config & payload config here
|
||||
const yourSanitizedEditorConfig = sanitizeServerEditorConfig(yourEditorConfig, payloadConfig) // <= your editor config & Payload Config here
|
||||
const markdown = `# Hello World`
|
||||
|
||||
headlessEditor.update(
|
||||
@@ -365,7 +365,7 @@ import { $convertToMarkdownString } from '@lexical/markdown'
|
||||
import { sanitizeServerEditorConfig } from '@payloadcms/richtext-lexical'
|
||||
import type { SerializedEditorState } from 'lexical'
|
||||
|
||||
const yourSanitizedEditorConfig = sanitizeServerEditorConfig(yourEditorConfig, payloadConfig) // <= your editor config & payload config here
|
||||
const yourSanitizedEditorConfig = sanitizeServerEditorConfig(yourEditorConfig, payloadConfig) // <= your editor config & Payload Config here
|
||||
const yourEditorState: SerializedEditorState // <= your current editor state here
|
||||
|
||||
// Import editor state into your headless editor
|
||||
|
||||
@@ -17,7 +17,7 @@ Just import the `migrateSlateToLexical` function we provide, pass it the `payloa
|
||||
IMPORTANT: This will overwrite all slate data. We recommend doing the following first:
|
||||
1. Take a backup of your entire database. If anything goes wrong and you do not have a backup, you are on your own and will not receive any support.
|
||||
2. Make every richText field a lexical editor. This script will only convert lexical richText fields with old Slate data
|
||||
3. Add the SlateToLexicalFeature (as seen below) first, and test it out by loading up the admin panel, to see if the migrator works as expected. You might have to build some custom converters for some fields first in order to convert custom Slate nodes. The SlateToLexicalFeature is where the converters are stored. Only fields with this feature added will be migrated.
|
||||
3. Add the SlateToLexicalFeature (as seen below) first, and test it out by loading up the Admin Panel, to see if the migrator works as expected. You might have to build some custom converters for some fields first in order to convert custom Slate nodes. The SlateToLexicalFeature is where the converters are stored. Only fields with this feature added will be migrated.
|
||||
|
||||
```ts
|
||||
import { migrateSlateToLexical } from '@payloadcms/richtext-lexical'
|
||||
@@ -55,7 +55,7 @@ and done! Now, everytime this lexical editor is initialized, it converts the sla
|
||||
This is by far the easiest way to migrate from Slate to Lexical, although it does come with a few caveats:
|
||||
|
||||
- There is a performance hit when initializing the lexical editor
|
||||
- The editor will still output the Slate data in the output JSON, as the on-the-fly converter only runs for the admin panel
|
||||
- The editor will still output the Slate data in the output JSON, as the on-the-fly converter only runs for the Admin Panel
|
||||
|
||||
The easy way to solve this: Edit the richText field and save the document! This overrides the slate data with the lexical data, and the next time the document is loaded, the lexical data will be used. This solves both the performance and the output issue for that specific document. This, however, is a slow and gradual migration process, thus you will have to support both API formats. Especially for a large number of documents, we recommend running the migration script, as explained above.
|
||||
|
||||
@@ -134,7 +134,7 @@ Each lexical node has a `version` property which is saved in the database. Every
|
||||
|
||||
The problem is, this migration only happens when you open the editor, modify the richText field (so that the field's `setValue` function is called) and save the document. Until you do that for all documents, some documents will still have the old data.
|
||||
|
||||
To solve this, we export an `upgradeLexicalData` function which goes through every single document in your payload app and re-saves it, if it has a lexical editor. This way, the data is automatically converted to the new format, and that automatic conversion gets applied to every single document in your app.
|
||||
To solve this, we export an `upgradeLexicalData` function which goes through every single document in your Payload app and re-saves it, if it has a lexical editor. This way, the data is automatically converted to the new format, and that automatic conversion gets applied to every single document in your app.
|
||||
|
||||
IMPORTANT: Take a backup of your entire database. If anything goes wrong and you do not have a backup, you are on your own and will not receive any support.
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ To use the Lexical editor, first you need to install it:
|
||||
npm install @payloadcms/richtext-lexical
|
||||
```
|
||||
|
||||
Once you have it installed, you can pass it to your top-level Payload config as follows:
|
||||
Once you have it installed, you can pass it to your top-level Payload Config as follows:
|
||||
|
||||
```ts
|
||||
import { buildConfig } from 'payload'
|
||||
|
||||
@@ -41,7 +41,7 @@ And return the following values:
|
||||
</Banner>
|
||||
|
||||
<Banner type="info">
|
||||
It is important that the `depth` argument matches exactly with the depth of your initial page request. The depth property is used to populated relationships and uploads beyond their IDs. See [Depth](../getting-started/concepts#depth) for more information.
|
||||
It is important that the `depth` argument matches exactly with the depth of your initial page request. The depth property is used to populated relationships and uploads beyond their IDs. See [Depth](../queries/depth) for more information.
|
||||
</Banner>
|
||||
|
||||
## Frameworks
|
||||
@@ -246,7 +246,7 @@ For a working demonstration of this, check out the official [Live Preview Exampl
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Relationships and/or uploads are not populating
|
||||
#### Relationships and/or uploads are not populating
|
||||
|
||||
If you are using relationships or uploads in your front-end application, and your front-end application runs on a different domain than your Payload server, you may need to configure [CORS](../configuration/overview) to allow requests to be made between the two domains. This includes sites that are running on a different port or subdomain. Similarly, if you are protecting resources behind user authentication, you may also need to configure [CSRF](../authentication/overview#csrf-protection) to allow cookies to be sent between the two domains. For example:
|
||||
|
||||
@@ -271,9 +271,9 @@ If you are using relationships or uploads in your front-end application, and you
|
||||
}
|
||||
```
|
||||
|
||||
### Relationships and/or uploads disappear after editing a document
|
||||
#### Relationships and/or uploads disappear after editing a document
|
||||
|
||||
It is possible that either you are setting an improper [`depth`](../getting-started/concepts#depth) in your initial request and/or your `useLivePreview` hook, or they're mismatched. Ensure that the `depth` parameter is set to the correct value, and that it matches exactly in both places. For example:
|
||||
It is possible that either you are setting an improper [`depth`](../queries/depth) in your initial request and/or your `useLivePreview` hook, or they're mismatched. Ensure that the `depth` parameter is set to the correct value, and that it matches exactly in both places. For example:
|
||||
|
||||
```tsx
|
||||
// Your initial request
|
||||
@@ -297,7 +297,7 @@ const { data } = useLivePreview<PageType>({
|
||||
})
|
||||
```
|
||||
|
||||
### Iframe refuses to connect
|
||||
#### Iframe refuses to connect
|
||||
|
||||
If your front-end application has set a [Content Security Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP) (CSP) that blocks the Admin Panel from loading your front-end application, the iframe will not be able to load your site. To resolve this, you can whitelist the Admin Panel's domain in your CSP by setting the `frame-ancestors` directive:
|
||||
|
||||
|
||||
@@ -10,12 +10,6 @@ With Live Preview you can render your front-end application directly within the
|
||||
|
||||
Live Preview works by rendering an iframe on the page that loads your front-end application. The Admin Panel communicates with your app through [`window.postMessage`](https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage) events. These events are emitted every time a change is made to the document. Your app then listens for these events and re-renders itself with the data it receives.
|
||||
|
||||
{/* IMAGE OF LIVE PREVIEW HERE */}
|
||||
|
||||
## Setup
|
||||
|
||||
Setting up Live Preview is easy. This can be done either globally through the [Root Config](../configuration/overview), or on individual [Collection](../configuration/collections) and [Global](../configuration/globals) configs. Once configured, a new "Live Preview" tab will appear at the top of enabled documents. Navigating to this tab opens the preview window and loads your front-end application.
|
||||
|
||||
To add Live Preview, use the `admin.livePreview` property in your [Payload Config](../configuration/overview):
|
||||
|
||||
```ts
|
||||
@@ -27,14 +21,20 @@ const config = buildConfig({
|
||||
// ...
|
||||
// highlight-start
|
||||
livePreview: {
|
||||
url: 'http://localhost:3000', // The URL to your front-end, this can also be a function (see below)
|
||||
collections: ['pages'], // The Collection(s) to enable Live Preview on (Globals are also possible)
|
||||
url: 'http://localhost:3000',
|
||||
collections: ['pages']
|
||||
},
|
||||
// highlight-end
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
{/* IMAGE OF LIVE PREVIEW HERE */}
|
||||
|
||||
## Options
|
||||
|
||||
Setting up Live Preview is easy. This can be done either globally through the [Root Config](../configuration/overview), or on individual [Collection](../configuration/collections) and [Global](../configuration/globals) configs. Once configured, a new "Live Preview" tab will appear at the top of enabled documents. Navigating to this tab opens the preview window and loads your front-end application.
|
||||
|
||||
The following options are available:
|
||||
|
||||
| Path | Description |
|
||||
|
||||
@@ -164,7 +164,7 @@ For a working demonstration of this, check out the official [Live Preview Exampl
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Updates do not appear as fast as client-side Live Preview
|
||||
#### Updates do not appear as fast as client-side Live Preview
|
||||
|
||||
If you are noticing that updates feel less snappy than client-side Live Preview (i.e. the `useLivePreview` hook), this is because of how the two differ in how they work—instead of emitting events against _form state_, server-side Live Preview refreshes the route after a new document is _saved_.
|
||||
|
||||
@@ -183,7 +183,7 @@ Use [Autosave](../versions/autosave) to mimic this effect server-side. Try decre
|
||||
}
|
||||
```
|
||||
|
||||
### Iframe refuses to connect
|
||||
#### Iframe refuses to connect
|
||||
|
||||
If your front-end application has set a [Content Security Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP) (CSP) that blocks the Admin Panel from loading your front-end application, the iframe will not be able to load your site. To resolve this, you can whitelist the Admin Panel's domain in your CSP by setting the `frame-ancestors` directive:
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
title: Using Payload outside Next.js
|
||||
label: Outside Next.js
|
||||
order: 20
|
||||
desc: Payload can be used outside of Next.js within standalone scripts or in other frameworks like Remix, Sveltekit, Nuxt, and similar.
|
||||
desc: Payload can be used outside of Next.js within standalone scripts or in other frameworks like Remix, Sveltekit, Nuxt, and similar.
|
||||
keywords: local api, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, express
|
||||
---
|
||||
|
||||
@@ -11,16 +11,16 @@ Payload can be used completely outside of Next.js which is helpful in cases like
|
||||
<Banner>
|
||||
<strong>Note:</strong>
|
||||
<br/>
|
||||
Payload and all of its official packages are fully ESM. If you want to use Payload within your own projects, make sure you are writing your scripts in ESM format or dynamically importing the Payload config.
|
||||
Payload and all of its official packages are fully ESM. If you want to use Payload within your own projects, make sure you are writing your scripts in ESM format or dynamically importing the Payload Config.
|
||||
</Banner>
|
||||
|
||||
## Importing the Payload config outside of Next.js
|
||||
## Importing the Payload Config outside of Next.js
|
||||
|
||||
Your Payload config likely has imports which need to be handled properly, such as CSS imports and similar. If you were to try and import your config without any Node support for SCSS / CSS files, you'll see errors that arise accordingly.
|
||||
Your Payload Config likely has imports which need to be handled properly, such as CSS imports and similar. If you were to try and import your config without any Node support for SCSS / CSS files, you'll see errors that arise accordingly.
|
||||
|
||||
This is especially relevant if you are importing your Payload config outside of a bundler context, such as in standalone Node scripts.
|
||||
This is especially relevant if you are importing your Payload Config outside of a bundler context, such as in standalone Node scripts.
|
||||
|
||||
For these cases, you can use Payload's `importConfig` function to handle importing your config safely. It will handle everything you need to be able to load and use your Payload config, without any client-side files present.
|
||||
For these cases, you can use Payload's `importConfig` function to handle importing your config safely. It will handle everything you need to be able to load and use your Payload Config, without any client-side files present.
|
||||
|
||||
Here's an example of a seed script that creates a few documents for local development / testing purposes, using Payload's `importConfig` function to safely import Payload, and the `getPayload` function to retrieve an initialized copy of Payload.
|
||||
|
||||
@@ -30,7 +30,7 @@ Here's an example of a seed script that creates a few documents for local develo
|
||||
// you should always use `import { getPayloadHMR } from '@payloadcms/next/utilities'` instead.
|
||||
import { getPayload } from 'payload'
|
||||
|
||||
// This is a helper function that will make sure we can safely load the Payload config
|
||||
// This is a helper function that will make sure we can safely load the Payload Config
|
||||
// and all of its client-side files, such as CSS, SCSS, etc.
|
||||
import { importConfig } from 'payload/node'
|
||||
|
||||
@@ -43,7 +43,7 @@ import dotenv from 'dotenv'
|
||||
const filename = fileURLToPath(import.meta.url)
|
||||
const dirname = path.dirname(filename)
|
||||
|
||||
// If you don't need to load your .env file,
|
||||
// If you don't need to load your .env file,
|
||||
// then you can skip this part!
|
||||
dotenv.config({
|
||||
path: path.resolve(dirname, '../.env'),
|
||||
|
||||
@@ -55,9 +55,9 @@ import config from '@payload-config'
|
||||
const payload = await getPayloadHMR({ config })
|
||||
```
|
||||
|
||||
You should import Payload using the first option (`getPayloadHMR`) if you are using Payload inside of Next.js (like route handlers, server components, and similar.)
|
||||
You should import Payload using the first option (`getPayloadHMR`) if you are using Payload inside of Next.js (like route handlers, server components, and similar.)
|
||||
|
||||
This way, in Next.js development mode, Payload will work with Hot Module Replacement (HMR), and as you make changes to your Payload config, your usage of Payload will always be in sync with your changes. In production, `getPayloadHMR` simply disables all HMR functionality so you don't need to write your code any differently. We handle optimization for you in production mode.
|
||||
This way, in Next.js development mode, Payload will work with Hot Module Replacement (HMR), and as you make changes to your Payload Config, your usage of Payload will always be in sync with your changes. In production, `getPayloadHMR` simply disables all HMR functionality so you don't need to write your code any differently. We handle optimization for you in production mode.
|
||||
|
||||
If you are accessing Payload via function arguments or `req.payload`, HMR is automatically supported if you are using it within Next.js.
|
||||
|
||||
@@ -73,7 +73,7 @@ const config = await importConfig('./payload.config.ts')
|
||||
const payload = await getPayload({ config })
|
||||
```
|
||||
|
||||
Both options function in exactly the same way outside of one having HMR support and the other not. However, when you import your Payload config, you need to make sure that you can import it safely.
|
||||
Both options function in exactly the same way outside of one having HMR support and the other not. However, when you import your Payload Config, you need to make sure that you can import it safely.
|
||||
|
||||
For more information about using Payload outside of Next.js, [click here](/docs/beta/local-api/outside-nextjs).
|
||||
|
||||
@@ -85,7 +85,7 @@ You can specify more options within the Local API vs. REST or GraphQL due to the
|
||||
| ------------------ | ------------ |
|
||||
| `collection` | Required for Collection operations. Specifies the Collection slug to operate against. |
|
||||
| `data` | The data to use within the operation. Required for `create`, `update`. |
|
||||
| `depth` | [Control auto-population](/docs/getting-started/concepts#depth) of nested relationship and upload fields. |
|
||||
| `depth` | [Control auto-population](../queries/depth) of nested relationship and upload fields. |
|
||||
| `locale` | Specify [locale](/docs/configuration/localization) for any returned documents. |
|
||||
| `fallbackLocale` | Specify a [fallback locale](/docs/configuration/localization) to use for any returned documents. |
|
||||
| `overrideAccess` | Skip access control. By default, this property is set to true within all Local API operations. |
|
||||
|
||||
@@ -9,11 +9,11 @@ The core logic and principles of Payload remain the same for 3.0. The brunt of t
|
||||
|
||||
## To migrate from Payload 2.0 to 3.0:
|
||||
|
||||
1. Delete the `admin.bundler` property from your Payload config:
|
||||
1. Delete the `admin.bundler` property from your Payload Config:
|
||||
|
||||
Payload no longer bundles the admin panel. Instead, we rely directly on Next.js for bundling. This also means that the `@payloadcms/bundler-webpack` and `@payloadcms/bundler-vite` packages have been deprecated. You can completely uninstall those from your project by removing them from your `package.json` file and re-running your package manager’s installation process, i.e. `pnpm i`.
|
||||
Payload no longer bundles the Admin Panel. Instead, we rely directly on Next.js for bundling. This also means that the `@payloadcms/bundler-webpack` and `@payloadcms/bundler-vite` packages have been deprecated. You can completely uninstall those from your project by removing them from your `package.json` file and re-running your package manager’s installation process, i.e. `pnpm i`.
|
||||
|
||||
2. Add the `secret` property to your Payload config. This used to be set in the `payload.init()` function of your `server.ts` file. Move it to `payload.config.ts` instead:
|
||||
2. Add the `secret` property to your Payload Config. This used to be set in the `payload.init()` function of your `server.ts` file. Move it to `payload.config.ts` instead:
|
||||
|
||||
```tsx
|
||||
// payload.config.ts
|
||||
@@ -24,7 +24,7 @@ buildConfig({
|
||||
})
|
||||
```
|
||||
|
||||
3. The `admin.css` and `admin.scss` properties in the Payload config have been removed:
|
||||
3. The `admin.css` and `admin.scss` properties in the Payload Config have been removed:
|
||||
|
||||
Instead for any global styles you can:
|
||||
|
||||
@@ -67,7 +67,7 @@ Instead, use the new `beforeDuplicate` field-level hook which take the usual fie
|
||||
```tsx
|
||||
// ❌ Before
|
||||
// file: collections/Posts.ts
|
||||
import type { CollectionConfig } from 'payload/types'
|
||||
import type { CollectionConfig } from 'payload'
|
||||
|
||||
export const PostsCollection: CollectionConfig = {
|
||||
slug: 'posts',
|
||||
@@ -414,7 +414,7 @@ export const MyClientComponent = {
|
||||
}
|
||||
```
|
||||
|
||||
8. The `custom` property in the Payload config, i.e. collections, globals, blocks, and fields are now ***server only***.
|
||||
8. The `custom` property in the Payload Config, i.e. collections, globals, blocks, and fields are now ***server only***.
|
||||
|
||||
Use `admin.custom` properties will be available in both server and client bundles.
|
||||
|
||||
@@ -708,11 +708,11 @@ This was changed for improved semantics. If you were previously importing this t
|
||||
```tsx
|
||||
// ❌ Before
|
||||
|
||||
import type { Fields } from 'payload/types'
|
||||
import type { Fields } from 'payload'
|
||||
|
||||
// ✅ After
|
||||
|
||||
import type { FormState } from 'payload/types'
|
||||
import type { FormState } from 'payload'
|
||||
```
|
||||
|
||||
16. The `useDocumentInfo` hook no longer returns a `SanizitedCollectionConfig` or `SanitizedGlobalConfig`:
|
||||
@@ -868,7 +868,7 @@ const { i18n, t } = useTranslation()
|
||||
return <p>{t('general:cancel')}</p>
|
||||
```
|
||||
|
||||
- `react-i18n` was removed, the `Trans` component from react-i18n has been replaced with a payload provided solution. You can instead `import { Translation } from "@payloadcms/ui"`
|
||||
- `react-i18n` was removed, the `Trans` component from react-i18n has been replaced with a Payload provided solution. You can instead `import { Translation } from "@payloadcms/ui"`
|
||||
|
||||
```tsx
|
||||
// Translation string example
|
||||
@@ -1017,7 +1017,7 @@ import { addLocalesToRequest } from '@payloadcms/next/utilities'
|
||||
|
||||
## Uploads
|
||||
|
||||
- `staticDir` must now be an absolute path. Before it would attempt to use the location of the payload config and merge the relative path set for staticDir.
|
||||
- `staticDir` must now be an absolute path. Before it would attempt to use the location of the Payload Config and merge the relative path set for staticDir.
|
||||
- `staticURL` has been removed. If you were using this format URLs when using an external provider, you can leverage the `generateFileURL` functions in order to do the same.
|
||||
|
||||
## Email Adapters
|
||||
|
||||
@@ -16,7 +16,7 @@ Building your own [Payload Plugin](./overview) is easy, and if you're alrea
|
||||
|
||||
Our plugin template includes everything you need to build a full life-cycle plugin:
|
||||
|
||||
- Example files and functions for extending the payload config
|
||||
- Example files and functions for extending the Payload Config
|
||||
- A local dev environment to develop the plugin
|
||||
- Test suite with integrated GitHub workflow
|
||||
|
||||
@@ -28,7 +28,7 @@ Here is a brief recap of how to integrate plugins with Payload, to learn more he
|
||||
|
||||
### How to install a plugin
|
||||
|
||||
To install any plugin, simply add it to your Payload config in the plugins array.
|
||||
To install any plugin, simply add it to your Payload Config in the plugins array.
|
||||
|
||||
```
|
||||
import samplePlugin from 'sample-plugin';
|
||||
@@ -183,7 +183,7 @@ export const samplePlugin =
|
||||
}
|
||||
```
|
||||
|
||||
1. First, you need to receive the existing Payload config along with any plugin options.
|
||||
1. First, you need to receive the existing Payload Config along with any plugin options.
|
||||
2. Then set the variable `config` to be equal to a copy of the existing config.
|
||||
3. From here, you can extend the config however you like!
|
||||
4. Finally, return the config and you're all set.
|
||||
@@ -192,7 +192,7 @@ export const samplePlugin =
|
||||
|
||||
[Spread syntax](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax) (or the spread operator) is a feature in JavaScript that uses the dot notation **(...)** to spread elements from arrays, strings, or objects into various contexts.
|
||||
|
||||
We are going to use spread syntax to allow us to add data to existing arrays without losing the existing data. It is crucial to spread the existing data correctly, else this can cause adverse behavior and conflicts with Payload config and other plugins.
|
||||
We are going to use spread syntax to allow us to add data to existing arrays without losing the existing data. It is crucial to spread the existing data correctly, else this can cause adverse behavior and conflicts with Payload Config and other plugins.
|
||||
|
||||
Let's say you want to build a plugin that adds a new collection:
|
||||
|
||||
@@ -204,7 +204,7 @@ config.collections = [
|
||||
]
|
||||
```
|
||||
|
||||
First, you need to spread the `config.collections` to ensure that we don't lose the existing collections. Then you can add any additional collections, just as you would in a regular payload config.
|
||||
First, you need to spread the `config.collections` to ensure that we don't lose the existing collections. Then you can add any additional collections, just as you would in a regular Payload Config.
|
||||
|
||||
This same logic is applied to other properties like admin, globals, hooks:
|
||||
|
||||
@@ -270,7 +270,7 @@ The best way to share and allow others to use your plugin once it is complete is
|
||||
|
||||
### Add payload-plugin topic tag
|
||||
|
||||
Apply the tag **payload-plugin** to your GitHub repository. This will boost the visibility of your plugin and ensure it gets listed with [existing payload plugins](https://github.com/topics/payload-plugin).
|
||||
Apply the tag **payload-plugin** to your GitHub repository. This will boost the visibility of your plugin and ensure it gets listed with [existing Payload plugins](https://github.com/topics/payload-plugin).
|
||||
|
||||
### Use Semantic Versioning (SemVer)
|
||||
|
||||
|
||||
@@ -2,15 +2,15 @@
|
||||
title: Form Builder Plugin
|
||||
label: Form Builder
|
||||
order: 20
|
||||
desc: Easily build and manage forms from the admin panel. Send dynamic, personalized emails and even accept and process payments.
|
||||
desc: Easily build and manage forms from the Admin Panel. Send dynamic, personalized emails and even accept and process payments.
|
||||
keywords: plugins, plugin, form, forms, form builder
|
||||
---
|
||||
|
||||
[](https://www.npmjs.com/package/@payloadcms/plugin-form-builder)
|
||||
|
||||
This plugin allows you to build and manage custom forms directly within the admin panel. Instead of hard-coding a new form into your website or application every time you need one, admins can simply define the schema for each form they need on-the-fly, and your front-end can map over this schema, render its own UI components, and match your brand's design system.
|
||||
This plugin allows you to build and manage custom forms directly within the [Admin Panel](../admin/overview). Instead of hard-coding a new form into your website or application every time you need one, admins can simply define the schema for each form they need on-the-fly, and your front-end can map over this schema, render its own UI components, and match your brand's design system.
|
||||
|
||||
All form submissions are stored directly in your database and are managed directly from the admin panel. When forms are submitted, you can display a custom on-screen confirmation message to the user or redirect them to a dedicated confirmation page. You can even send dynamic, personalized emails derived from the form's data. For example, you may want to send a confirmation email to the user who submitted the form, and also send a notification email to your team.
|
||||
All form submissions are stored directly in your database and are managed directly from the Admin Panel. When forms are submitted, you can display a custom on-screen confirmation message to the user or redirect them to a dedicated confirmation page. You can even send dynamic, personalized emails derived from the form's data. For example, you may want to send a confirmation email to the user who submitted the form, and also send a notification email to your team.
|
||||
|
||||
Forms can be as simple or complex as you need, from a basic contact form, to a multi-step lead generation engine, or even a donation form that processes payment. You may not need to reach for third-party services like HubSpot or Mailchimp for this, but instead use your own first-party tooling, built directly into your own application.
|
||||
|
||||
@@ -25,7 +25,7 @@ Forms can be as simple or complex as you need, from a basic contact form, to a m
|
||||
|
||||
## Core Features
|
||||
|
||||
- Build completely dynamic forms directly from the admin panel for a variety of use cases
|
||||
- Build completely dynamic forms directly from the Admin Panel for a variety of use cases
|
||||
- Render forms on your front-end using your own UI components and match your brand's design system
|
||||
- Send dynamic, personalized emails upon form submission to multiple recipients, derived from the form's data
|
||||
- Display a custom confirmation message or automatically redirect upon form submission
|
||||
@@ -41,10 +41,10 @@ pnpm add @payloadcms/plugin-form-builder
|
||||
|
||||
## Basic Usage
|
||||
|
||||
In the `plugins` array of your [Payload config](https://payloadcms.com/docs/configuration/overview), call the plugin with [options](#options):
|
||||
In the `plugins` array of your [Payload Config](https://payloadcms.com/docs/configuration/overview), call the plugin with [options](#options):
|
||||
|
||||
```ts
|
||||
import { buildConfig } from 'payload/config'
|
||||
import { buildConfig } from 'payload'
|
||||
import { formBuilderPlugin } from '@payloadcms/plugin-form-builder'
|
||||
|
||||
const config = buildConfig({
|
||||
|
||||
@@ -53,11 +53,11 @@ or [PNPM](https://pnpm.io):
|
||||
|
||||
## Basic Usage
|
||||
|
||||
In the `plugins` array of your [Payload config](https://payloadcms.com/docs/configuration/overview), call the plugin
|
||||
In the `plugins` array of your [Payload Config](https://payloadcms.com/docs/configuration/overview), call the plugin
|
||||
with [options](#options):
|
||||
|
||||
```ts
|
||||
import { buildConfig } from 'payload/config'
|
||||
import { buildConfig } from 'payload'
|
||||
import { nestedDocsPlugin } from '@payloadcms/plugin-nested-docs'
|
||||
|
||||
const config = buildConfig({
|
||||
@@ -177,7 +177,7 @@ You can also extend the built-in `parent` and `breadcrumbs` fields per collectio
|
||||
and `createBreadcrumbField` methods. They will merge your customizations overtop the plugin's base field configurations.
|
||||
|
||||
```ts
|
||||
import { CollectionConfig } from 'payload/types'
|
||||
import { CollectionConfig } from 'payload'
|
||||
import { createParentField } from '@payloadcms/plugin-nested-docs/fields'
|
||||
import { createBreadcrumbsField } from '@payloadcms/plugin-nested-docs/fields'
|
||||
|
||||
@@ -224,7 +224,7 @@ const examplePageConfig: CollectionConfig = {
|
||||
|
||||
## Localization
|
||||
|
||||
This plugin supports localization by default. If the `localization` property is set in your Payload config,
|
||||
This plugin supports localization by default. If the `localization` property is set in your Payload Config,
|
||||
the `breadcrumbs` field is automatically localized. For more details on how localization works in Payload, see
|
||||
the [Localization](https://payloadcms.com/docs/localization/overview) docs.
|
||||
|
||||
|
||||
@@ -6,11 +6,26 @@ desc: Plugins provide a great way to modularize Payload functionalities into eas
|
||||
keywords: plugins, config, configuration, extensions, custom, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
|
||||
---
|
||||
|
||||
Payload Plugins take full advantage of the modularity of the [Payload Config](../configuration/overview), allowing developers to easily extend Payload's core functionality in a precise and granular way. This pattern allows developers to easily inject custom—sometimes complex—functionality into Payload apps from a very small touch-point.
|
||||
Payload Plugins take full advantage of the modularity of the [Payload Config](../configuration/overview), allowing developers to extend Payload's core functionality in a precise and granular way. This pattern allows developers to easily inject custom—sometimes complex—functionality into Payload apps from a very small touch-point.
|
||||
|
||||
There are many [Official Plugins](#official-plugins) available that solve for some of the most common uses cases, such as the [Form Builder Plugin](./seo) or [SEO Plugin](./seo). There are also [Community Plugins](#community-plugins) available, maintained entirely by contributing members. To extend Payload's functionality in some other way, you can easily [build your own plugin](./build-your-own).
|
||||
|
||||
Writing plugins is no more complex than writing regular JavaScript. If you know the basic concept of [callback functions](https://developer.mozilla.org/en-US/docs/Glossary/Callback_function) or how [spread syntax](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax) works, and are up to speed with Payload concepts, then writing a plugin will be a breeze.
|
||||
To configure Plugins, use the `plugins` property in your [Payload Config](../configuration/overview):
|
||||
|
||||
```ts
|
||||
import { buildConfig } from 'payload'
|
||||
|
||||
const config = buildConfig({
|
||||
// ...
|
||||
// highlight-start
|
||||
plugins: [
|
||||
// Add Plugins here
|
||||
],
|
||||
// highlight-end
|
||||
})
|
||||
```
|
||||
|
||||
Writing Plugins is no more complex than writing regular JavaScript. If you know the basic concept of [callback functions](https://developer.mozilla.org/en-US/docs/Glossary/Callback_function) or how [spread syntax](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax) works, and are up to speed with Payload concepts, then writing a plugin will be a breeze.
|
||||
|
||||
<Banner type="success">
|
||||
Because we rely on a simple config-based structure, Payload Plugins simply take in an
|
||||
@@ -23,7 +38,7 @@ Writing plugins is no more complex than writing regular JavaScript. If you know
|
||||
- Automatically sync data from a specific collection to HubSpot or a similar CRM when data is added or changes
|
||||
- Add password-protection functionality to certain documents
|
||||
- Add a full e-commerce backend to any Payload app
|
||||
- Add custom reporting views to Payload's admin panel
|
||||
- Add custom reporting views to Payload's Admin Panel
|
||||
- Encrypt specific collections' data
|
||||
- Add a full form builder implementation
|
||||
- Integrate all `upload`-enabled collections with a third-party file host like S3 or Cloudinary
|
||||
@@ -59,32 +74,19 @@ Some plugins have become so widely used that they are adopted as an [Official Pl
|
||||
For maintainers building plugins for others to use, please add the `payload-plugin` topic on [GitHub](https://github.com/topics/payload-plugin) to help others find it.
|
||||
</Banner>
|
||||
|
||||
## Installing Plugins
|
||||
## Example
|
||||
|
||||
The base [Payload Config](../configuration/overview) allows for a `plugins` property which takes an `array` of [Plugin Configs](./build-your-own).
|
||||
|
||||
```ts
|
||||
import { buildConfig } from 'payload/config'
|
||||
// note: these plugins are not real (yet?)
|
||||
import addLastModified from 'payload-add-last-modified'
|
||||
import passwordProtect from 'payload-password-protect'
|
||||
import { buildConfig } from 'payload'
|
||||
import { addLastModified } from './addLastModified.ts'
|
||||
|
||||
const config = buildConfig({
|
||||
// ...
|
||||
// highlight-start
|
||||
plugins: [
|
||||
// Many plugins require options to be passed.
|
||||
// In the following example, we call the function
|
||||
// and pass it options accordingly
|
||||
passwordProtect(['pages']),
|
||||
|
||||
// This plugin takes no options and just
|
||||
// needs to be passed directly
|
||||
addLastModified,
|
||||
|
||||
// ..
|
||||
// To understand how to use the plugins you're interested in,
|
||||
// consult their corresponding documentation
|
||||
],
|
||||
// highlight-end
|
||||
})
|
||||
@@ -97,9 +99,9 @@ const config = buildConfig({
|
||||
Here is an example what the `addLastModified` plugin from above might look like. It adds a `lastModifiedBy` field to all Payload collections. For full details, see [how to build your own plugin](./build-your-own).
|
||||
|
||||
```ts
|
||||
import { Config, Plugin } from 'payload/config'
|
||||
import { Config, Plugin } from 'payload'
|
||||
|
||||
const addLastModified: Plugin = (incomingConfig: Config): Config => {
|
||||
export const addLastModified: Plugin = (incomingConfig: Config): Config => {
|
||||
// Find all incoming auth-enabled collections
|
||||
// so we can create a lastModifiedBy relationship field
|
||||
// to all auth collections
|
||||
@@ -142,6 +144,9 @@ const addLastModified: Plugin = (incomingConfig: Config): Config => {
|
||||
|
||||
return config
|
||||
}
|
||||
|
||||
export default addLastModified
|
||||
```
|
||||
|
||||
<Banner type="success">
|
||||
<strong>Reminder:</strong>
|
||||
See [how to build your own plugin](./build-your-own) for a more in-depth explication on how create your own Payload Plugin.
|
||||
</Banner>
|
||||
|
||||
@@ -8,7 +8,7 @@ keywords: plugins, redirects, redirect, plugin, payload, cms, seo, indexing, sea
|
||||
|
||||
[](https://www.npmjs.com/package/@payloadcms/plugin-redirects)
|
||||
|
||||
This plugin allows you to easily manage redirects for your application from within your admin panel. It does so by adding a `redirects` collection to your config that allows you specify a redirect from one URL to another. Your front-end application can use this data to automatically redirect users to the correct page using proper HTTP status codes. This is useful for SEO, indexing, and search engine ranking when re-platforming or when changing your URL structure.
|
||||
This plugin allows you to easily manage redirects for your application from within your [Admin Panel](../admin/overview). It does so by adding a `redirects` collection to your config that allows you specify a redirect from one URL to another. Your front-end application can use this data to automatically redirect users to the correct page using proper HTTP status codes. This is useful for SEO, indexing, and search engine ranking when re-platforming or when changing your URL structure.
|
||||
|
||||
For example, if you have a page at `/about` and you want to change it to `/about-us`, you can create a redirect from the old page to the new one, then you can use this data to write HTTP redirects into your front-end application. This will ensure that users are redirected to the correct page without penalty because search engines are notified of the change at the request level. This is a very lightweight plugin that will allow you to integrate managed redirects for any front-end framework.
|
||||
|
||||
@@ -37,10 +37,10 @@ Install the plugin using any JavaScript package manager like [Yarn](https://yarn
|
||||
|
||||
## Basic Usage
|
||||
|
||||
In the `plugins` array of your [Payload config](https://payloadcms.com/docs/configuration/overview), call the plugin with [options](#options):
|
||||
In the `plugins` array of your [Payload Config](https://payloadcms.com/docs/configuration/overview), call the plugin with [options](#options):
|
||||
|
||||
```ts
|
||||
import { buildConfig } from 'payload/config'
|
||||
import { buildConfig } from 'payload'
|
||||
import { redirectsPlugin } from '@payloadcms/plugin-redirects'
|
||||
|
||||
const config = buildConfig({
|
||||
|
||||
@@ -44,10 +44,10 @@ Install the plugin using any JavaScript package manager like [Yarn](https://yarn
|
||||
|
||||
## Basic Usage
|
||||
|
||||
In the `plugins` array of your [Payload config](https://payloadcms.com/docs/configuration/overview), call the plugin with [options](#options):
|
||||
In the `plugins` array of your [Payload Config](https://payloadcms.com/docs/configuration/overview), call the plugin with [options](#options):
|
||||
|
||||
```js
|
||||
import { buildConfig } from 'payload/config'
|
||||
import { buildConfig } from 'payload'
|
||||
import { searchPlugin } from '@payloadcms/plugin-search'
|
||||
|
||||
const config = buildConfig({
|
||||
|
||||
@@ -44,10 +44,10 @@ Install the plugin using any JavaScript package manager like [Yarn](https://yarn
|
||||
|
||||
## Basic Usage
|
||||
|
||||
In the `plugins` array of your [Payload config](https://payloadcms.com/docs/configuration/overview), call the plugin and pass in your Sentry DSN as an option.
|
||||
In the `plugins` array of your [Payload Config](https://payloadcms.com/docs/configuration/overview), call the plugin and pass in your Sentry DSN as an option.
|
||||
|
||||
```ts
|
||||
import { buildConfig } from 'payload/config'
|
||||
import { buildConfig } from 'payload'
|
||||
import { sentryPlugin } from '@payloadcms/plugin-sentry'
|
||||
import { Pages, Media } from './collections'
|
||||
|
||||
@@ -96,7 +96,7 @@ To see all options available, visit the [Sentry Docs](https://docs.sentry.io/pla
|
||||
Configure any of these options by passing them to the plugin:
|
||||
|
||||
```ts
|
||||
import { buildConfig } from 'payload/config'
|
||||
import { buildConfig } from 'payload'
|
||||
import { sentry } from '@payloadcms/plugin-sentry'
|
||||
import { Pages, Media } from './collections'
|
||||
|
||||
|
||||
@@ -8,9 +8,9 @@ keywords: plugins, seo, meta, search, engine, ranking, google
|
||||
|
||||
[](https://www.npmjs.com/package/@payloadcms/plugin-seo)
|
||||
|
||||
This plugin allows you to easily manage SEO metadata for your application from within your admin panel. When enabled on your collections and globals, it adds a new `meta` field group containing `title`, `description`, and `image` by default. Your front-end application can then use this data to render meta tags however your application requires. For example, you would inject a `title` tag into the `<head>` of your page using `meta.title` as its content.
|
||||
This plugin allows you to easily manage SEO metadata for your application from within your [Admin Panel](../admin/overview). When enabled on your [Collections](../configuration/collections) and [Globals](../configuration/globals), it adds a new `meta` field group containing `title`, `description`, and `image` by default. Your front-end application can then use this data to render meta tags however your application requires. For example, you would inject a `title` tag into the `<head>` of your page using `meta.title` as its content.
|
||||
|
||||
As users are editing documents within the admin panel, they have the option to "auto-generate" these fields. When clicked, this plugin will execute your own custom functions that re-generate the title, description, and image. This way you can build your own SEO writing assistance directly into your application. For example, you could append your site name onto the page title, or use the document's excerpt field as the description, or even integrate with some third-party API to generate the image using AI.
|
||||
As users are editing documents within the Admin Panel, they have the option to "auto-generate" these fields. When clicked, this plugin will execute your own custom functions that re-generate the title, description, and image. This way you can build your own SEO writing assistance directly into your application. For example, you could append your site name onto the page title, or use the document's excerpt field as the description, or even integrate with some third-party API to generate the image using AI.
|
||||
|
||||
To help you visualize what your page might look like in a search engine, a preview is rendered on page just beneath the meta fields. This preview is updated in real-time as you edit your metadata. There are also visual indicators to help you write effective meta, such as a character counter for the title and description fields. You can even inject your own custom fields into the `meta` field group as your application requires, like `og:title` or `json-ld`. If you've ever used something like Yoast SEO, this plugin might feel very familiar.
|
||||
|
||||
@@ -42,10 +42,10 @@ Install the plugin using any JavaScript package manager like [Yarn](https://yarn
|
||||
|
||||
## Basic Usage
|
||||
|
||||
In the `plugins` array of your [Payload config](https://payloadcms.com/docs/configuration/overview), call the plugin with [options](#options):
|
||||
In the `plugins` array of your [Payload Config](https://payloadcms.com/docs/configuration/overview), call the plugin with [options](#options):
|
||||
|
||||
```ts
|
||||
import { buildConfig } from 'payload/config';
|
||||
import { buildConfig } from 'payload';
|
||||
import { seoPlugin } from '@payloadcms/plugin-seo';
|
||||
|
||||
const config = buildConfig({
|
||||
@@ -205,7 +205,7 @@ seoPlugin({
|
||||
There is the option to directly import any of the fields from the plugin so that you can include them anywhere as needed.
|
||||
|
||||
<Banner type="info">
|
||||
You will still need to configure the plugin in the Payload config in order to configure the generation functions.
|
||||
You will still need to configure the plugin in the Payload Config in order to configure the generation functions.
|
||||
Since these fields are imported and used directly, they don't have access to the plugin config so they may need additional arguments to work the same way.
|
||||
</Banner>
|
||||
|
||||
|
||||
@@ -44,10 +44,10 @@ Install the plugin using any JavaScript package manager like [Yarn](https://yarn
|
||||
|
||||
## Basic Usage
|
||||
|
||||
In the `plugins` array of your [Payload config](https://payloadcms.com/docs/configuration/overview), call the plugin with [options](#options):
|
||||
In the `plugins` array of your [Payload Config](https://payloadcms.com/docs/configuration/overview), call the plugin with [options](#options):
|
||||
|
||||
```ts
|
||||
import { buildConfig } from 'payload/config'
|
||||
import { buildConfig } from 'payload'
|
||||
import { stripePlugin } from '@payloadcms/plugin-stripe'
|
||||
|
||||
const config = buildConfig({
|
||||
@@ -140,7 +140,7 @@ Production:
|
||||
1. Then, handle these events using the `webhooks` portion of this plugin's config:
|
||||
|
||||
```ts
|
||||
import { buildConfig } from 'payload/config'
|
||||
import { buildConfig } from 'payload'
|
||||
import stripePlugin from '@payloadcms/plugin-stripe'
|
||||
|
||||
const config = buildConfig({
|
||||
@@ -239,7 +239,7 @@ This option will setup a basic sync between Payload collections and Stripe resou
|
||||
</Banner>
|
||||
|
||||
```ts
|
||||
import { buildConfig } from 'payload/config'
|
||||
import { buildConfig } from 'payload'
|
||||
import stripePlugin from '@payloadcms/plugin-stripe'
|
||||
|
||||
const config = buildConfig({
|
||||
@@ -254,7 +254,7 @@ const config = buildConfig({
|
||||
stripeResourceTypeSingular: 'customer',
|
||||
fields: [
|
||||
{
|
||||
fieldPath: 'name', // this is a field on your own Payload config
|
||||
fieldPath: 'name', // this is a field on your own Payload Config
|
||||
stripeProperty: 'name', // use dot notation, if applicable
|
||||
},
|
||||
],
|
||||
|
||||
@@ -16,7 +16,7 @@ Set the max number of failed login attempts before a user account is locked out
|
||||
|
||||
## Max Depth
|
||||
|
||||
Querying a collection and automatically including related documents via `depth` incurs a performance cost. Also, it's possible that your configs may have circular relationships, meaning scenarios where an infinite amount of relationships might populate back and forth until your server times out and crashes. You can prevent any potential of depth-related issues by setting a `maxDepth` property on your Payload config.. The maximum allowed depth should be as small as possible without interrupting dev experience, and it defaults to `10`.
|
||||
Querying a collection and automatically including related documents via `depth` incurs a performance cost. Also, it's possible that your configs may have circular relationships, meaning scenarios where an infinite amount of relationships might populate back and forth until your server times out and crashes. You can prevent any potential of depth-related issues by setting a `maxDepth` property on your Payload Config.. The maximum allowed depth should be as small as possible without interrupting dev experience, and it defaults to `10`.
|
||||
|
||||
## Cross-Site Request Forgery (CSRF)
|
||||
|
||||
@@ -24,15 +24,15 @@ CSRF prevention will verify the authenticity of each request to your API to prev
|
||||
|
||||
## Cross Origin Resource Sharing (CORS)
|
||||
|
||||
To securely allow headless operation you will need to configure the allowed origins for requests to be able to use the Payload API. You can see how to set CORS as well as other payload configuration settings [here](/docs/configuration/overview)
|
||||
To securely allow headless operation you will need to configure the allowed origins for requests to be able to use the Payload API. You can see how to set CORS as well as other Payload configuration settings [here](/docs/configuration/overview)
|
||||
|
||||
## Limiting GraphQL Complexity
|
||||
|
||||
Because GraphQL gives the power of query writing outside a server's control, someone with bad intentions might write a maliciously complex query and bog down your server. To prevent resource-intensive GraphQL requests, Payload provides a way specify complexity limits which are based on a complexity score that is calculated for each request.
|
||||
|
||||
Any GraphQL request that is calculated to be too expensive is rejected. On the Payload config, in `graphQL` you can set the `maxComplexity` value as an integer. For reference, the default complexity value for each added field is 1, and all `relationship` and `upload` fields are assigned a value of 10.
|
||||
Any GraphQL request that is calculated to be too expensive is rejected. On the Payload Config, in `graphQL` you can set the `maxComplexity` value as an integer. For reference, the default complexity value for each added field is 1, and all `relationship` and `upload` fields are assigned a value of 10.
|
||||
|
||||
If you do not need GraphQL it is advised that you disable it altogether with the Payload config by setting `graphQL.disable: true`. Should you wish to enable GraphQL again, you can remove this property or set it `false`, any time. By turning it off, Payload will bypass creating schemas from your collections and will not register the route.
|
||||
If you do not need GraphQL it is advised that you disable it altogether with the Payload Config by setting `graphQL.disable: true`. Should you wish to enable GraphQL again, you can remove this property or set it `false`, any time. By turning it off, Payload will bypass creating schemas from your collections and will not register the route.
|
||||
|
||||
## Malicious File Uploads
|
||||
|
||||
|
||||
94
docs/queries/depth.mdx
Normal file
94
docs/queries/depth.mdx
Normal file
@@ -0,0 +1,94 @@
|
||||
---
|
||||
title: Depth
|
||||
label: Depth
|
||||
order: 30
|
||||
desc: Payload depth determines how many levels down related documents should be automatically populated when retrieved.
|
||||
keywords: query, documents, pagination, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
|
||||
---
|
||||
|
||||
Documents in Payload can have relationships to other Documents. This is true for both [Collections](../configuration/collections) as well as [Globals](../configuration/globals). When you query a Document, you can specify the depth at which to populate any of its related Documents either as full objects, or only their IDs.
|
||||
|
||||
Depth will optimize the performance of your application by limiting the amount of processing made in the database and significantly reducing the amount of data returned. Since Documents can be infinitely nested or recursively related, it's important to be able to control how deep your API populates.
|
||||
|
||||
For example, when you specify a `depth` of `0`, the API response might look like this:
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "5ae8f9bde69e394e717c8832",
|
||||
"title": "This is a great post",
|
||||
"author": "5f7dd05cd50d4005f8bcab17"
|
||||
}
|
||||
```
|
||||
|
||||
But with a `depth` of `1`, the response might look like this:
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "5ae8f9bde69e394e717c8832",
|
||||
"title": "This is a great post",
|
||||
"author": {
|
||||
"id": "5f7dd05cd50d4005f8bcab17",
|
||||
"name": "John Doe"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
<Banner type="warning">
|
||||
<strong>Important:</strong>
|
||||
Depth has no effect in the [GraphQL API](../graphql/overview), because there, depth is based on the shape of your queries.
|
||||
</Banner>
|
||||
|
||||
## Local API
|
||||
|
||||
To specify depth in the [Local API](../local-api/overview), you can use the `depth` option in your query:
|
||||
|
||||
```ts
|
||||
const getPosts = async () => {
|
||||
const posts = await payload.find({
|
||||
collection: 'posts',
|
||||
depth: 2, // highlight-line
|
||||
})
|
||||
|
||||
return posts
|
||||
}
|
||||
```
|
||||
|
||||
<Banner type="info">
|
||||
<strong>Reminder:</strong>
|
||||
This is the same for [Globals](../configuration/globals) using the `findGlobal` operation.
|
||||
</Banner>
|
||||
|
||||
## REST API
|
||||
|
||||
To specify depth in the [REST API](../rest-api/overview), you can use the `depth` parameter in your query:
|
||||
|
||||
```ts
|
||||
fetch('https://localhost:3000/api/posts?depth=2') // highlight-line
|
||||
.then((res) => res.json())
|
||||
.then((data) => console.log(data))
|
||||
```
|
||||
|
||||
<Banner type="info">
|
||||
<strong>Reminder:</strong>
|
||||
This is the same for [Globals](../configuration/globals) using the `/api/globals` endpoint.
|
||||
</Banner>
|
||||
|
||||
## Max Depth
|
||||
|
||||
Fields like the [Relationship Field](../fields/relationship) or the [Upload Field](../fields/upload) can also set a maximum depth. If exceeded, this will limit the population depth regardless of what the depth might be on the request.
|
||||
|
||||
To set a max depth for a field, use the `maxDepth` property in your field configuration:
|
||||
|
||||
```js
|
||||
{
|
||||
slug: 'posts',
|
||||
fields: [
|
||||
{
|
||||
name: 'author',
|
||||
type: 'relationship',
|
||||
relationTo: 'users',
|
||||
maxDepth: 2, // highlight-line
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
@@ -6,54 +6,37 @@ desc: Payload provides a querying language through all APIs, allowing you to fil
|
||||
keywords: query, documents, overview, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
|
||||
---
|
||||
|
||||
Payload provides an extremely granular querying language through all APIs. Each API takes the same syntax and fully supports all options.
|
||||
In Payload, "querying" means filtering or searching through Documents within a [Collection](../configuration/collections). The querying language in Payload is designed to be simple and powerful, allowing you to filter documents with extreme precision.
|
||||
|
||||
<Banner>
|
||||
<strong>
|
||||
Here, "querying" relates to filtering or searching through documents within a Collection.
|
||||
</strong>
|
||||
You can build queries to pass to Find operations as well as to [restrict which documents certain
|
||||
users can [access](/docs/access-control/overview) via access control functions.
|
||||
</Banner>
|
||||
Payload provides three common APIs for querying your data:
|
||||
|
||||
## Simple queries
|
||||
- [Local API](/docs/local-api/overview) - Extremely fast, direct-to-database access
|
||||
- [REST API](/docs/rest-api/overview) - Standard HTTP endpoints for querying and mutating data
|
||||
- [GraphQL](/docs/graphql/overview) - A full GraphQL API with a GraphQL Playground
|
||||
|
||||
For example, say you have a collection as follows:
|
||||
Each of these APIs share the same underlying querying language, and fully support all of the same features. This means that you can learn Payload's querying language once, and use it across any of the APIs that you might use.
|
||||
|
||||
To query your Documents, you can send any number of [Operators](#operators) through your request:
|
||||
|
||||
```ts
|
||||
import { CollectionConfig } from 'payload/types'
|
||||
|
||||
export const Post: CollectionConfig = {
|
||||
slug: 'posts',
|
||||
fields: [
|
||||
{
|
||||
name: 'color',
|
||||
type: 'select',
|
||||
options: ['mint', 'dark-gray', 'white'],
|
||||
},
|
||||
{
|
||||
name: 'featured',
|
||||
type: 'checkbox',
|
||||
},
|
||||
],
|
||||
}
|
||||
```
|
||||
|
||||
You may eventually have a lot of documents within this Collection. If you wanted to find only documents with `color` equal to `mint`, you could write a query as follows:
|
||||
|
||||
```js
|
||||
const query = {
|
||||
color: {
|
||||
// property name to filter on
|
||||
equals: 'mint', // operator to use and value to compare against
|
||||
equals: 'blue',
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
The above example demonstrates a simple query but you can get much more complex.
|
||||
_The exact query syntax will depend on the API you are using, but the concepts are the same across all APIs. [More details](#writing-queries)._
|
||||
|
||||
<Banner>
|
||||
<strong>Tip:</strong>
|
||||
You can also use queries within [Access Control](../access-control/overview) functions.
|
||||
</Banner>
|
||||
|
||||
## Operators
|
||||
|
||||
The following operators are available for use in queries:
|
||||
|
||||
| Operator | Description |
|
||||
| -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `equals` | The value must be exactly equal. |
|
||||
@@ -68,31 +51,29 @@ The above example demonstrates a simple query but you can get much more complex.
|
||||
| `not_in` | The value must NOT be within the provided comma-delimited list of values. |
|
||||
| `all` | The value must contain all values provided in the comma-delimited list. |
|
||||
| `exists` | Only return documents where the value either exists (`true`) or does not exist (`false`). |
|
||||
| `near` | For distance related to a [point field](/docs/fields/point) comma separated as `<longitude>, <latitude>, <maxDistance in meters (nullable)>, <minDistance in meters (nullable)>`. |
|
||||
| `near` | For distance related to a [Point Field](../fields/point) comma separated as `<longitude>, <latitude>, <maxDistance in meters (nullable)>, <minDistance in meters (nullable)>`. |
|
||||
|
||||
<Banner type="success">
|
||||
<strong>Tip</strong>:<br />
|
||||
If you know your users will be querying on certain fields a lot, you can add <strong>
|
||||
index: true
|
||||
</strong> to a field's config which will speed up searches using that field immensely.
|
||||
<strong>Tip:</strong>
|
||||
If you know your users will be querying on certain fields a lot, add `index: true` to the Field Config. This will speed up searches using that field immensely.
|
||||
</Banner>
|
||||
|
||||
## And / Or Logic
|
||||
### And / Or Logic
|
||||
|
||||
In addition to defining simple queries, you can join multiple queries together using simple AND / OR logic. Let's take the above `Post` collection for example and write a more complex query using AND / OR:
|
||||
In addition to defining simple queries, you can join multiple queries together using AND / OR logic. These can be nested as deeply as you need to create complex queries.
|
||||
|
||||
```js
|
||||
To join queries, use the `and` or `or` keys in your query object:
|
||||
|
||||
```ts
|
||||
const query = {
|
||||
or: [
|
||||
// array of OR conditions
|
||||
or: [ // highlight-line
|
||||
{
|
||||
color: {
|
||||
equals: 'mint',
|
||||
},
|
||||
},
|
||||
{
|
||||
and: [
|
||||
// nested array of AND conditions
|
||||
and: [ // highlight-line
|
||||
{
|
||||
color: {
|
||||
equals: 'white',
|
||||
@@ -111,7 +92,7 @@ const query = {
|
||||
|
||||
Written in plain English, if the above query were passed to a `find` operation, it would translate to finding posts where either the `color` is `mint` OR the `color` is `white` AND `featured` is set to false.
|
||||
|
||||
## Nested properties
|
||||
### Nested properties
|
||||
|
||||
When working with nested properties, which can happen when using relational fields, it is possible to use the dot notation to access the nested property. For example, when working with a `Song` collection that has a `artists` field which is related to an `Artists` collection using the `name: 'artists'`. You can access a property within the collection `Artists` like so:
|
||||
|
||||
@@ -124,13 +105,34 @@ const query = {
|
||||
}
|
||||
```
|
||||
|
||||
## GraphQL Find Queries
|
||||
## Writing Queries
|
||||
|
||||
All GraphQL `find` queries support the `where` argument, which accepts queries exactly as detailed above.
|
||||
Writing queries in Payload is simple and consistent across all APIs, with only minor differences in syntax between them.
|
||||
|
||||
**For example:**
|
||||
### Local API
|
||||
|
||||
The [Local API](../local-api/overview) supports the `find` operation that accepts a raw query object:
|
||||
|
||||
```ts
|
||||
const getPosts = async () => {
|
||||
const posts = await payload.find({
|
||||
collection: 'posts',
|
||||
where: {
|
||||
color: {
|
||||
equals: 'mint',
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
return posts
|
||||
}
|
||||
```
|
||||
|
||||
### GraphQL API
|
||||
|
||||
All `find` queries in the [GraphQL API](../graphql/overview) support the `where` argument that accepts a raw query object:
|
||||
|
||||
```ts
|
||||
query {
|
||||
Posts(where: { color: { equals: mint } }) {
|
||||
docs {
|
||||
@@ -141,19 +143,17 @@ query {
|
||||
}
|
||||
```
|
||||
|
||||
## REST Queries
|
||||
### REST API
|
||||
|
||||
With the REST API, you can use the full power of Payload queries as well but they become a bit more unwieldy the more complex that they get.
|
||||
|
||||
Simple queries are fairly straightforward to write. To understand the syntax, you need to understand that complex URL search strings are parsed into a JSON object. For example, the above [simple query](#simple-queries) would be parsed into a string like this:
|
||||
With the [REST API](../rest-api/overview), you can use the full power of Payload queries, but they are written as query strings instead:
|
||||
|
||||
**`https://localhost:3000/api/posts?where[color][equals]=mint`**
|
||||
|
||||
This one isn't too bad, but more complex queries get unavoidably more difficult to write as query strings. For this reason, we recommend to use the extremely helpful and ubiquitous [`qs`](https://www.npmjs.com/package/qs) package to parse your JSON / object-formatted queries into query strings for use with the REST API.
|
||||
To understand the syntax, you need to understand that complex URL search strings are parsed into a JSON object. This one isn't too bad, but more complex queries get unavoidably more difficult to write.
|
||||
|
||||
**For example, using fetch:**
|
||||
For this reason, we recommend to use the extremely helpful and ubiquitous [`qs`](https://www.npmjs.com/package/qs) package to parse your JSON / object-formatted queries into query strings:
|
||||
|
||||
```js
|
||||
```ts
|
||||
import { stringify } from 'qs-esm'
|
||||
|
||||
const query = {
|
||||
@@ -176,54 +176,3 @@ const getPosts = async () => {
|
||||
// Continue to handle the response below...
|
||||
}
|
||||
```
|
||||
|
||||
## Local API Queries
|
||||
|
||||
The Local API's `find` operation accepts an object exactly how you write it. For example:
|
||||
|
||||
```js
|
||||
const getPosts = async () => {
|
||||
const posts = await payload.find({
|
||||
collection: 'posts',
|
||||
where: {
|
||||
color: {
|
||||
equals: 'mint',
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
return posts
|
||||
}
|
||||
```
|
||||
|
||||
## Sort
|
||||
|
||||
Payload `find` queries support a `sort` parameter through all APIs. Pass the `name` of a top-level field to sort by that field in ascending order. Prefix the name of the field with a minus symbol ("-") to sort in descending order. Because sorting is handled by the database, the field you wish to sort on must be stored in the database to work; not a [virtual field](https://payloadcms.com/blog/learn-how-virtual-fields-can-help-solve-common-cms-challenges). It is recommended to enable indexing for the fields where sorting is used.
|
||||
|
||||
**REST example:**
|
||||
**`https://localhost:3000/api/posts?sort=-createdAt`**
|
||||
|
||||
**GraphQL example:**
|
||||
|
||||
```
|
||||
query {
|
||||
Posts(sort: "-createdAt") {
|
||||
docs {
|
||||
color
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Local API example:**
|
||||
|
||||
```js
|
||||
const getPosts = async () => {
|
||||
const posts = await payload.find({
|
||||
collection: 'posts',
|
||||
sort: '-createdAt',
|
||||
})
|
||||
|
||||
return posts
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
title: Pagination
|
||||
label: Pagination
|
||||
order: 20
|
||||
order: 40
|
||||
desc: Payload queries are equipped with automatic pagination so you create paginated lists of documents within your app.
|
||||
keywords: query, documents, pagination, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
|
||||
---
|
||||
|
||||
55
docs/queries/sort.mdx
Normal file
55
docs/queries/sort.mdx
Normal file
@@ -0,0 +1,55 @@
|
||||
---
|
||||
title: Sort
|
||||
label: Sort
|
||||
order: 20
|
||||
desc: Payload sort allows you to order your documents by a field in ascending or descending order.
|
||||
keywords: query, documents, pagination, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
|
||||
---
|
||||
|
||||
Documents in Payload can be easily sorted by a specific [Field](../fields/overview). When querying Documents, you can pass the name of any top-level field, and the response will sort the Documents by that field in _ascending_ order. If prefixed with a minus symbol ("-"), they will be sorted in _descending_ order.
|
||||
|
||||
Because sorting is handled by the database, the field cannot be a [Virtual Field](https://payloadcms.com/blog/learn-how-virtual-fields-can-help-solve-common-cms-challenges). It must be stored in the database to be searchable.
|
||||
|
||||
<Banner type="success">
|
||||
<strong>Tip:</strong>
|
||||
For performance reasons, it is recommended to enable `index: true` for the fields that will be sorted upon. [More details](../fields/overview).
|
||||
</Banner>
|
||||
|
||||
## Local API
|
||||
|
||||
To sort Documents in the [Local API](../local-api/overview), you can use the `sort` option in your query:
|
||||
|
||||
```ts
|
||||
const getPosts = async () => {
|
||||
const posts = await payload.find({
|
||||
collection: 'posts',
|
||||
sort: '-createdAt', // highlight-line
|
||||
})
|
||||
|
||||
return posts
|
||||
}
|
||||
```
|
||||
|
||||
## REST API
|
||||
|
||||
To sort in the [REST API](../rest-api/overview), you can use the `sort` parameter in your query:
|
||||
|
||||
```ts
|
||||
fetch('https://localhost:3000/api/posts?sort=-createdAt') // highlight-line
|
||||
.then((response) => response.json())
|
||||
.then((data) => console.log(data))
|
||||
```
|
||||
|
||||
## GraphQL API
|
||||
|
||||
To sort in the [GraphQL API](../graphql/overview), you can use the `sort` parameter in your query:
|
||||
|
||||
```ts
|
||||
query {
|
||||
Posts(sort: "-createdAt") {
|
||||
docs {
|
||||
color
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -10,11 +10,12 @@ keywords: rest, api, documentation, Content Management System, cms, headless, ja
|
||||
A fully functional REST API is automatically generated from your Collection and Global configs.
|
||||
</Banner>
|
||||
|
||||
The REST API is a fully functional HTTP client that allows you to interact with your Documents in a RESTful manner. It supports all CRUD operations and is equipped with automatic pagination, depth, and sorting.
|
||||
All Payload API routes are mounted and prefixed to your config's `routes.api` URL segment (default: `/api`).
|
||||
|
||||
**REST query parameters:**
|
||||
|
||||
- [depth](/docs/getting-started/concepts#depth) - automatically populates relationships and uploads
|
||||
- [depth](../queries/depth) - automatically populates relationships and uploads
|
||||
- [locale](/docs/configuration/localization#retrieving-localized-docs) - retrieves document(s) in a specific locale
|
||||
- [fallback-locale](/docs/configuration/localization#retrieving-localized-docs) - specifies a fallback locale if no locale value exists
|
||||
|
||||
@@ -570,7 +571,7 @@ In addition to the dynamically generated endpoints above Payload also has REST e
|
||||
|
||||
## Custom Endpoints
|
||||
|
||||
Additional REST API endpoints can be added to your application by providing an array of `endpoints` in various places within a Payload config. Custom endpoints are useful for adding additional middleware on existing routes or for building custom functionality into Payload apps and plugins. Endpoints can be added at the top of the Payload config, `collections`, and `globals` and accessed respective of the api and slugs you have configured.
|
||||
Additional REST API endpoints can be added to your application by providing an array of `endpoints` in various places within a Payload Config. Custom endpoints are useful for adding additional middleware on existing routes or for building custom functionality into Payload apps and plugins. Endpoints can be added at the top of the Payload Config, `collections`, and `globals` and accessed respective of the api and slugs you have configured.
|
||||
|
||||
Each endpoint object needs to have:
|
||||
|
||||
@@ -579,13 +580,13 @@ Each endpoint object needs to have:
|
||||
| **`path`** | A string for the endpoint route after the collection or globals slug |
|
||||
| **`method`** | The lowercase HTTP verb to use: 'get', 'head', 'post', 'put', 'delete', 'connect' or 'options' |
|
||||
| **`handler`** | A function or array of functions to be called with **req**, **res** and **next** arguments. [Next.js](https://nextjs.org/docs/app/building-your-application/routing/route-handlers) |
|
||||
| **`root`** | When `true`, defines the endpoint on the root Next.js app, bypassing Payload handlers and the `routes.api` subpath. Note: this only applies to top-level endpoints of your Payload config, endpoints defined on `collections` or `globals` cannot be root. |
|
||||
| **`root`** | When `true`, defines the endpoint on the root Next.js app, bypassing Payload handlers and the `routes.api` subpath. Note: this only applies to top-level endpoints of your Payload Config, endpoints defined on `collections` or `globals` cannot be root. |
|
||||
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
|
||||
|
||||
Example:
|
||||
|
||||
```ts
|
||||
import { CollectionConfig } from 'payload/types'
|
||||
import { CollectionConfig } from 'payload'
|
||||
|
||||
// a collection of 'orders' with an additional route for tracking details, reachable at /api/orders/:id/tracking
|
||||
export const Orders: CollectionConfig = {
|
||||
|
||||
@@ -16,10 +16,10 @@ To use the Slate editor, first you need to install it:
|
||||
npm install --save @payloadcms/richtext-slate
|
||||
```
|
||||
|
||||
After installation, you can pass it to your top-level Payload config:
|
||||
After installation, you can pass it to your top-level Payload Config:
|
||||
|
||||
```ts
|
||||
import { buildConfig } from 'payload/config'
|
||||
import { buildConfig } from 'payload'
|
||||
import { slateEditor } from '@payloadcms/richtext-slate'
|
||||
|
||||
export default buildConfig({
|
||||
@@ -34,7 +34,7 @@ export default buildConfig({
|
||||
And here's an example for how to install the Slate editor on a field-by-field basis, while customizing its options:
|
||||
|
||||
```ts
|
||||
import { CollectionConfig } from 'payload/types'
|
||||
import { CollectionConfig } from 'payload'
|
||||
import { slateEditor } from '@payloadcms/richtext-slate'
|
||||
|
||||
export const Pages: CollectionConfig = {
|
||||
@@ -63,7 +63,7 @@ export const Pages: CollectionConfig = {
|
||||
|
||||
**`elements`**
|
||||
|
||||
The `elements` property is used to specify which built-in or custom [SlateJS elements](https://docs.slatejs.org/concepts/02-nodes#element) should be made available to the field within the admin panel.
|
||||
The `elements` property is used to specify which built-in or custom [SlateJS elements](https://docs.slatejs.org/concepts/02-nodes#element) should be made available to the field within the Admin Panel.
|
||||
|
||||
The default `elements` available in Payload are:
|
||||
|
||||
@@ -167,7 +167,7 @@ Specifying custom `Type`s let you extend your custom elements by adding addition
|
||||
`collections/ExampleCollection.ts`
|
||||
|
||||
```ts
|
||||
import type { CollectionConfig } from 'payload/types'
|
||||
import type { CollectionConfig } from 'payload'
|
||||
|
||||
import { slateEditor } from '@payloadcms/richtext-slate'
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ keywords: admin, components, custom, customize, documentation, Content Managemen
|
||||
|
||||
### "Unauthorized, you must be logged in to make this request" when attempting to log in
|
||||
|
||||
This means that your auth cookie is not being set or accepted correctly upon logging in. To resolve heck the following settings in your Payload config:
|
||||
This means that your auth cookie is not being set or accepted correctly upon logging in. To resolve heck the following settings in your Payload Config:
|
||||
|
||||
- CORS - If you are using the '\*', try to explicitly only allow certain domains instead including the one you have specified.
|
||||
- CSRF - Do you have this set? if so, make sure your domain is whitelisted within the csrf domains. If not, probably not the issue, but probably can't hurt to whitelist it anyway.
|
||||
|
||||
@@ -6,11 +6,11 @@ desc: Generate your own TypeScript interfaces based on your collections and glob
|
||||
keywords: headless cms, typescript, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
|
||||
---
|
||||
|
||||
While building your own custom functionality into Payload, like plugins, hooks, access control functions, custom views, GraphQL queries / mutations, or anything else, you may benefit from generating your own TypeScript types dynamically from your Payload config itself.
|
||||
While building your own custom functionality into Payload, like plugins, hooks, access control functions, custom views, GraphQL queries / mutations, or anything else, you may benefit from generating your own TypeScript types dynamically from your Payload Config itself.
|
||||
|
||||
## Types generation script
|
||||
|
||||
Run the following command in a Payload project to generate types based on your Payload config:
|
||||
Run the following command in a Payload project to generate types based on your Payload Config:
|
||||
|
||||
```
|
||||
payload generate:types
|
||||
@@ -46,7 +46,7 @@ declare module 'payload' {
|
||||
|
||||
## Custom output file path
|
||||
|
||||
You can specify where you want your types to be generated by adding a property to your Payload config:
|
||||
You can specify where you want your types to be generated by adding a property to your Payload Config:
|
||||
|
||||
```ts
|
||||
// payload.config.ts
|
||||
@@ -59,7 +59,7 @@ You can specify where you want your types to be generated by adding a property t
|
||||
}
|
||||
```
|
||||
|
||||
The above example places your types next to your Payload config itself as the file `generated-types.ts`.
|
||||
The above example places your types next to your Payload Config itself as the file `generated-types.ts`.
|
||||
|
||||
## Custom generated types
|
||||
|
||||
@@ -100,7 +100,7 @@ This function takes the existing JSON schema as an argument and returns the modi
|
||||
|
||||
## Example Usage
|
||||
|
||||
For example, let's look at the following simple Payload config:
|
||||
For example, let's look at the following simple Payload Config:
|
||||
|
||||
```ts
|
||||
import type { Config } from 'payload'
|
||||
@@ -211,7 +211,7 @@ export interface Collection1 {
|
||||
|
||||
## Using your types
|
||||
|
||||
Now that your types have been generated, payloads local API will now be typed. It is common for users to want to use this in their frontend code, we recommend generating them with payload and then copying the file over to your frontend codebase. This is the simplest way to get your types into your frontend codebase.
|
||||
Now that your types have been generated, payloads local API will now be typed. It is common for users to want to use this in their frontend code, we recommend generating them with Payload and then copying the file over to your frontend codebase. This is the simplest way to get your types into your frontend codebase.
|
||||
|
||||
### Adding an NPM script
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ keywords: uploads, images, media, overview, documentation, Content Management Sy
|
||||
<LightDarkImage
|
||||
srcLight="https://payloadcms.com/images/docs/upload-admin.jpg"
|
||||
srcDark="https://payloadcms.com/images/docs/upload-admin.jpg"
|
||||
alt="Shows an Upload enabled collection in the Payload admin panel"
|
||||
alt="Shows an Upload enabled collection in the Payload Admin Panel"
|
||||
caption="Admin Panel screenshot depicting a Media Collection with Upload enabled"
|
||||
/>
|
||||
|
||||
@@ -43,7 +43,7 @@ Every Payload Collection can opt-in to supporting Uploads by specifying the `upl
|
||||
</Banner>
|
||||
|
||||
```ts
|
||||
import { CollectionConfig } from 'payload/types'
|
||||
import { CollectionConfig } from 'payload'
|
||||
|
||||
export const Media: CollectionConfig = {
|
||||
slug: 'media',
|
||||
@@ -89,31 +89,31 @@ export const Media: CollectionConfig = {
|
||||
|
||||
_An asterisk denotes that an option is required._
|
||||
|
||||
| Option | Description |
|
||||
| ------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| Option | Description |
|
||||
| ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **`adminThumbnail`** | Set the way that the [Admin Panel](../admin/overview) will display thumbnails for this Collection. [More](#admin-thumbnails) |
|
||||
| **`crop`** | Set to `false` to disable the cropping tool in the [Admin Panel](../admin/overview). Crop is enabled by default. [More](#crop-and-focal-point-selector) |
|
||||
| **`disableLocalStorage`** | Completely disable uploading files to disk locally. [More](#disabling-local-upload-storage) |
|
||||
| **`externalFileHeaderFilter`** | Accepts existing headers and returns the headers after filtering or modifying. |
|
||||
| **`filesRequiredOnCreate`** | Mandate file data on creation, default is true. |
|
||||
| **`disableLocalStorage`** | Completely disable uploading files to disk locally. [More](#disabling-local-upload-storage) |
|
||||
| **`externalFileHeaderFilter`** | Accepts existing headers and returns the headers after filtering or modifying. |
|
||||
| **`filesRequiredOnCreate`** | Mandate file data on creation, default is true. |
|
||||
| **`focalPoint`** | Set to `false` to disable the focal point selection tool in the [Admin Panel](../admin/overview). The focal point selector is only available when `imageSizes` or `resizeOptions` are defined. [More](#crop-and-focal-point-selector) |
|
||||
| **`formatOptions`** | An object with `format` and `options` that are used with the Sharp image library to format the upload file. [More](https://sharp.pixelplumbing.com/api-output#toformat) |
|
||||
| **`handlers`** | Array of Request handlers to execute when fetching a file, if a handler returns a Response it will be sent to the client. Otherwise Payload will retrieve and send back the file. |
|
||||
| **`imageSizes`** | If specified, image uploads will be automatically resized in accordance to these image sizes. [More](#image-sizes) |
|
||||
| **`mimeTypes`** | Restrict mimeTypes in the file picker. Array of valid mimetypes or mimetype wildcards [More](#mimetypes) |
|
||||
| **`resizeOptions`** | An object passed to the the Sharp image library to resize the uploaded file. [More](https://sharp.pixelplumbing.com/api-resize) |
|
||||
| **`staticDir`** | The folder directory to use to store media in. Can be either an absolute path or relative to the directory that contains your config. Defaults to your collection slug |
|
||||
| **`trimOptions`** | An object passed to the the Sharp image library to trim the uploaded file. [More](https://sharp.pixelplumbing.com/api-resize#trim) |
|
||||
| **`formatOptions`** | An object with `format` and `options` that are used with the Sharp image library to format the upload file. [More](https://sharp.pixelplumbing.com/api-output#toformat) |
|
||||
| **`handlers`** | Array of Request handlers to execute when fetching a file, if a handler returns a Response it will be sent to the client. Otherwise Payload will retrieve and send back the file. |
|
||||
| **`imageSizes`** | If specified, image uploads will be automatically resized in accordance to these image sizes. [More](#image-sizes) |
|
||||
| **`mimeTypes`** | Restrict mimeTypes in the file picker. Array of valid mimetypes or mimetype wildcards [More](#mimetypes) |
|
||||
| **`resizeOptions`** | An object passed to the the Sharp image library to resize the uploaded file. [More](https://sharp.pixelplumbing.com/api-resize) |
|
||||
| **`staticDir`** | The folder directory to use to store media in. Can be either an absolute path or relative to the directory that contains your config. Defaults to your collection slug |
|
||||
| **`trimOptions`** | An object passed to the the Sharp image library to trim the uploaded file. [More](https://sharp.pixelplumbing.com/api-resize#trim) |
|
||||
|
||||
|
||||
### Payload-wide Upload Options
|
||||
|
||||
Upload options are specifiable on a Collection by Collection basis, you can also control app wide options by passing your base Payload config an `upload` property containing an object supportive of all `Busboy` configuration options. [Click here](https://github.com/mscdex/busboy#api) for more documentation about what you can control.
|
||||
Upload options are specifiable on a Collection by Collection basis, you can also control app wide options by passing your base Payload Config an `upload` property containing an object supportive of all `Busboy` configuration options. [Click here](https://github.com/mscdex/busboy#api) for more documentation about what you can control.
|
||||
|
||||
A common example of what you might want to customize within Payload-wide Upload options would be to increase the allowed `fileSize` of uploads sent to Payload:
|
||||
|
||||
```ts
|
||||
import { buildConfig } from 'payload/config'
|
||||
import { buildConfig } from 'payload'
|
||||
|
||||
export default buildConfig({
|
||||
collections: [
|
||||
@@ -197,7 +197,7 @@ You can specify how Payload retrieves admin thumbnails for your upload-enabled C
|
||||
1. `adminThumbnail` as a **string**, equal to one of your provided image size names.
|
||||
|
||||
```ts
|
||||
import { CollectionConfig } from 'payload/types'
|
||||
import { CollectionConfig } from 'payload'
|
||||
|
||||
export const Media: CollectionConfig = {
|
||||
slug: 'media',
|
||||
@@ -226,7 +226,7 @@ export const Media: CollectionConfig = {
|
||||
2. `adminThumbnail` as a **function** that takes the document's data and sends back a full URL to load the thumbnail.
|
||||
|
||||
```ts
|
||||
import { CollectionConfig } from 'payload/types'
|
||||
import { CollectionConfig } from 'payload'
|
||||
|
||||
export const Media: CollectionConfig = {
|
||||
slug: 'media',
|
||||
@@ -247,7 +247,7 @@ Some example values are: `image/*`, `audio/*`, `video/*`, `image/png`, `applicat
|
||||
**Example mimeTypes usage:**
|
||||
|
||||
```ts
|
||||
import { CollectionConfig } from 'payload/types'
|
||||
import { CollectionConfig } from 'payload'
|
||||
|
||||
export const Media: CollectionConfig = {
|
||||
slug: 'media',
|
||||
|
||||
@@ -286,7 +286,7 @@ export interface GeneratedAdapter {
|
||||
```
|
||||
|
||||
```ts
|
||||
import { buildConfig } from 'payload/config'
|
||||
import { buildConfig } from 'payload'
|
||||
import { cloudStoragePlugin } from '@payloadcms/plugin-cloud-storage'
|
||||
|
||||
export default buildConfig({
|
||||
|
||||
@@ -37,7 +37,12 @@ export const rootParserOptions = {
|
||||
export const rootEslintConfig = [
|
||||
...payloadEsLintConfig,
|
||||
{
|
||||
ignores: [...defaultESLintIgnores, 'test/live-preview/next-app', 'packages/**/*.spec.ts'],
|
||||
ignores: [
|
||||
...defaultESLintIgnores,
|
||||
'test/live-preview/next-app',
|
||||
'packages/**/*.spec.ts',
|
||||
'templates/**',
|
||||
],
|
||||
},
|
||||
{
|
||||
languageOptions: {
|
||||
|
||||
3
examples/multi-tenant-single-domain/.env.example
Normal file
3
examples/multi-tenant-single-domain/.env.example
Normal file
@@ -0,0 +1,3 @@
|
||||
DATABASE_URI=mongodb://127.0.0.1/payload-example-multi-tenant-single-domain
|
||||
PAYLOAD_SECRET=PAYLOAD_MULTI_TENANT_EXAMPLE_SECRET_KEY
|
||||
PAYLOAD_PUBLIC_SERVER_URL=http://localhost:3000
|
||||
4
examples/multi-tenant-single-domain/.eslintrc.cjs
Normal file
4
examples/multi-tenant-single-domain/.eslintrc.cjs
Normal file
@@ -0,0 +1,4 @@
|
||||
module.exports = {
|
||||
root: true,
|
||||
extends: ['@payloadcms'],
|
||||
}
|
||||
5
examples/multi-tenant-single-domain/.gitignore
vendored
Normal file
5
examples/multi-tenant-single-domain/.gitignore
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
build
|
||||
dist
|
||||
node_modules
|
||||
package-lock.json
|
||||
.env
|
||||
24
examples/multi-tenant-single-domain/.swcrc
Normal file
24
examples/multi-tenant-single-domain/.swcrc
Normal file
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/swcrc",
|
||||
"sourceMaps": true,
|
||||
"jsc": {
|
||||
"target": "esnext",
|
||||
"parser": {
|
||||
"syntax": "typescript",
|
||||
"tsx": true,
|
||||
"dts": true
|
||||
},
|
||||
"transform": {
|
||||
"react": {
|
||||
"runtime": "automatic",
|
||||
"pragmaFrag": "React.Fragment",
|
||||
"throwIfNamespace": true,
|
||||
"development": false,
|
||||
"useBuiltins": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"module": {
|
||||
"type": "es6"
|
||||
}
|
||||
}
|
||||
75
examples/multi-tenant-single-domain/README.md
Normal file
75
examples/multi-tenant-single-domain/README.md
Normal file
@@ -0,0 +1,75 @@
|
||||
# Payload Multi-Tenant Example
|
||||
|
||||
This example demonstrates how to achieve a multi-tenancy in [Payload](https://github.com/payloadcms/payload) on a single domain. Tenants are separated by a `Tenants` collection.
|
||||
|
||||
## Quick Start
|
||||
|
||||
To spin up this example locally, follow these steps:
|
||||
|
||||
1. First clone the repo
|
||||
2. `cd YOUR_PROJECT_REPO && cp .env.example .env`
|
||||
3. `pnpm i && pnpm dev`
|
||||
4. run `yarn seed` to seed the database
|
||||
5. open `http://localhost:3000/admin` to access the admin panel
|
||||
6. Login with email `demo@payloadcms.com` and password `demo`
|
||||
|
||||
## How it works
|
||||
|
||||
A multi-tenant Payload application is a single server that hosts multiple "tenants". Examples of tenants may be your agency's clients, your business conglomerate's organizations, or your SaaS customers.
|
||||
|
||||
Each tenant has its own set of users, pages, and other data that is scoped to that tenant. This means that your application will be shared across tenants but the data will be scoped to each tenant.
|
||||
|
||||
### Collections
|
||||
|
||||
See the [Collections](https://payloadcms.com/docs/configuration/collections) docs for details on how to extend any of this functionality.
|
||||
|
||||
- #### Users
|
||||
|
||||
The `users` collection is auth-enabled and encompass both app-wide and tenant-scoped users based on the value of their `roles` and `tenants` fields. Users with the role `super-admin` can manage your entire application, while users with the _tenant role_ of `admin` have limited access to the platform and can manage only the tenant(s) they are assigned to, see [Tenants](#tenants) for more details.
|
||||
|
||||
For additional help with authentication, see the official [Auth Example](https://github.com/payloadcms/payload/tree/main/examples/auth/cms#readme) or the [Authentication](https://payloadcms.com/docs/authentication/overview#authentication-overview) docs.
|
||||
|
||||
- #### Tenants
|
||||
|
||||
A `tenants` collection is used to achieve tenant-based access control. Each user is assigned an array of `tenants` which includes a relationship to a `tenant` and their `roles` within that tenant. You can then scope any document within your application to any of your tenants using a simple [relationship](https://payloadcms.com/docs/fields/relationship) field on the `users` or `pages` collections, or any other collection that your application needs. The value of this field is used to filter documents in the admin panel and API to ensure that users can only access documents that belong to their tenant and are within their role. See [Access Control](#access-control) for more details.
|
||||
|
||||
For more details on how to extend this functionality, see the [Payload Access Control](https://payloadcms.com/docs/access-control/overview) docs.
|
||||
|
||||
- #### Pages
|
||||
|
||||
Each page is assigned a `tenant` which is used to control access and scope API requests. Pages that are created by tenants are automatically assigned that tenant based on that user's `lastLoggedInTenant` field.
|
||||
|
||||
## Access control
|
||||
|
||||
Basic role-based access control is setup to determine what users can and cannot do based on their roles, which are:
|
||||
|
||||
- `super-admin`: They can access the Payload admin panel to manage your multi-tenant application. They can see all tenants and make all operations.
|
||||
- `user`: They can only access the Payload admin panel if they are a tenant-admin, in which case they have a limited access to operations based on their tenant (see below).
|
||||
|
||||
This applies to each collection in the following ways:
|
||||
|
||||
- `users`: Only super-admins, tenant-admins, and the user themselves can access their profile. Anyone can create a user, but only these admins can delete users. See [Users](#users) for more details.
|
||||
- `tenants`: Only super-admins and tenant-admins can read, create, update, or delete tenants. See [Tenants](#tenants) for more details.
|
||||
- `pages`: Everyone can access pages, but only super-admins and tenant-admins can create, update, or delete them.
|
||||
|
||||
When a user logs in, a `lastLoggedInTenant` field is saved to their profile. This is done by reading the value of `req.headers.host`, querying for a tenant with a matching `domain`, and verifying that the user is a member of that tenant. This field is then used to automatically assign the tenant to any documents that the user creates, such as pages. Super-admins can also use this field to browse the admin panel as a specific tenant.
|
||||
|
||||
> If you have versions and drafts enabled on your pages, you will need to add additional read access control condition to check the user's tenants that prevents them from accessing draft documents of other tenants.
|
||||
|
||||
For more details on how to extend this functionality, see the [Payload Access Control](https://payloadcms.com/docs/access-control/overview#access-control) docs.
|
||||
|
||||
## CORS
|
||||
|
||||
This multi-tenant setup requires an open CORS policy. Since each tenant contains a dynamic list of domains, there's no way to know specifically which domains to whitelist at runtime without significant performance implications. This also means that the `serverURL` is not set, as this scopes all requests to a single domain.
|
||||
|
||||
Alternatively, if you know the domains of your tenants ahead of time and these values won't change often, you could simply remove the `domains` field altogether and instead use static values.
|
||||
|
||||
For more details on this, see the [CORS](https://payloadcms.com/docs/production/preventing-abuse#cross-origin-resource-sharing-cors) docs.
|
||||
|
||||
## Front-end
|
||||
|
||||
The frontend is scaffolded out in this example directory. You can view the code for rendering pages at `/src/app/(app)/[tenant]/[...slug]/page.tsx`. This is a starter template, you may need to adjust the app to better fit your needs.
|
||||
|
||||
## Questions
|
||||
|
||||
If you have any issues or questions, reach out to us on [Discord](https://discord.com/invite/payload) or start a [GitHub discussion](https://github.com/payloadcms/payload/discussions).
|
||||
5
examples/multi-tenant-single-domain/next-env.d.ts
vendored
Normal file
5
examples/multi-tenant-single-domain/next-env.d.ts
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
/// <reference types="next" />
|
||||
/// <reference types="next/image-types/global" />
|
||||
|
||||
// NOTE: This file should not be edited
|
||||
// see https://nextjs.org/docs/basic-features/typescript for more information.
|
||||
55
examples/multi-tenant-single-domain/package.json
Normal file
55
examples/multi-tenant-single-domain/package.json
Normal file
@@ -0,0 +1,55 @@
|
||||
{
|
||||
"name": "multi-tenant-single-domain",
|
||||
"description": "An example of a multi tenant application, using a single domain",
|
||||
"version": "1.0.0",
|
||||
"license": "MIT",
|
||||
"type": "module",
|
||||
"engines": {
|
||||
"node": "^18.20.2 || >=20.9.0"
|
||||
},
|
||||
"scripts": {
|
||||
"dev": "cross-env NODE_OPTIONS=--no-deprecation next dev --turbo",
|
||||
"_dev": "cross-env NODE_OPTIONS=--no-deprecation next dev",
|
||||
"build": "cross-env NODE_OPTIONS=--no-deprecation next build",
|
||||
"payload": "cross-env NODE_OPTIONS=--no-deprecation payload",
|
||||
"start": "cross-env NODE_OPTIONS=--no-deprecation next start",
|
||||
"generate:types": "payload generate:types",
|
||||
"generate:schema": "payload-graphql generate:schema",
|
||||
"seed": "tsx ./scripts/seed.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@payloadcms/db-mongodb": "3.0.0-beta.58",
|
||||
"@payloadcms/next": "3.0.0-beta.58",
|
||||
"@payloadcms/richtext-lexical": "3.0.0-beta.58",
|
||||
"@payloadcms/ui": "3.0.0-beta.58",
|
||||
"cross-env": "^7.0.3",
|
||||
"dotenv": "^8.2.0",
|
||||
"graphql": "^16.9.0",
|
||||
"next": "15.0.0-rc.0",
|
||||
"payload": "3.0.0-beta.58",
|
||||
"qs": "^6.12.1",
|
||||
"react": "19.0.0-rc-f994737d14-20240522",
|
||||
"react-dom": "19.0.0-rc-f994737d14-20240522",
|
||||
"sharp": "0.32.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@payloadcms/graphql": "3.0.0-beta.58",
|
||||
"@swc/core": "^1.6.13",
|
||||
"@types/react": "npm:types-react@19.0.0-beta.2",
|
||||
"@types/react-dom": "npm:types-react-dom@19.0.0-beta.2",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-config-next": "15.0.0-rc.0",
|
||||
"tsx": "^4.16.2",
|
||||
"typescript": "5.5.2"
|
||||
},
|
||||
"pnpm": {
|
||||
"overrides": {
|
||||
"@types/react": "npm:types-react@19.0.0-beta.2",
|
||||
"@types/react-dom": "npm:types-react-dom@19.0.0-beta.2"
|
||||
}
|
||||
},
|
||||
"overrides": {
|
||||
"@types/react": "npm:types-react@19.0.0-beta.2",
|
||||
"@types/react-dom": "npm:types-react-dom@19.0.0-beta.2"
|
||||
}
|
||||
}
|
||||
182
examples/multi-tenant-single-domain/scripts/seed.ts
Normal file
182
examples/multi-tenant-single-domain/scripts/seed.ts
Normal file
@@ -0,0 +1,182 @@
|
||||
/**
|
||||
* This is an example of a standalone script that loads in the Payload config
|
||||
* and uses the Payload Local API to query the database.
|
||||
*/
|
||||
|
||||
import type { Payload } from 'payload';
|
||||
|
||||
import { getPayload } from 'payload'
|
||||
import { importConfig } from 'payload/node'
|
||||
|
||||
async function findOrCreateTenant({ data, payload }: { data: any; payload: Payload }) {
|
||||
const tenantsQuery = await payload.find({
|
||||
collection: 'tenants',
|
||||
where: {
|
||||
slug: {
|
||||
equals: data.slug,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
if (tenantsQuery.docs?.[0]) return tenantsQuery.docs[0]
|
||||
|
||||
return payload.create({
|
||||
collection: 'tenants',
|
||||
data,
|
||||
})
|
||||
}
|
||||
|
||||
async function findOrCreateUser({ data, payload }: { data: any; payload: Payload }) {
|
||||
const usersQuery = await payload.find({
|
||||
collection: 'users',
|
||||
where: {
|
||||
email: {
|
||||
equals: data.email,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
if (usersQuery.docs?.[0]) return usersQuery.docs[0]
|
||||
|
||||
return payload.create({
|
||||
collection: 'users',
|
||||
data,
|
||||
})
|
||||
}
|
||||
|
||||
async function findOrCreatePage({ data, payload }: { data: any; payload: Payload }) {
|
||||
const pagesQuery = await payload.find({
|
||||
collection: 'pages',
|
||||
where: {
|
||||
slug: {
|
||||
equals: data.slug,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
if (pagesQuery.docs?.[0]) return pagesQuery.docs[0]
|
||||
|
||||
return payload.create({
|
||||
collection: 'pages',
|
||||
data,
|
||||
})
|
||||
}
|
||||
|
||||
async function run() {
|
||||
const awaitedConfig = await importConfig('../src/payload.config.ts')
|
||||
const payload = await getPayload({ config: awaitedConfig })
|
||||
|
||||
const tenant1 = await findOrCreateTenant({
|
||||
data: {
|
||||
name: 'Tenant 1',
|
||||
slug: 'tenant-1',
|
||||
},
|
||||
payload,
|
||||
})
|
||||
|
||||
const tenant2 = await findOrCreateTenant({
|
||||
data: {
|
||||
name: 'Tenant 2',
|
||||
slug: 'tenant-2',
|
||||
public: true,
|
||||
},
|
||||
payload,
|
||||
})
|
||||
|
||||
const tenant3 = await findOrCreateTenant({
|
||||
data: {
|
||||
name: 'Tenant 3',
|
||||
slug: 'tenant-3',
|
||||
},
|
||||
payload,
|
||||
})
|
||||
|
||||
await findOrCreateUser({
|
||||
data: {
|
||||
email: 'demo@payloadcms.com',
|
||||
password: 'demo',
|
||||
roles: ['super-admin'],
|
||||
},
|
||||
payload,
|
||||
})
|
||||
|
||||
await findOrCreateUser({
|
||||
data: {
|
||||
email: 'tenant1@payloadcms.com',
|
||||
password: 'test',
|
||||
tenants: [
|
||||
{
|
||||
roles: ['super-admin'],
|
||||
tenant: tenant1.id,
|
||||
},
|
||||
],
|
||||
username: 'tenant1',
|
||||
},
|
||||
payload,
|
||||
})
|
||||
|
||||
await findOrCreateUser({
|
||||
data: {
|
||||
email: 'tenant2@payloadcms.com',
|
||||
password: 'test',
|
||||
tenants: [
|
||||
{
|
||||
roles: ['super-admin'],
|
||||
tenant: tenant2.id,
|
||||
},
|
||||
],
|
||||
username: 'tenant2',
|
||||
},
|
||||
payload,
|
||||
})
|
||||
|
||||
await findOrCreateUser({
|
||||
data: {
|
||||
email: 'multi-admin@payloadcms.com',
|
||||
password: 'test',
|
||||
tenants: [
|
||||
{
|
||||
roles: ['super-admin'],
|
||||
tenant: tenant1.id,
|
||||
},
|
||||
{
|
||||
roles: ['super-admin'],
|
||||
tenant: tenant2.id,
|
||||
},
|
||||
],
|
||||
username: 'tenant3',
|
||||
},
|
||||
payload,
|
||||
})
|
||||
|
||||
await findOrCreatePage({
|
||||
data: {
|
||||
slug: 'home',
|
||||
tenant: tenant1.id,
|
||||
title: 'Page for Tenant 1',
|
||||
},
|
||||
payload,
|
||||
})
|
||||
|
||||
await findOrCreatePage({
|
||||
data: {
|
||||
slug: 'home',
|
||||
tenant: tenant2.id,
|
||||
title: 'Page for Tenant 2',
|
||||
},
|
||||
payload,
|
||||
})
|
||||
|
||||
await findOrCreatePage({
|
||||
data: {
|
||||
slug: 'home',
|
||||
tenant: tenant3.id,
|
||||
title: 'Page for Tenant 3',
|
||||
},
|
||||
payload,
|
||||
})
|
||||
|
||||
process.exit(0)
|
||||
}
|
||||
|
||||
run().catch(console.error)
|
||||
@@ -0,0 +1,88 @@
|
||||
import type { Where } from 'payload'
|
||||
|
||||
import configPromise from '@payload-config'
|
||||
import { getPayloadHMR } from '@payloadcms/next/utilities'
|
||||
import { headers as getHeaders } from 'next/headers.js'
|
||||
import { notFound, redirect } from 'next/navigation'
|
||||
import React from 'react'
|
||||
|
||||
import { RenderPage } from '../../../components/RenderPage'
|
||||
|
||||
export default async function Page({ params }: { params: { slug?: string[]; tenant: string } }) {
|
||||
const headers = getHeaders()
|
||||
const payload = await getPayloadHMR({ config: configPromise })
|
||||
const { user } = await payload.auth({ headers })
|
||||
|
||||
const tenantsQuery = await payload.find({
|
||||
collection: 'tenants',
|
||||
overrideAccess: false,
|
||||
user,
|
||||
where: {
|
||||
slug: {
|
||||
equals: params.tenant,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
const slug = params?.slug
|
||||
|
||||
// If no tenant is found, the user does not have access
|
||||
// Show the login view
|
||||
if (tenantsQuery.docs.length === 0) {
|
||||
redirect(
|
||||
`/${params.tenant}/login?redirect=${encodeURIComponent(
|
||||
`/${params.tenant}${slug ? `/${slug.join('/')}` : ''}`,
|
||||
)}`,
|
||||
)
|
||||
}
|
||||
|
||||
const slugConstraint: Where = slug
|
||||
? {
|
||||
slug: {
|
||||
equals: slug.join('/'),
|
||||
},
|
||||
}
|
||||
: {
|
||||
or: [
|
||||
{
|
||||
slug: {
|
||||
equals: '',
|
||||
},
|
||||
},
|
||||
{
|
||||
slug: {
|
||||
equals: 'home',
|
||||
},
|
||||
},
|
||||
{
|
||||
slug: {
|
||||
exists: false,
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
const pageQuery = await payload.find({
|
||||
collection: 'pages',
|
||||
overrideAccess: false,
|
||||
user,
|
||||
where: {
|
||||
and: [
|
||||
{
|
||||
'tenant.slug': {
|
||||
equals: params.tenant,
|
||||
},
|
||||
},
|
||||
slugConstraint,
|
||||
],
|
||||
},
|
||||
})
|
||||
|
||||
const pageData = pageQuery.docs?.[0]
|
||||
|
||||
// The page with the provided slug could not be found
|
||||
if (!pageData) return notFound()
|
||||
|
||||
// The page was found, render the page with data
|
||||
return <RenderPage data={pageData} />
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import React from 'react'
|
||||
|
||||
import { Login } from '../../../components/Login/client.page'
|
||||
|
||||
type RouteParams = {
|
||||
tenant: string
|
||||
}
|
||||
|
||||
export default function Page({ params }: { params: RouteParams }) {
|
||||
return <Login tenantSlug={params.tenant} />
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
import React from 'react'
|
||||
|
||||
import Page from './[...slug]/page'
|
||||
|
||||
export default Page
|
||||
@@ -0,0 +1,6 @@
|
||||
.multi-tenant {
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 10px
|
||||
}
|
||||
}
|
||||
18
examples/multi-tenant-single-domain/src/app/(app)/layout.tsx
Normal file
18
examples/multi-tenant-single-domain/src/app/(app)/layout.tsx
Normal file
@@ -0,0 +1,18 @@
|
||||
import React from 'react'
|
||||
|
||||
import './index.scss'
|
||||
|
||||
const baseClass = 'multi-tenant'
|
||||
|
||||
export const metadata = {
|
||||
description: 'Generated by Next.js',
|
||||
title: 'Next.js',
|
||||
}
|
||||
|
||||
export default function RootLayout({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<html className={baseClass} lang="en">
|
||||
<body>{children}</body>
|
||||
</html>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
|
||||
import type { Metadata } from 'next'
|
||||
|
||||
import config from '@payload-config'
|
||||
/* DO NOT MODIFY IT BECAUSE IT COULD BE REWRITTEN AT ANY TIME. */
|
||||
import { NotFoundPage, generatePageMetadata } from '@payloadcms/next/views'
|
||||
|
||||
type Args = {
|
||||
params: {
|
||||
segments: string[]
|
||||
}
|
||||
searchParams: {
|
||||
[key: string]: string | string[]
|
||||
}
|
||||
}
|
||||
|
||||
export const generateMetadata = ({ params, searchParams }: Args): Promise<Metadata> =>
|
||||
generatePageMetadata({ config, params, searchParams })
|
||||
|
||||
const NotFound = ({ params, searchParams }: Args) => NotFoundPage({ config, params, searchParams })
|
||||
|
||||
export default NotFound
|
||||
@@ -0,0 +1,22 @@
|
||||
/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
|
||||
import type { Metadata } from 'next'
|
||||
|
||||
import config from '@payload-config'
|
||||
/* DO NOT MODIFY IT BECAUSE IT COULD BE REWRITTEN AT ANY TIME. */
|
||||
import { RootPage, generatePageMetadata } from '@payloadcms/next/views'
|
||||
|
||||
type Args = {
|
||||
params: {
|
||||
segments: string[]
|
||||
}
|
||||
searchParams: {
|
||||
[key: string]: string | string[]
|
||||
}
|
||||
}
|
||||
|
||||
export const generateMetadata = ({ params, searchParams }: Args): Promise<Metadata> =>
|
||||
generatePageMetadata({ config, params, searchParams })
|
||||
|
||||
const Page = ({ params, searchParams }: Args) => RootPage({ config, params, searchParams })
|
||||
|
||||
export default Page
|
||||
@@ -0,0 +1,10 @@
|
||||
/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
|
||||
/* DO NOT MODIFY it because it could be re-written at any time. */
|
||||
import config from '@payload-config'
|
||||
import { REST_DELETE, REST_GET, REST_OPTIONS, REST_PATCH, REST_POST } from '@payloadcms/next/routes'
|
||||
|
||||
export const GET = REST_GET(config)
|
||||
export const POST = REST_POST(config)
|
||||
export const DELETE = REST_DELETE(config)
|
||||
export const PATCH = REST_PATCH(config)
|
||||
export const OPTIONS = REST_OPTIONS(config)
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user