Compare commits

..

50 Commits

Author SHA1 Message Date
Elliot DeNolf
a8d88b8238 chore(release): v3.0.0-beta.68 [skip ci] 2024-07-22 16:05:04 -04:00
Jarrod Flesch
5aa3283dc0 fix: search plugin localized fields (#7292) 2024-07-22 15:47:39 -04:00
Alessio Gravili
45844789f2 feat: upgrade pino and pino-pretty, clean up hacky esm imports (#7291)
Doesn't look like those hacky esm-cjs imports are needed anymore.

These major pino releases only drop Node.js version support for versions
which payload doesn't support anyways.
2024-07-22 15:11:34 -04:00
Alessio Gravili
79975f48cf chore: ensure the correct next & react versions are installed in templates and core (#7283)
Some package.json's were on older or mismatching Next.js / React
versions. This includes other Next.js packages like @next/env
2024-07-22 18:33:54 +00:00
Paul
bba7cf37f8 fix(templates): website template building error with postgres number IDs (#7281) 2024-07-22 17:40:58 +00:00
Paul
1ae71a3d24 fix(ui): not updating permissions when locale changes (#7245)
Closes https://github.com/payloadcms/payload/issues/7163
2024-07-22 17:31:20 +00:00
Alessio Gravili
e83eb99436 feat: remove joi schema validation (#7226)
We do not really need runtime joi schema validation - this is what TypeScript is for. If people are ignoring TypeScript errors in your schema, or JavaScript errors, that is their fault and does not warrant an extra dependency (joi), lots of code to maintain, as well as slower startups.

If we wanna keep runtime schema validation, we should switch to zod so that we can generate TypeScript types based on the schema and do not have to manually maintain config properties in 2 different places (types & schema).

**joi PROs:**
- Safety for JavaScript-only evangelists messing up their schema
- Safety for people putting @ts-expect-error or `as any` everywhere in their code

**joi CONs:**
- Larger bundle size
- More Modules
- Slower Compilation Speed in dev. Worse DX
- Slower Startup (it needs to validate) in dev. Worse DX
- More code to maintain. For every schema change we'll have to change the types AND the joi schema
- TypeScript already throws proper errors if you mess up your schema. Why have runtime errors?
- The errors are bad. They might tell you what field has an issue, but they do not tell you what exactly is wrong. You have probably seen those "Field XY, value is incorrect" errors - and value could mean anything. Worse DX
- Having extra properties in your schema, even if they are useless, doesn't cause any harm

Cons outweigh the pros
2024-07-22 13:22:54 -04:00
Dan Ribbens
f50e599684 chore: add index to status for versions (#6257) 2024-07-22 13:13:09 -04:00
Dan Ribbens
7dab75d85e chore: make ui bundle script windows compatible (#7197) 2024-07-22 13:10:07 -04:00
Alessio Gravili
c45fbb9149 feat!: 700% faster deepCopyObject, refactor deep merging and deep copying, type improvements (#7272)
**BREAKING:**
- The `deepMerge` exported from payload now handles more complex data and
is slower. The old, simple deepMerge is now exported as `deepMergeSimple`
- `combineMerge` is no longer exported. You can use
`deepMergeWithCombinedArrays` instead
- The behavior of the exported `deepCopyObject` and `isPlainObject` may
be different and more reliable, as the underlying algorithm has changed
2024-07-22 13:01:52 -04:00
Patrik
2c16c608ba fix(payload): resizes images first before applying focal point (#7277)
Fixes #7275
2024-07-22 12:28:35 -04:00
Paul
c3f6c81dc6 chore: add custom ID warning about forbidden characters (#7268) 2024-07-22 02:23:53 +00:00
Alessio Gravili
a7b0f8ba36 feat!: new server-only, faster and immediate autoLogin (#7224)
- When autoLogin is enabled, it will no longer flash an unresponsive
"login" screen. Instead, it will straight up open the admin panel.
That's because, on the server, we will now always & immediately see the
user as authenticated, thus no initial login view is pushed to the
client until the client component sends the auth request anymore. Less
useless requests. Additionally, jwt verification is now completely
skipped
- No more auto-login related frontend code. autoLogin handling has been
removed from the frontend `Auth` component
- less code to maintain, this is way simpler now

**For reviewers:**
- The new logic for autoFill without prefillOnly is here: [jwt auth
strategy](https://github.com/payloadcms/payload/pull/7224/files#diff-7d40839079a8b2abb58233e5904513ab321023a70538229dfaf1dfee067dc8bfR21)
- The new logic for autoFill with prefillOnly is here: [Server Login
View](https://github.com/payloadcms/payload/pull/7224/files#diff-683770104f196196743398a698fbf8987f00e4426ca1c0ace3658d18ab80e82dL72)
=> [Client Login
Form](https://github.com/payloadcms/payload/pull/7224/files#diff-ac3504d3b3b0489455245663649bef9e84477bf0c1185da5a4d3a612450f01eeL20)

**BREAKING**
`autoLogin` without `prefillOnly` set now also affects graphQL/Rest
operations. Only the user specified in `autoLogin` will be returned.
Within the graphQL/Rest/Local API, this should still allow you to
authenticate with a different user, as the autoLogin user is only used
if no token is set.
2024-07-20 23:25:50 +00:00
Paul
014ee1a1b2 feat(ui): change autosave logic to send updates as soon as possible, improving live preview speed (#7201)
Now has a minimum animation time for the autosave but it fires off the
send events sooner to improve the live preview timing.
2024-07-19 15:24:53 -04:00
Patrik
cf6da0186b chore(translations, ui): updates addImage translation to addFile translation (#7231) 2024-07-19 13:36:37 -04:00
Jacob Fletcher
18063bd256 chore(examples): proper module resolution and migrations for multi-tenant single-domain example (#7240) 2024-07-19 13:18:13 -04:00
Paul
76b3075369 feat: update reserved fields name check to be more comprehensive and only check top level fields (#7235)
Continuation of https://github.com/payloadcms/payload/pull/7179
2024-07-19 15:53:00 +00:00
Jacob Fletcher
3d63ce94bb fix: api errors not populating in prod (#7232) 2024-07-19 11:42:53 -04:00
Paul
f8a5103ed7 chore(docs): update rest API handler to async (#7237)
Closes https://github.com/payloadcms/payload/issues/7077
2024-07-19 15:41:10 +00:00
Paul
2bd53a06eb chore(templates): add react cache to queryPostBySlug in website template (#7219) 2024-07-18 18:20:05 +00:00
Elliot DeNolf
442518dbc9 ci: make release script synchronous to ensure consistency 2024-07-18 14:09:36 -04:00
Elliot DeNolf
d3131122db chore(release): v3.0.0-beta.67 [skip ci] 2024-07-18 14:00:49 -04:00
Alessio Gravili
6d0dfeafc8 chore: ensure fs operations in bundle scripts finish in sync (#7218)
Hopefully fixes broken releases
2024-07-18 13:44:26 -04:00
Patrik
00771b1f2a fix(ui): uploading from drawer & focal point positioning (#7117)
Fixes #7101
Fixes #7006

Drawers were sending duplicate query params. This new approach modeled after the fix in V2, ensures that each drawer has its own action url created per document and the query params will be created when that is generated.

Also fixes the following:
- incorrect focal point cropping
- generated filenames for animated image names used incorrect heights
2024-07-18 13:43:53 -04:00
Jarrod Flesch
448186f374 chore: use href for locale switching, warns user before leaving (#7215)
Opts to use links instead of router.replace when switching locales. The
main benefit is now the user will be warned if they have changes and
want to switch locales. Before it would switch locales and they would
lose any unsaved changes in the locale they came from.
2024-07-18 12:59:27 -04:00
Elliot DeNolf
0ada3df220 chore(release): v3.0.0-beta.66 [skip ci] 2024-07-18 12:25:49 -04:00
Jarrod Flesch
478fb8d3fd fix: cherry picks lockUntil fix from #6052 (#7213) 2024-07-18 12:14:31 -04:00
Jacob Fletcher
700baf1899 fix: aliases AfterMe, AfterLogout, and AfterRefresh hook types (#7216) 2024-07-18 15:49:50 +00:00
Jarrod Flesch
7b3b02198c feat: ability to login with email, username or both (#7086)
`auth.loginWithUsername`:

```ts
auth: {
  loginWithUsername: {
    allowEmailLogin: true, // default: false
    requireEmail: false, // default: false
  }
}
```

#### `allowEmailLogin`
This property will allow you to determine if users should be able to
login with either email or username. If set to `false`, the default
value, then users will only be able to login with usernames when using
the `loginWithUsername` property.

#### `requireEmail`
Require that users also provide emails when using usernames.
2024-07-18 10:29:44 -04:00
Paul
a3af3605f0 fix(templates): bad import in website seed script (#7198) 2024-07-17 18:20:43 +00:00
Paul
502548a581 feat: add db idType to generated payload types (#7186)
Makes it so generated types now includes a `db` object with `idType` set
to `string` or `number` depending on the database

```ts
db: {
  defaultIDType: number;
};
```
2024-07-17 18:01:28 +00:00
Alessio Gravili
1fe6761d43 fix: maxListenersExceeded warning due to atomically, which is a peerdep of conf (#7182)
The conf dependency being bundled (not even executed) causes frequent
HMR runs (around 10+) to throw multiple MaxListenersExceeded warnings in
the console.

This PR
- fixes telemetry which was previously broken (threw an error which we
ignored) due to a conf version upgrade
- Removes the conf dependency (which is large and comes with a lot of
unneeded dependencies from functionality we don't need, like dot
notation or ajv validation). The important parts of the source code were
copied over - it's now dependency-free
- makes sure we only register the Next.js HMR websocket listener once,
by adding it to the cache

Before this PR:
![CleanShot 2024-07-16 at 19 35
22](https://github.com/user-attachments/assets/cfd926b7-fe5d-440a-9b35-91f61eaa69fd)


After this PR:

![CleanShot 2024-07-16 at 19 37
41](https://github.com/user-attachments/assets/f5d0f0f3-4e00-4d28-8e32-be42db2f5f6c)

Canary: 3.0.0-canary.ca3dd1c
2024-07-17 13:19:08 -04:00
Paul
f909f0663b fix(ui): search queries remain between navigation (#7169)
Closes https://github.com/payloadcms/payload/issues/7085
2024-07-17 17:17:46 +00:00
Jacob Fletcher
edb501349f docs: improves authentication docs (#7195) 2024-07-17 12:52:41 -04:00
Alessio Gravili
4ff8b20ddb chore(templates): clean up templates dependencies (#7139)
- use react 19 types
- no need for dotenv - next has their own dotenv file loader
- disable deprecation warnings by default (newer node version spam you
with it)
- disable turbo by default as hmr is broken and we cannot test against
it yet
- remove ts-node mention in tsconfig as it's not used anymore
- remove unused packages
- [fix: potential seed issues due to parallel payload operations being
on the same
transaction](f899f6a408)
and
b3b565dd75
@DanRibbens can you sense-check this? I do remember that anything
running in parallel should never be on the same transaction

---------

Co-authored-by: Paul Popus <paul@nouance.io>
2024-07-17 02:43:58 +00:00
Alessio Gravili
fe23ca5b1a fix(richtext-lexical): slash menu keyboard navigation not triggering auto-scroll (#7185)
`ref` was not added to internal slash menu items correctly.

Works as expected now:
![CleanShot 2024-07-16 at 22 05
41](https://github.com/user-attachments/assets/cfb32ec8-a449-41a7-a556-1e5ac365c6bc)
2024-07-17 02:30:04 +00:00
Alessio Gravili
8fdd88bd66 fix: webpack error if dbName or enumName was set (#7184)
Something like this:

```ts
  {
    name: 'select',
    type: 'select',
    dbName: ({ tableName }) => `${tableName}_customSelect`,
    enumName: 'selectEnum',
    hasMany: true,
    options: ['a', 'b', 'c'],
},
```
        
caused the "Functions cannot be passed directly to Client Components"
error, as the dbName function was sent to the client.

Now, you can run `pnpm dev database` again without it erroring
2024-07-17 01:02:42 +00:00
Alessio Gravili
676dfa3ecf feat(richtext-lexical): inline blocks (#7102) 2024-07-17 00:42:36 +00:00
Jessica Chowdhury
1ea2e323bc fix(ui): date field background color specificity (#7181)
## Description

Fixes `date` field background in dark mode.

Before:
<img width="464" alt="Screenshot 2024-07-16 at 5 22 42 PM"
src="https://github.com/user-attachments/assets/90235512-bd97-4b0a-b7b8-3e4ce49a8ba2">

After:
<img width="502" alt="Screenshot 2024-07-16 at 5 22 53 PM"
src="https://github.com/user-attachments/assets/ce3f5bc9-8693-4fc8-a0e3-d0042a92756f">

- [X] I have read and understand the
[CONTRIBUTING.md](https://github.com/payloadcms/payload/blob/main/CONTRIBUTING.md)
document in this repository.

## Type of change

- [X] Chore (non-breaking change which does not add functionality)
2024-07-16 21:36:34 +00:00
Jessica Chowdhury
8fb17c2752 fix: version comparison view showing empty localized fields (#7180)
## Description

Localized fields show no data for the base comparison data in the
version comparison view.

Before:
<img width="1419" alt="Screenshot 2024-07-16 at 4 48 45 PM"
src="https://github.com/user-attachments/assets/c4c063a6-41c1-41a5-92b3-ff7d1febe9f1">

After:
<img width="1382" alt="Screenshot 2024-07-16 at 4 46 31 PM"
src="https://github.com/user-attachments/assets/bbfa9faf-2753-450d-a911-fbbca27ab051">

- [X] I have read and understand the
[CONTRIBUTING.md](https://github.com/payloadcms/payload/blob/main/CONTRIBUTING.md)
document in this repository.

## Type of change

- [X] Bug fix (non-breaking change which fixes an issue)

## Checklist:

- [X] Existing test suite passes locally with my changes
2024-07-16 21:08:48 +00:00
Jacob Fletcher
2d96a1f0b6 docs: misc improvements to high-level docs (#7177) 2024-07-16 15:47:56 -04:00
Paul
2f0aa83a93 fix: localised relationship fields (#7178)
Fixes the issue where locale is not passed into the relationship field
resulting in documents without titles in some situations


![image](https://github.com/user-attachments/assets/67f0a70c-29a0-4f54-a395-f4aa9b132d6f)
2024-07-16 19:22:37 +00:00
Jacob Fletcher
0371aea711 docs: moves collection and global admin options to admin docs (#7168) 2024-07-16 12:08:21 -04:00
Alessio Gravili
36ae125caf chore(richtext-lexical): adjust error message when loading the editor on unmigrated data (#7170) 2024-07-16 16:07:53 +00:00
Jarrod Flesch
fa07b317b1 chore(examples): updates to multi tenant single domain example (#7165) 2024-07-16 09:06:46 -04:00
Alessio Gravili
08f50bb441 chore: run esbuild scripts in sync, hopefully fixing publishing issues (#7159)
We are suspecting that operations within those esbuild scripts are not
awaited properly - potentially causing issues in the publish script,
publishing the next package without any built .js files
2024-07-15 17:31:48 -04:00
Jacob Fletcher
2925c3bb90 docs: root hooks (#7160) 2024-07-15 17:15:34 -04:00
Alessio Gravili
c6da04a061 feat(next): strongly type getNextRequestI18n (#7157)
Fixes https://github.com/payloadcms/payload/issues/7137
2024-07-15 20:48:17 +00:00
Alessio Gravili
809ae41725 chore(richtext-lexical): add e2e test which reproduces #7128 (#7156)
Fix for this is in separate PR:
https://github.com/payloadcms/payload/pull/7155
2024-07-15 20:47:03 +00:00
Elliot DeNolf
ee6ab214a5 chore(release): v3.0.0-beta.65 [skip ci] 2024-07-15 16:29:22 -04:00
450 changed files with 8589 additions and 28537 deletions

View File

@@ -63,7 +63,7 @@ Each test directory is split up in this way specifically to reduce friction when
The following command will start Payload with your config: `pnpm dev my-test-dir`. Example: `pnpm dev fields` for the test/`fields` test suite. This command will start up Payload using your config and refresh a test database on every restart. If you're using VS Code, the most common run configs are automatically added to your editor - you should be able to find them in your VS Code launch tab.
By default, payload will [automatically log you in](https://payloadcms.com/docs/authentication/config#admin-autologin) with the default credentials. To disable that, you can either pass in the --no-auto-login flag (example: `pnpm dev my-test-dir --no-auto-login`) or set the `PAYLOAD_PUBLIC_DISABLE_AUTO_LOGIN` environment variable to `false`.
By default, payload will [automatically log you in](https://payloadcms.com/docs/authentication/overview#admin-autologin) with the default credentials. To disable that, you can either pass in the --no-auto-login flag (example: `pnpm dev my-test-dir --no-auto-login`) or set the `PAYLOAD_PUBLIC_DISABLE_AUTO_LOGIN` environment variable to `false`.
The default credentials are `dev@payloadcms.com` as E-Mail and `test` as password. These are used in the auto-login.
@@ -120,5 +120,5 @@ This is how you can preview changes you made locally to the docs:
2. Run `yarn install`
3. Duplicate the `.env.example` file and rename it to `.env`
4. Add a `DOCS_DIR` environment variable to the `.env` file which points to the absolute path of your modified docs folder. For example `DOCS_DIR=/Users/yourname/Documents/GitHub/payload/docs`
5. Run `yarn run fetchDocs:local`. If this was successful, you should see no error messages and the following output: *Docs successfully written to /.../website/src/app/docs.json*. There could be error messages if you have incorrect markdown in your local docs folder. In this case, it will tell you how you can fix it
5. Run `yarn run fetchDocs:local`. If this was successful, you should see no error messages and the following output: _Docs successfully written to /.../website/src/app/docs.json_. There could be error messages if you have incorrect markdown in your local docs folder. In this case, it will tell you how you can fix it
6. You're done! Now you can start the website locally using `yarn run dev` and preview the docs under [http://localhost:3000/docs/](http://localhost:3000/docs/)

View File

@@ -44,7 +44,7 @@ export const CollectionWithAccessControl: CollectionConfig = {
unlock: () => {...},
// Version-enabled Collections only
readVersion: () => {...},
readVersions: () => {...},
},
// highlight-end
}
@@ -286,7 +286,7 @@ The following arguments are provided to the `admin` function:
### Unlock
Determines which users can [unlock](/docs/authentication/operations#unlock) other users who may be blocked from authenticating successfully due to [failing too many login attempts](/docs/authentication/config#options).
Determines which users can [unlock](/docs/authentication/operations#unlock) other users who may be blocked from authenticating successfully due to [failing too many login attempts](/docs/authentication/overview#options).
To add Unlock Access Control to a Collection, use the `unlock` property in the [Collection Config](../collections/overview):

View File

@@ -46,7 +46,7 @@ const defaultPayloadAccess = ({ req: { user } }) => {
In the [Local API](../local-api/overview), all Access Control is _skipped_ by default. This allows your server to have full control over your application. To opt back in, you can set the `overrideAccess` option to `false` in your requests.
</Banner>
## The Admin Panel
## The Access Operation
The Admin Panel responds dynamically to your changes to Access Control. For example, if you restrict editing `ExampleCollection` to only users that feature an "admin" role, Payload will **hide** that Collection from the Admin Panel entirely. This is super powerful and allows you to control who can do what within your Admin Panel using the same functions that secure your APIs.

173
docs/admin/collections.mdx Normal file
View File

@@ -0,0 +1,173 @@
---
title: Collection Admin Config
label: Collections
order: 20
desc:
keywords: admin, components, custom, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
The behavior of [Collections](../configuration/collections) within the [Admin Panel](./overview) can be fully customized to fit the needs of your application. This includes grouping or hiding their navigation links, adding [Custom Components](./components), selecting which fields to display in the List View, and more.
To configure Admin Options for Collections, use the `admin` property in your Collection Config:
```ts
import { CollectionConfig } from 'payload'
export const MyCollection: CollectionConfig = {
// ...
admin: { // highlight-line
// ...
},
}
```
## Admin Options
The following options are available:
| Option | Description |
| ---------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`group`** | Text used as a label for grouping Collection and Global links together in the navigation. |
| **`hidden`** | Set to true or a function, called with the current user, returning true to exclude this Collection from navigation and admin routing. |
| **`hooks`** | Admin-specific hooks for this Collection. [More details](../hooks/collections). |
| **`useAsTitle`** | Specify a top-level field to use for a document title throughout the Admin Panel. If no field is defined, the ID of the document is used as the title. |
| **`description`** | Text or React component to display below the Collection label in the List View to give editors more information. |
| **`defaultColumns`** | Array of field names that correspond to which columns to show by default in this Collection's List View. |
| **`hideAPIURL`** | Hides the "API URL" meta field while editing documents within this Collection. |
| **`enableRichTextLink`** | The [Rich Text](../fields/rich-text) field features a `Link` element which allows for users to automatically reference related documents within their rich text. Set to `true` by default. |
| **`enableRichTextRelationship`** | The [Rich Text](../fields/rich-text) field features a `Relationship` element which allows for users to automatically reference related documents within their rich text. Set to `true` by default. |
| **`meta`** | Metadata overrides to apply to the Admin Panel. Included properties are `description` and `openGraph`. |
| **`preview`** | Function to generate preview URLs within the Admin Panel that can point to your app. [More details](#preview). |
| **`livePreview`** | Enable real-time editing for instant visual feedback of your front-end application. [More details](../live-preview/overview). |
| **`components`** | Swap in your own React components to be used within this Collection. [More details](#components). |
| **`listSearchableFields`** | Specify which fields should be searched in the List search view. [More details](#list-searchable-fields). |
| **`pagination`** | Set pagination-specific options for this Collection. [More details](#pagination). |
### Components
Collections can set their own [Custom Components](./components) which only apply to [Collection](../configuration/collections)-specific UI within the [Admin Panel](./overview). This includes elements such as the Save Button, or entire layouts such as the Edit View.
To override Collection Components, use the `admin.components` property in your [Collection Config](../configuration/collections):
```ts
import type { SanitizedCollectionConfig } from 'payload'
import { CustomSaveButton } from './CustomSaveButton'
export const MyCollection: SanitizedCollectionConfig = {
// ...
admin: {
components: { // highlight-line
// ...
},
},
}
```
The following options are available:
| Path | Description |
| -------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
| **`beforeList`** | An array of components to inject _before_ the built-in List View |
| **`beforeListTable`** | An array of components to inject _before_ the built-in List View's table |
| **`afterList`** | An array of components to inject _after_ the built-in List View |
| **`afterListTable`** | An array of components to inject _after_ the built-in List View's table |
| **`edit.SaveButton`** | Replace the default Save Button with a Custom Component. [Drafts](../versions/drafts) must be disabled. |
| **`edit.SaveDraftButton`** | Replace the default Save Draft Button with a Custom Component. [Drafts](../versions/drafts) must be enabled and autosave must be disabled. |
| **`edit.PublishButton`** | Replace the default Publish Button with a Custom Component. [Drafts](../versions/drafts) must be enabled. |
| **`edit.PreviewButton`** | Replace the default Preview Button with a Custom Component. [Preview](#preview) must be enabled. |
| **`views`** | Override or create new views within the Admin Panel. [More details](./views). |
<Banner type="success">
<strong>Note:</strong>
For details on how to build Custom Components, see [Building Custom Components](./components#building-custom-components).
</Banner>
### Preview
It is possible to display a Preview Button within the Edit View of the Admin Panel. This will allow editors to visit the frontend of your app the corresponds to the document they are actively editing. This way they can preview the latest, potentially unpublished changes.
To configure the Preview Button, set the `admin.preview` property to a function in your [Collection Config](../configuration/collections):
```ts
import { CollectionConfig } from 'payload'
export const Posts: CollectionConfig = {
// ...
admin: {
// highlight-start
preview: (doc, { locale }) => {
if (doc?.slug) {
return `/${doc.slug}?locale=${locale}`
}
return null
},
// highlight-end
},
}
```
The preview function receives two arguments:
| Argument | Description |
| --- | --- |
| **`doc`** | The Document being edited. |
| **`ctx`** | An object containing `locale` and `token` properties. The `token` is the currently logged-in user's JWT. |
<Banner type="success">
<strong>Note:</strong>
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
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, and uses the same [Pagination](../queries/pagination) API that Payload provides.
To configure pagination options, use the `admin.pagination` property in your [Collection Config](../configuration/collections):
```ts
import { CollectionConfig } from 'payload'
export const Posts: CollectionConfig = {
// ...
admin: {
// highlight-start
pagination: {
defaultLimit: 10,
limits: [10, 20, 50],
},
// highlight-end
},
}
```
The following options are available:
| Option | Description |
| -------------- | --------------------------------------------------------------------------------------------------- |
| `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. |
### 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.
To define which fields should be searched, use the `admin.listSearchableFields` property in your [Collection Config](../configuration/collections):
```ts
import { CollectionConfig } from 'payload'
export const Posts: CollectionConfig = {
// ...
admin: {
// highlight-start
listSearchableFields: ['title', 'slug'],
// highlight-end
},
}
```
<Banner type="warning">
<strong>Tip:</strong>
If you are adding `listSearchableFields`, make sure you index each of these fields so your admin queries can remain performant.
</Banner>

View File

@@ -1,7 +1,7 @@
---
title: Swap in your own React components
label: Custom Components
order: 20
order: 40
desc: Fully customize your Admin Panel by swapping in your own React components. Add fields, remove views, update routes and change functions to sculpt your perfect Dashboard.
keywords: admin, components, custom, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
@@ -18,8 +18,8 @@ All Custom Components in Payload are [React Server Components](https://react.dev
There are four main types of Custom Components in Payload:
- [Root Components](#root-components)
- [Collection Components](#collection-components)
- [Global Components](#global-components)
- [Collection Components](./collections#components)
- [Global Components](./globals#components)
- [Field Components](./fields)
To swap in your own Custom Component, consult the list of available components. Determine the scope that corresponds to what you are trying to accomplish, then [author your React component(s)](#building-custom-components) accordingly.
@@ -38,11 +38,11 @@ import { MyCustomLogo } from './MyCustomLogo'
export default buildConfig({
// ...
admin: {
// highlight-start
components: {
graphics: {
Logo: MyCustomLogo, // highlight-line
},
// ...
},
// highlight-end
},
})
```
@@ -63,17 +63,18 @@ The following options are available:
| **`logout.Button`** | The button displayed in the sidebar that logs the user out. |
| **`graphics.Icon`** | The simplified logo used in contexts like the the `Nav` component. |
| **`graphics.Logo`** | The full logo used in contexts like the `Login` view. |
| **`providers`** | Custom [React Context](https://react.dev/learn/scaling-up-with-reducer-and-context) providers that will wrap the entire [Admin Panel](./overview). [More details](#custom-providers). |
| **`actions`** | An array of Custom Components to be rendered in the header of the [Admin Panel](./overview), providing additional interactivity and functionality. |
| **`views`** | Override or create new views within the [Admin Panel](./overview). [More details](./views). |
| **`providers`** | Custom [React Context](https://react.dev/learn/scaling-up-with-reducer-and-context) providers that will wrap the entire Admin Panel. [More details](#custom-providers). |
| **`actions`** | An array of Custom Components to be rendered in the header of the Admin Panel, providing additional interactivity and functionality. |
| **`views`** | Override or create new views within the Admin Panel. [More details](./views). |
<Banner type="success">
<strong>Note:</strong> You can also use the `admin.components` property in your _[Collection](#collection-components) or [Global](#global-components)_.
<strong>Note:</strong>
You can also use set [Collection Components](./collections#components) and [Global Components](./globals#components) in their respective configs.
</Banner>
### Custom Providers
As you add more and more Custom Components to your [Admin Panel](./overview), you may find it helpful to add additional [React Context](https://react.dev/learn/scaling-up-with-reducer-and-context)(s). Payload allows you to inject your own context providers in your app where you can export your own custom hooks, etc.
As you add more and more Custom Components to your [Admin Panel](./overview), you may find it helpful to add additional [React Context](https://react.dev/learn/scaling-up-with-reducer-and-context)(s). Payload allows you to inject your own context providers in your app so you can export your own custom hooks, etc.
To add a Custom Provider, use the `admin.components.providers` property in your [Payload Config](../getting-started/overview):
@@ -115,80 +116,6 @@ export const useMyCustomContext = () => useContext(MyCustomContext)
<strong>Reminder:</strong> Custom Providers are by definition Client Components. This means they must include the `use client` directive at the top of their files and cannot use server-only code.
</Banner>
## Collection Components
Collection Components are those that effect [Collection](../configuration/collections)-specific UI within the [Admin Panel](./overview), such as the save button or the List View.
To override Collection Components, use the `admin.components` property in your [Collection Config](../configuration/collections):
```ts
import type { SanitizedCollectionConfig } from 'payload'
import { CustomSaveButton } from './CustomSaveButton'
export const MyCollection: SanitizedCollectionConfig = {
slug: 'my-collection',
admin: {
components: {
edit: {
SaveButton: CustomSaveButton, // highlight-line
},
},
},
// ...
}
```
_For details on how to build Custom Components, see [Building Custom Components](#building-custom-components)._
The following options are available:
| Path | Description |
| -------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
| **`beforeList`** | An array of components to inject _before_ the built-in List View |
| **`beforeListTable`** | An array of components to inject _before_ the built-in List View's table |
| **`afterList`** | An array of components to inject _after_ the built-in List View |
| **`afterListTable`** | An array of components to inject _after_ the built-in List View's table |
| **`edit.SaveButton`** | Replace the default `Save` button with a Custom Component. Drafts must be disabled |
| **`edit.SaveDraftButton`** | Replace the default `Save Draft` button with a Custom Component. Drafts must be enabled and autosave must be disabled. |
| **`edit.PublishButton`** | Replace the default `Publish` button with a Custom Component. Drafts must be enabled. |
| **`edit.PreviewButton`** | Replace the default `Preview` button with a Custom Component. |
| **`views`** | Override or create new views within the [Admin Panel](./overview). [More details](./views). |
## Global Components
Global Components are those that effect [Global](../configuration/globals)-specific UI within the [Admin Panel](./overview), such as the save button or the Edit View.
To override Global Components, use the `admin.components` property in your [Global Config](../configuration/globals):
```ts
import type { SanitizedGlobalConfig } from 'payload'
import { CustomSaveButton } from './CustomSaveButton'
export const MyGlobal: SanitizedGlobalConfig = {
slug: 'my-global',
admin: {
components: {
elements: {
SaveButton: CustomSaveButton, // highlight-line
},
},
},
// ...
}
```
_For details on how to build Custom Components, see [Building Custom Components](#building-custom-components)._
The following options are available:
| Path | Description |
| ------------------------------ | ---------------------------------------------------------------------------------------------------------------------- |
| **`elements.SaveButton`** | Replace the default `Save` button with a Custom Component. Drafts must be disabled. |
| **`elements.SaveDraftButton`** | Replace the default `Save Draft` button with a Custom Component. Drafts must be enabled and autosave must be disabled. |
| **`elements.PublishButton`** | Replace the default `Publish` button with a Custom Component. Drafts must be enabled. |
| **`elements.PreviewButton`** | Replace the default `Preview` button with a Custom Component. |
| **`views`** | Override or create new views within the [Admin Panel](./overview). [More details](./views). |
## Building Custom Components
All Custom Components in Payload are [React Server Components](https://react.dev/reference/rsc/server-components) by default, with the exception of [Custom Providers](#custom-providers). This enables the use of the [Local API](../local-api) directly on the front-end, among other things.

View File

@@ -1,7 +1,7 @@
---
title: Customizing CSS & SCSS
label: Customizing CSS
order: 60
order: 80
desc: Customize the Payload Admin Panel further by adding your own CSS or SCSS style sheet to the configuration, powerful theme and design options are waiting for you.
keywords: admin, css, scss, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---

View File

@@ -1,7 +1,7 @@
---
title: Customizing Fields
label: Customizing Fields
order: 40
order: 60
desc:
keywords:
---
@@ -18,7 +18,7 @@ For example, your app might need to render a specific interface that Payload doe
## Admin Options
You can customize the appearance and behavior of fields within the [Admin Panel](./overvieW) through the `admin` property of any [Field Config](../fields/overview):
You can customize the appearance and behavior of fields within the [Admin Panel](./overview) through the `admin` property of any [Field Config](../fields/overview):
```ts
import type { CollectionConfig } from 'payload'

108
docs/admin/globals.mdx Normal file
View File

@@ -0,0 +1,108 @@
---
title: Global Admin Config
label: Globals
order: 30
desc:
keywords: admin, components, custom, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
The behavior of [Globals](../configuration/globals) within the [Admin Panel](./overview) can be fully customized to fit the needs of your application. This includes grouping or hiding their navigation links, adding [Custom Components](./components), setting page metadata, and more.
To configure Admin Options for Globals, use the `admin` property in your Global Config:
```ts
import { GlobalConfig } from 'payload'
export const MyGlobal: GlobalConfig = {
// ...
admin: { // highlight-line
// ...
},
}
```
## Admin Options
The following options are available:
| Option | Description |
| ------------- | --------------------------------------------------------------------------------------------------------------------------------- |
| **`group`** | Text used as a label for grouping Collection and Global links together in the navigation. |
| **`hidden`** | Set to true or a function, called with the current user, returning true to exclude this Global from navigation and admin routing. |
| **`components`** | Swap in your own React components to be used within this Global. [More details](#components). |
| **`preview`** | Function to generate a preview URL within the Admin Panel for this Global that can point to your app. [More details](#preview). |
| **`livePreview`** | Enable real-time editing for instant visual feedback of your front-end application. [More details](../live-preview/overview). |
| **`hideAPIURL`** | Hides the "API URL" meta field while editing documents within this collection. |
| **`meta`** | Metadata overrides to apply to the Admin Panel. Included properties are `description` and `openGraph`. |
### Components
Globals can set their own [Custom Components](./components) which only apply to [Global](../configuration/globals)-specific UI within the [Admin Panel](./overview). This includes elements such as the Save Button, or entire layouts such as the Edit View.
To override Global Components, use the `admin.components` property in your [Global Config](../configuration/globals):
```ts
import type { SanitizedGlobalConfig } from 'payload'
import { CustomSaveButton } from './CustomSaveButton'
export const MyGlobal: SanitizedGlobalConfig = {
// ...
admin: {
components: { // highlight-line
// ...
},
},
}
```
The following options are available:
| Path | Description |
| ------------------------------ | ---------------------------------------------------------------------------------------------------------------------- |
| **`elements.SaveButton`** | Replace the default Save Button with a Custom Component. [Drafts](../versions/drafts) must be disabled. |
| **`elements.SaveDraftButton`** | Replace the default Save Draft Button with a Custom Component. [Drafts](../versions/drafts) must be enabled and autosave must be disabled. |
| **`elements.PublishButton`** | Replace the default Publish Button with a Custom Component. [Drafts](../versions/drafts) must be enabled. |
| **`elements.PreviewButton`** | Replace the default Preview Button with a Custom Component. [Preview](#preview) must be enabled. |
| **`views`** | Override or create new views within the Admin Panel. [More details](./views). |
<Banner type="success">
<strong>Note:</strong>
For details on how to build Custom Components, see [Building Custom Components](./components#building-custom-components).
</Banner>
### Preview
It is possible to display a Preview Button within the Edit View of the Admin Panel. This will allow editors to visit the frontend of your app the corresponds to the document they are actively editing. This way they can preview the latest, potentially unpublished changes.
To configure the Preview Button, set the `admin.preview` property to a function in your Global Config:
```ts
import { GlobalConfig } from 'payload'
export const MainMenu: GlobalConfig = {
// ...
admin: {
// highlight-start
preview: (doc, { locale }) => {
if (doc?.slug) {
return `/${doc.slug}?locale=${locale}`
}
return null
},
// highlight-end
},
}
```
The preview function receives two arguments:
| Argument | Description |
| --- | --- |
| **`doc`** | The Document being edited. |
| **`ctx`** | An object containing `locale` and `token` properties. The `token` is the currently logged-in user's JWT. |
<Banner type="success">
<strong>Note:</strong>
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>

View File

@@ -1,7 +1,7 @@
---
title: React Hooks
label: React Hooks
order: 50
order: 70
desc: Make use of all of the powerful React hooks that Payload provides.
keywords: admin, components, custom, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---

View File

@@ -55,6 +55,11 @@ As shown above, all Payload routes are nested within the `(payload)` route group
The `admin` directory contains all the _pages_ related to the interface itself, whereas the `api` and `graphql` directories contains all the _routes_ related to the [REST API](../rest-api/overview) and [GraphQL API](../graphql/overview). All admin routes are [easily configurable](#customizing-routes) to meet your application's exact requirements.
<Banner type="warning">
<strong>Note:</strong>
If you don't use the [REST API](../rest/overview) or [GraphQL API](../graphql/overview), you can delete the [Next.js files corresponding to those routes](../admin/overview#project-structure), however, the overhead of this API is completely constrained to these endpoints, and will not slow down or affect Payload outside of the endpoints.
</Banner>
Finally, the `custom.scss` file is where you can add or override globally-oriented styles in the Admin Panel, such as modify the color palette. Customizing the look and feel through CSS alone is a powerful feature of the Admin Panel, [more on that here](./customizing-css).
All auto-generated files will contain the following comments at the top of each file:
@@ -81,23 +86,23 @@ const config = buildConfig({
The following options are available:
| Option | Description |
| ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `user` | The `slug` of the Collection that you want to allow to login to the Admin Panel. [More details](#the-admin-user-collection). |
| `buildPath` | Specify an absolute path for where to store the built Admin bundle used in production. Defaults to `path.resolve(process.cwd(), 'build')`. |
| `meta` | Base metadata to use for the Admin Panel. Included properties are `titleSuffix`, `icons`, and `openGraph`. Can be overridden on a per Collection or per Global basis. |
| `disable` | If set to `true`, the entire Admin Panel will be disabled. |
| `dateFormat` | The date format that will be used for all dates within the Admin Panel. Any valid [date-fns](https://date-fns.org/) format pattern can be used. |
| `avatar` | Set account profile picture. Options: `gravatar`, `default` or a custom React component. |
| `autoLogin` | Used to automate admin log-in for dev and demonstration convenience. [More details](../authentication/config). |
| `livePreview` | Enable real-time editing for instant visual feedback of your front-end application. [More details](../live-preview/overview). |
| `components` | Component overrides that affect the entirety of the Admin Panel. [More details](./components). |
| `routes` | Replace built-in Admin Panel routes with your own custom routes. [More details](#customizing-routes). |
| `custom` | Any custom properties you wish to pass to the Admin Panel. |
| Option | Description |
|---------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `avatar` | Set account profile picture. Options: `gravatar`, `default` or a custom React component. |
| `autoLogin` | Used to automate log-in for dev and demonstration convenience. [More details](../authentication/overview). |
| `buildPath` | Specify an absolute path for where to store the built Admin bundle used in production. Defaults to `path.resolve(process.cwd(), 'build')`. |
| `components` | Component overrides that affect the entirety of the Admin Panel. [More details](./components). |
| `custom` | Any custom properties you wish to pass to the Admin Panel. |
| `dateFormat` | The date format that will be used for all dates within the Admin Panel. Any valid [date-fns](https://date-fns.org/) format pattern can be used. |
| `disable` | If set to `true`, the entire Admin Panel will be disabled. |
| `livePreview` | Enable real-time editing for instant visual feedback of your front-end application. [More details](../live-preview/overview). |
| `meta` | Base metadata to use for the Admin Panel. Included properties are `titleSuffix`, `icons`, and `openGraph`. Can be overridden on a per Collection or per Global basis. |
| `routes` | Replace built-in Admin Panel routes with your own custom routes. [More details](#customizing-routes). |
| `user` | The `slug` of the Collection that you want to allow to login to the Admin Panel. [More details](#the-admin-user-collection). |
<Banner type="success">
<strong>Reminder:</strong>
These are the _root-level_ options for the Admin Panel. You can also customize the admin options for _Collections and Globals_ through their respective `admin` keys.
These are the _root-level_ options for the Admin Panel. You can also customize [Collection Admin Options](./collections) and [Global Admin Options](./globals) through their respective `admin` keys.
</Banner>
### The Admin User Collection

View File

@@ -1,7 +1,7 @@
---
title: Managing User Preferences
label: Preferences
order: 50
order: 70
desc: Store the preferences of your users as they interact with the Admin Panel.
keywords: admin, preferences, custom, customize, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
@@ -22,7 +22,7 @@ Out of the box, Payload handles the persistence of your users' preferences in a
that is reading or setting a preference via all provided authentication methods.
</Banner>
## Use cases
## Use Cases
This API is used significantly for internal operations of the Admin Panel, as mentioned above. But, if you're building your own React components for use in the Admin Panel, you can allow users to set their own preferences in correspondence to their usage of your components. For example:

View File

@@ -1,7 +1,7 @@
---
title: Customizing Views
label: Customizing Views
order: 30
order: 50
desc:
keywords:
---
@@ -278,7 +278,7 @@ export const MyCollectionConfig: SanitizedCollectionConfig = {
Your Custom Views will be provided with the following props:
| Prop | Description |
| ------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- | |
| ------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| **`user`** | The currently logged in user. |
| **`locale`** | The current [Locale](../configuration/localization) of the [Admin Panel](./overview). |
| **`navGroups`** | The grouped navigation items according to `admin.group` in your [Collection Config](../collections/overview) or [Global Config](../globals/overview). |

View File

@@ -1,206 +0,0 @@
---
title: Authentication Config
label: Config
order: 20
desc: Enable and customize options in the Authentication config for features including Forgot Password, Login Attempts, API key usage and more.
keywords: authentication, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
Payload's Authentication is extremely powerful and gives you everything you need when you go to build a new app or site in a secure and responsible manner.
To enable Authentication on a collection, define an `auth` property and set it to either `true` or to an object containing the options below.
## Options
| Option | Description |
|----------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **`useAPIKey`** | Payload Authentication provides for API keys to be set on each user within an Authentication-enabled Collection. [More](/docs/authentication/config#api-keys) |
| **`tokenExpiration`** | How long (in seconds) to keep the user logged in. JWTs and HTTP-only cookies will both expire at the same time. |
| **`maxLoginAttempts`** | Only allow a user to attempt logging in X amount of times. Automatically locks out a user from authenticating if this limit is passed. Set to `0` to disable. |
| **`lockTime`** | Set the time (in milliseconds) that a user should be locked out if they fail authentication more times than `maxLoginAttempts` allows for. |
| **`depth`** | How many levels deep a `user` document should be populated when creating the JWT and binding the `user` to the `req`. Defaults to `0` and should only be modified if absolutely necessary, as this will affect performance. |
| **`cookies`** | Set cookie options, including `secure`, `sameSite`, and `domain`. For advanced users. |
| **`forgotPassword`** | Customize the way that the `forgotPassword` operation functions. [More](/docs/authentication/config#forgot-password) |
| **`verify`** | Set to `true` or pass an object with verification options to require users to verify by email before they are allowed to log into your app. [More](/docs/authentication/config#email-verification) |
| **`disableLocalStrategy`** | Advanced - disable Payload's built-in local auth strategy. Only use this property if you have replaced Payload's auth mechanisms with your own. |
| **`strategies`** | Advanced - an array of custom authentification strategies to extend this collection's authentication with. [More](/docs/authentication/custom-strategies) |
### Forgot Password
You can customize how the Forgot Password workflow operates with the following options on the `auth.forgotPassword` property:
**`generateEmailHTML`**
Function that accepts one argument, containing `{ req, token, user }`, that allows for overriding the HTML within emails that are sent to users attempting to reset their password. The function should return a string that supports HTML, which can be a full HTML email.
<Banner type="success">
<strong>Tip:</strong>
<br />
HTML templating can be used to create custom email templates, inline CSS automatically, and more.
You can make a reusable function that standardizes all email sent from Payload, which makes
sending custom emails more DRY. Payload doesn't ship with an HTML templating engine, so you are
free to choose your own.
</Banner>
Example:
```ts
import { CollectionConfig } from 'payload'
export const Customers: CollectionConfig = {
slug: 'customers',
auth: {
forgotPassword: {
// highlight-start
generateEmailHTML: ({ req, token, user }) => {
// Use the token provided to allow your user to reset their password
const resetPasswordURL = `https://yourfrontend.com/reset-password?token=${token}`
return `
<!doctype html>
<html>
<body>
<h1>Here is my custom email template!</h1>
<p>Hello, ${user.email}!</p>
<p>Click below to reset your password.</p>
<p>
<a href="${resetPasswordURL}">${resetPasswordURL}</a>
</p>
</body>
</html>
`
},
// highlight-end
},
},
}
```
<Banner type="warning">
<strong>Important:</strong>
<br />
If you specify a different URL to send your users to for resetting their password, such as a page
on the frontend of your app or similar, you need to handle making the call to the Payload REST or
GraphQL reset-password operation yourself on your frontend, using the token that was provided for
you. Above, it was passed via query parameter.
</Banner>
**`generateEmailSubject`**
Similarly to the above `generateEmailHTML`, you can also customize the subject of the email. The function argument are the same but you can only return a string - not HTML.
Example:
```ts
{
slug: 'customers',
auth: {
forgotPassword: {
// highlight-start
generateEmailSubject: ({ req, user }) => {
return `Hey ${user.email}, reset your password!`;
}
// highlight-end
}
}
}
```
### Email Verification
If you'd like to require email verification before a user can successfully log in, you can enable it by passing `true` or an `options` object to `auth.verify`. The following options are available:
**`generateEmailHTML`**
Function that accepts one argument, containing `{ req, token, user }`, that allows for overriding the HTML within emails that are sent to users indicating how to validate their account. The function should return a string that supports HTML, which can optionally be a full HTML email.
Example:
```ts
import { CollectionConfig } from 'payload'
export const Customers: CollectionConfig = {
slug: 'customers',
auth: {
verify: {
// highlight-start
generateEmailHTML: ({ req, token, user }) => {
// Use the token provided to allow your user to verify their account
const url = `https://yourfrontend.com/verify?token=${token}`
return `Hey ${user.email}, verify your email by clicking here: ${url}`
},
// highlight-end
},
},
}
```
<Banner type="warning">
<strong>Important:</strong>
<br />
If you specify a different URL to send your users to for email verification, such as a page on the
frontend of your app or similar, you need to handle making the call to the Payload REST or GraphQL
verification operation yourself on your frontend, using the token that was provided for you.
Above, it was passed via query parameter.
</Banner>
**`generateEmailSubject`**
Similarly to the above `generateEmailHTML`, you can also customize the subject of the email. The function argument are the same but you can only return a string - not HTML.
Example:
```ts
{
slug: 'customers',
auth: {
forgotPassword: {
// highlight-start
generateEmailSubject: ({ req, user }) => {
return `Hey ${user.email}, reset your password!`;
}
// highlight-end
}
}
}
```
### 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 default is that all users will have to login and this should not be enabled for environments where data needs to protected.
#### autoLogin Options
| Option | Description |
| ----------------- | --------------------------------------------------------------------------------------------------------------- |
| **`email`** | The email address of the user to login as |
| **`password`** | The password of the user to login as |
| **`prefillOnly`** | If set to true, the login credentials will be prefilled but the user will still need to click the login button. |
The recommended way to use this feature is behind an environment variable to ensure it is disabled when in production.
**Example:**
```ts
export default buildConfig({
admin: {
user: 'users',
// highlight-start
autoLogin:
process.env.PAYLOAD_PUBLIC_ENABLE_AUTOLOGIN === 'true'
? {
email: 'test@example.com',
password: 'test',
prefillOnly: true,
}
: false,
// highlight-end
},
collections: [
/** */
],
})
```

View File

@@ -1,19 +1,16 @@
---
title: Cookie Strategy
label: Cookie Strategy
order: 30
order: 40
desc: Enable HTTP Cookie based authentication to interface with Payload.
keywords: authentication, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
Payload `login`, `logout`, and `refresh` operations make use of HTTP-only cookies for authentication purposes.
Payload offers the ability to [Authenticate](./overview) via HTTP-only cookies. These can be read from the responses of `login`, `logout`, `refresh`, and `me` auth operations.
<Banner type="success">
<strong>Tip:</strong>
<br />
You can access the logged-in user from [Access Control](../access-control/overview) functions and hooks from the `req.user` property.
<br />
[Learn more about token data](/docs/authentication/token-data).
You can access the logged-in user from within [Access Control](../access-control/overview) and [Hooks](../hooks/overview) through the `req.user` argument. [More details](./token-data).
</Banner>
### Automatic browser inclusion
@@ -38,7 +35,6 @@ For more about including cookies in requests from your app to your Payload API,
<Banner type="success">
<strong>Tip:</strong>
<br />
To make sure you have a Payload cookie set properly in your browser after logging in, you can use
the browsers Developer Tools > Application > Cookies > [your-domain-here]. The Developer tools
will still show HTTP-only cookies.

View File

@@ -13,7 +13,7 @@ keywords: authentication, config, configuration, overview, documentation, Conten
### Creating a strategy
At the core, a strategy is a way to authenticate a user making a request. As of `3.0` we moved away from passportJS in favor of pulling back the curtain and putting you in full control.
At the core, a strategy is a way to authenticate a user making a request. As of `3.0` we moved away from [Passport](https://www.passportjs.org) in favor of pulling back the curtain and putting you in full control.
A strategy is made up of the following:

View File

@@ -0,0 +1,203 @@
---
title: Authentication Emails
label: Email Verification
order: 30
desc: Email Verification allows users to verify their email address before they're account is fully activated. Email Verification ties directly into the Email functionality that Payload provides.
keywords: authentication, email, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
[Authentication](./overview) ties directly into the [Email](../email) functionality that Payload provides. This allows you to send emails to users for verification, password resets, and more. While Payload provides default email templates for these actions, you can customize them to fit your brand.
## Email Verification
Email Verification forces users to prove they have access to the email address they can authenticate. This will help to reduce spam accounts and ensure that users are who they say they are.
To enable Email Verification, use the `auth.verify` property on your [Collection Config](../configuration/collections):
```ts
import { CollectionConfig } from 'payload'
export const Customers: CollectionConfig = {
// ...
auth: {
verify: true // highlight-line
},
}
```
<Banner type="info">
<strong>Tip:</strong>
Verification emails are fully customizable. [More details](#generateEmailHTML).
</Banner>
The following options are available:
| Option | Description |
|----------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **`generateEmailHTML`** | Allows for overriding the HTML within emails that are sent to users indicating how to validate their account. [More details](#generateEmailHTML). |
| **`generateEmailSubject`** | Allows for overriding the subject of the email that is sent to users indicating how to validate their account. [More details](#generateEmailSubject). |
#### generateEmailHTML
Function that accepts one argument, containing `{ req, token, user }`, that allows for overriding the HTML within emails that are sent to users indicating how to validate their account. The function should return a string that supports HTML, which can optionally be a full HTML email.
```ts
import { CollectionConfig } from 'payload'
export const Customers: CollectionConfig = {
// ...
auth: {
verify: {
// highlight-start
generateEmailHTML: ({ req, token, user }) => {
// Use the token provided to allow your user to verify their account
const url = `https://yourfrontend.com/verify?token=${token}`
return `Hey ${user.email}, verify your email by clicking here: ${url}`
},
// highlight-end
},
},
}
```
<Banner type="warning">
<strong>Important:</strong>
If you specify a different URL to send your users to for email verification, such as a page on the
frontend of your app or similar, you need to handle making the call to the Payload REST or GraphQL
verification operation yourself on your frontend, using the token that was provided for you.
Above, it was passed via query parameter.
</Banner>
#### generateEmailSubject
Similarly to the above `generateEmailHTML`, you can also customize the subject of the email. The function argument are the same but you can only return a string - not HTML.
```ts
import { CollectionConfig } from 'payload'
export const Customers: CollectionConfig = {
// ...
auth: {
verify: {
// highlight-start
generateEmailSubject: ({ req, user }) => {
return `Hey ${user.email}, reset your password!`;
}
// highlight-end
}
}
}
```
## Forgot Password
You can customize how the Forgot Password workflow operates with the following options on the `auth.forgotPassword` property:
```ts
import { CollectionConfig } from 'payload'
export const Customers: CollectionConfig = {
// ...
auth: {
forgotPassword: { // highlight-line
// ...
},
},
}
```
The following options are available:
| Option | Description |
|----------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **`generateEmailHTML`** | Allows for overriding the HTML within emails that are sent to users attempting to reset their password. [More details](#generateEmailHTML). |
| **`generateEmailSubject`** | Allows for overriding the subject of the email that is sent to users attempting to reset their password. [More details](#generateEmailSubject). |
#### generateEmailHTML
This function allows for overriding the HTML within emails that are sent to users attempting to reset their password. The function should return a string that supports HTML, which can be a full HTML email.
```ts
import { CollectionConfig } from 'payload'
export const Customers: CollectionConfig = {
// ...
auth: {
forgotPassword: {
// highlight-start
generateEmailHTML: ({ req, token, user }) => {
// Use the token provided to allow your user to reset their password
const resetPasswordURL = `https://yourfrontend.com/reset-password?token=${token}`
return `
<!doctype html>
<html>
<body>
<h1>Here is my custom email template!</h1>
<p>Hello, ${user.email}!</p>
<p>Click below to reset your password.</p>
<p>
<a href="${resetPasswordURL}">${resetPasswordURL}</a>
</p>
</body>
</html>
`
},
// highlight-end
},
},
}
```
<Banner type="warning">
<strong>Important:</strong>
If you specify a different URL to send your users to for resetting their password, such as a page
on the frontend of your app or similar, you need to handle making the call to the Payload REST or
GraphQL reset-password operation yourself on your frontend, using the token that was provided for
you. Above, it was passed via query parameter.
</Banner>
<Banner type="success">
<strong>Tip:</strong>
HTML templating can be used to create custom email templates, inline CSS automatically, and more.
You can make a reusable function that standardizes all email sent from Payload, which makes
sending custom emails more DRY. Payload doesn't ship with an HTML templating engine, so you are
free to choose your own.
</Banner>
The following arguments are passed to the `generateEmailHTML` function:
| Argument | Description |
|----------|-----------------------------------------------------------------------------------------------|
| `req` | The request object. |
| `token` | The token that is generated for the user to reset their password. |
| `user` | The user document that is attempting to reset their password. |
#### generateEmailSubject
Similarly to the above `generateEmailHTML`, you can also customize the subject of the email. The function argument are the same but you can only return a string - not HTML.
```ts
import { CollectionConfig } from 'payload'
export const Customers: CollectionConfig = {
// ...
auth: {
forgotPassword: {
// highlight-start
generateEmailSubject: ({ req, user }) => {
return `Hey ${user.email}, reset your password!`;
}
// highlight-end
}
}
}
```
The following arguments are passed to the `generateEmailSubject` function:
| Argument | Description |
|----------|-----------------------------------------------------------------------------------------------|
| `req` | The request object. |
| `user` | The user document that is attempting to reset their password. |

View File

@@ -6,14 +6,11 @@ desc: Enable JSON Web Token based authentication to interface with Payload.
keywords: authentication, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
Payload offers the ability to authenticate via `JWT` (JSON web token). These can be read from the responses of `login`, `refresh`, and `me` auth operations.
Payload offers the ability to [Authenticate](./overview) via JSON Web Tokens (JWT). These can be read from the responses of `login`, `logout`, `refresh`, and `me` auth operations.
<Banner type="success">
<strong>Tip:</strong>
<br />
You can access the logged-in user from [Access Control](../access-control/overview) functions and hooks from the `req.user` property.
<br />
[Learn more about token data](/docs/authentication/token-data).
You can access the logged-in user from within [Access Control](../access-control/overview) and [Hooks](../hooks/overview) through the `req.user` argument. [More details](./token-data).
</Banner>
### Identifying Users Via The Authorization Header

View File

@@ -1,12 +1,12 @@
---
title: Authentication Operations
label: Operations
order: 80
order: 20
desc: Enabling Authentication automatically makes key operations available such as Login, Logout, Verify, Unlock, Reset Password and more.
keywords: authentication, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
Enabling Authentication on a Collection automatically exposes additional auth-based operations in the Local, REST, and GraphQL APIs.
Enabling [Authentication](./overview) on a [Collection](../configuration/collections) automatically exposes additional auth-based operations in the [Local API](../local-api/overview), [REST API](../rest-api/overview), and [GraphQL API](../graphql/overview).
## Access
@@ -308,7 +308,7 @@ Payload comes with built-in forgot password functionality. Submitting an email a
The link to reset the user's password contains a token which is what allows the user to securely reset their password.
By default, the Forgot Password operations send users to the [Admin Panel](../admin/overview) to reset their password, but you can customize the generated email to send users to the frontend of your app instead by [overriding the email HTML](/docs/authentication/config#forgot-password).
By default, the Forgot Password operations send users to the [Admin Panel](../admin/overview) to reset their password, but you can customize the generated email to send users to the frontend of your app instead by [overriding the email HTML](/docs/authentication/overview#forgot-password).
**Example REST API Forgot Password**:

View File

@@ -11,38 +11,47 @@ keywords: authentication, config, configuration, overview, documentation, Conten
title="Simplified Authentication for Headless CMS: Unlocking Reusability in One Line"
/>
<Banner>
Payload provides for highly secure and customizable user Authentication out of the box, which
allows for users to identify themselves to Payload.
</Banner>
Authentication is a critical part of any application. Payload provides a secure, portable way to manage user accounts out of the box. Payload Authentication is designed to be used in both the [Admin Panel](../admin/overview), all well as your own external applications, completely eliminating the need for paid, third-party platforms and services.
Authentication is used within the [Admin Panel](../admin/overview) itself as well as throughout your app(s) themselves however you determine necessary.
Here are some common use cases of Authentication in your own applications:
- Customer accounts for an e-commerce app
- User accounts for a SaaS product
- P2P apps or social sites where users need to log in and manage their profiles
- Online games where players need to track their progress over time
When Authentication is enabled on a [Collection](../configuration/collections), Payload injects all necessary functionality to support the entire user flow. This includes all [auth-related operations](./operations) like account creation, logging in and out, and resetting passwords, all [auth-related emails](./email) like email verification and password reset, as well as any necessary UI to manage users from the Admin Panel.
To enable Authentication on a Collection, use the `auth` property in the [Collection Config](../configuration/collection#auth):
```ts
import { CollectionConfig } from 'payload'
export const Users: CollectionConfig = {
// ...
auth: true, // highlight-line
}
```
![Authentication Admin Panel functionality](https://payloadcms.com/images/docs/auth-admin.jpg)
_Admin Panel screenshot depicting an Admins Collection with Auth enabled_
**Here are some common use cases of Authentication outside of Payload's dashboard itself:**
## Config Options
- Customer accounts for an ecommerce app
- Customer accounts for a SaaS product
- P2P app or social site where users need to log in and manage their profiles
- Online game where players need to track their progress over time
Any [Collection](../configuration/collections) can opt-in to supporting Authentication. Once enabled, each Document that is created within the Collection can be thought of as a "user". This enables a complete authentication workflow on your Collection, such as logging in and out, resetting their password, and more.
By default, Payload provides you with a `User` collection that supports Authentication, which is used to access the [Admin Panel](../admin/overview). But, you can add support to one or many Collections of your own. For more information on how to customize, override, or remove the default `User` collection, [click here](/docs/admin/overview#the-admin-user-collection).
<Banner type="warning">
<strong>Note:</strong>
By default, Payload provides an auth-enabled `User` Collection which is used to access the Admin Panel. [More details](../admin/overview#the-admin-user-collection).
</Banner>
## Enabling Auth on a collection
Every Payload Collection can opt-in to supporting Authentication by specifying the `auth` property on the Collection's config to either `true` or to an object containing `auth` options.
**For a full list of all `auth` options, [click here](/docs/authentication/config).**
Simple example collection:
To enable Authentication on a Collection, use the `auth` property in the [Collection Config](../configuration/collections):
```ts
import { CollectionConfig } from 'payload'
export const Admins: CollectionConfig = {
slug: 'admins',
// ...
// highlight-start
auth: {
tokenExpiration: 7200, // How many seconds to keep the user logged in
@@ -52,53 +61,136 @@ export const Admins: CollectionConfig = {
// More options are available
},
// highlight-end
fields: [
{
name: 'role',
type: 'select',
required: true,
options: ['user', 'admin', 'editor', 'developer'],
},
],
}
```
**By enabling Authentication on a config, the following modifications will automatically be made to your Collection:**
<Banner type="info">
<strong>Tip:</strong>
For default auth behavior, set `auth: true`. This is a good starting point for most applications.
</Banner>
1. `email` as well as password `salt` & `hash` fields will be added to your Collection's schema
1. The [Admin Panel](../admin/overview) will feature a new set of corresponding UI to allow for changing password and editing email
1. [A new set of `operations`](/docs/authentication/operations) will be exposed via Payload's REST, Local, and GraphQL APIs
<Banner type="warning">
<strong>Note:</strong>
Auth-enabled Collections with be automatically injected with the `hash`, `salt`, and `email` fields. [More details](../fields/overview#field-names).
</Banner>
Once enabled, each document that is created within the Collection can be thought of as a `user` - who can make use of commonly required authentication functions such as logging in / out, resetting their password, and more.
The following options are available:
## Authentication Strategies
| Option | Description |
|----------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **`cookies`** | Set cookie options, including `secure`, `sameSite`, and `domain`. For advanced users. |
| **`depth`** | How many levels deep a `user` document should be populated when creating the JWT and binding the `user` to the `req`. Defaults to `0` and should only be modified if absolutely necessary, as this will affect performance. |
| **`disableLocalStrategy`** | Advanced - disable Payload's built-in local auth strategy. Only use this property if you have replaced Payload's auth mechanisms with your own. |
| **`forgotPassword`** | Customize the way that the `forgotPassword` operation functions. [More details](./email#forgot-password). |
| **`lockTime`** | Set the time (in milliseconds) that a user should be locked out if they fail authentication more times than `maxLoginAttempts` allows for. |
| **`loginWithUsername`** | Ability to allow users to login with username/password. [More](/docs/authentication/overview#login-with-username) |
| **`maxLoginAttempts`** | Only allow a user to attempt logging in X amount of times. Automatically locks out a user from authenticating if this limit is passed. Set to `0` to disable. |
| **`strategies`** | Advanced - an array of custom authentification strategies to extend this collection's authentication with. [More details](./custom-strategies). |
| **`tokenExpiration`** | How long (in seconds) to keep the user logged in. JWTs and HTTP-only cookies will both expire at the same time. |
| **`useAPIKey`** | Payload Authentication provides for API keys to be set on each user within an Authentication-enabled Collection. [More details](./api-keys). |
| **`verify`** | Set to `true` or pass an object with verification options to require users to verify by email before they are allowed to log into your app. [More details](./email#email-verification). |
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.
### Login With Username
You can allow users to login with their username instead of their email address by setting the `loginWithUsername` property to `true`.
Example:
```ts
{
slug: 'customers',
auth: {
loginWithUsername: true,
},
}
```
Or, you can pass an object with additional options:
```ts
{
slug: 'customers',
auth: {
loginWithUsername: {
allowEmailLogin: true, // default: false
requireEmail: false, // default: false
},
},
}
```
**`allowEmailLogin`**
If set to `true`, users can log in with either their username or email address. If set to `false`, users can only log in with their username.
**`requireEmail`**
If set to `true`, an email address is required when creating a new user. If set to `false`, email is not required upon creation.
## Auto-Login
For testing and demo purposes you may want to skip forcing the user to login in order to access your application. Typically, all users should be required to login, however, you can speed up local development time by enabling auto-login.
To enable auto-login, set the `autoLogin` property in the [Admin Config](../configuration/admin):
```ts
import { buildConfig } from 'payload'
export default buildConfig({
// ...
// highlight-start
autoLogin:
process.env.NEXT_PUBLIC_ENABLE_AUTOLOGIN === 'true'
? {
email: 'test@example.com',
password: 'test',
prefillOnly: true,
}
: false,
// highlight-end
})
```
<Banner type="warning">
<strong>Warning:</strong>
The recommended way to use this feature is behind an [Environment Variable](../configuration/environment-vars). This will ensure it is _disabled_ in production.
</Banner>
The following options are available:
| Option | Description |
|-------------------|-----------------------------------------------------------------------------------------------------------------|
| **`username`** | The username of the user to login as |
| **`email`** | The email address of the user to login as |
| **`password`** | The password of the user to login as. This is only needed if `prefillOnly` is set to true |
| **`prefillOnly`** | If set to true, the login credentials will be prefilled but the user will still need to click the login button. |
## Operations
All auth-related operations are available via Payload's REST, Local, and GraphQL APIs. These operations are automatically added to your Collection when you enable Authentication. [More details](./operations).
## Strategies
Out of the box Payload ships with a three powerful Authentication strategies:
- [HTTP-Only Cookies](./cookies)
- [JSON Web Tokens (JWT)](./jwt)
- [API-Keys](./api-keys)
Each of these strategies can work together or independently. You can also create your own custom strategies to fit your specific needs. [More details](./custom-strategies).
### HTTP-Only Cookies
HTTP-only cookies are a highly secure method of storing identifiable data on a user's device so that Payload can automatically recognize a returning user until their cookie expires. They are totally protected from common XSS attacks and <strong>cannot be read by JavaScript in the browser</strong>, unlike JWT's.
You can learn more about this strategy from the [HTTP-Only Cookies](/docs/authentication/http-only-cookies) docs.
[HTTP-only cookies](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies) are a highly secure method of storing identifiable data on a user's device so that Payload can automatically recognize a returning user until their cookie expires. They are totally protected from common XSS attacks and <strong>cannot be read by JavaScript in the browser</strong>, unlike JWT's. [More details](./cookies).
### JSON Web Tokens
JWT (JSON Web Tokens) can also be utilized to perform authentication. Tokens are generated on `login`, `refresh` and `me` operations and can be attached to future requests to authenticate users.
You can learn more about this strategy from the [JWT](/docs/authentication/jwt) docs.
JWT (JSON Web Tokens) can also be utilized to perform authentication. Tokens are generated on `login`, `refresh` and `me` operations and can be attached to future requests to authenticate users. [More details](./jwt).
### API Keys
API Keys can be enabled on auth collections. These are particularly useful when you want to authenticate against Payload from a third party service.
You can learn more about this strategy from the [API Keys](/docs/authentication/api-keys) docs.
API Keys can be enabled on auth collections. These are particularly useful when you want to authenticate against Payload from a third party service. [More details](./api-keys).
### Custom Strategies
There are cases where these may not be enough for your application. Payload is extendable by design so you can wire up your own strategy when you need to.
You can learn more about custom strategies from the [Custom Strategies](/docs/authentication/custom-strategies) docs.
## Logging in / out, resetting password, etc.
[Click here](/docs/authentication/operations) for a list of all automatically-enabled Auth operations, including `login`, `logout`, `refresh`, and others.
There are cases where these may not be enough for your application. Payload is extendable by design so you can wire up your own strategy when you need to. [More details](./custom-strategies).

View File

@@ -59,9 +59,7 @@ You can update settings from your Projects Settings tab. Changes to your buil
From the Environment Variables page of the Settings tab, you can add, update and delete variables for use in your project. Like build settings, these changes will trigger a redeployment of your project.
<Banner>
Note: For security reasons, any variables you wish to provide to the [Admin Panel](../admin/overview) must be prefixed
with `PAYLOAD_PUBLIC_`.  Learn more
[here](../configuration/environment-vars).
Note: For security reasons, any variables you wish to provide to the [Admin Panel](../admin/overview) must be prefixed with `NEXT_PUBLIC_`. [More details](../configuration/environment-vars).
</Banner>
## Custom Domains

View File

@@ -6,9 +6,9 @@ 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
---
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.
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 Document in a Collection is stored in the [Database](../database/overview) based on the [Fields](../fields/overview) that you define, and automatically generates a [Local API](../local-api/overview), [REST API](../rest-api/overview), and [GraphQL API](../graphql/overview) used to manage your Documents.
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.
Collections are also used to achieve [Authentication](../authentication/overview) in Payload. By defining a Collection with `auth` options, that Collection receives additional operations to support user authentication.
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.
@@ -59,15 +59,15 @@ The following options are available:
| Option | Description |
|------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **`admin`** | The configuration options for the Admin Panel. [More details](#admin-options). |
| **`admin`** | The configuration options for the Admin Panel. [More details](../admin/collections). |
| **`access`** | Provide Access Control functions to define exactly who should be able to do what with Documents in this Collection. [More details](../access-control/collections). |
| **`auth`** | Specify options if you would like this Collection to feature authentication. For more, consult the [Authentication](../authentication/config) documentation. |
| **`auth`** | Specify options if you would like this Collection to feature authentication. [More details](../authentication/overview). |
| **`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. |
| **`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. |
| **`fields`** \* | Array of field types that will determine the structure and functionality of the data stored within this Collection. [More details](../fields/overview). |
| **`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 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. |
@@ -93,145 +93,14 @@ Fields define the schema of the Documents within a Collection. To learn more, go
### Admin Options
You can customize the way that the [Admin Panel](../admin/overview) behaves on a Collection-by-Collection basis.
To configure Admin Options for Collections, use the `admin` property in your Collection Config:
```ts
import { CollectionConfig } from 'payload'
export const Posts: CollectionConfig = {
// ...
admin: { // highlight-line
// ...
},
}
```
The following options are available:
| Option | Description |
| ---------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`group`** | Text used as a label for grouping Collection and Global links together in the navigation. |
| **`hidden`** | Set to true or a function, called with the current user, returning true to exclude this Collection from navigation and admin routing. |
| **`hooks`** | Admin-specific hooks for this Collection. [More details](#admin-hooks). |
| **`useAsTitle`** | Specify a top-level field to use for a document title throughout the [Admin Panel](../admin/overview). If no field is defined, the ID of the document is used as the title. |
| **`description`** | Text or React component to display below the Collection label in the List View to give editors more information. |
| **`defaultColumns`** | Array of field names that correspond to which columns to show by default in this Collection's List View. |
| **`hideAPIURL`** | Hides the "API URL" meta field while editing documents within this Collection. |
| **`enableRichTextLink`** | The [Rich Text](../fields/rich-text) field features a `Link` element which allows for users to automatically reference related documents within their rich text. Set to `true` by default. |
| **`enableRichTextRelationship`** | The [Rich Text](../fields/rich-text) field features a `Relationship` element which allows for users to automatically reference related documents within their rich text. Set to `true` by default. |
| **`meta`** | Metadata overrides to apply to the [Admin Panel](../admin/overview). Included properties are `description` and `openGraph`. |
| **`preview`** | Function to generate preview URLs within the [Admin Panel](../admin/overview) that can point to your app. [More details](#preview). |
| **`livePreview`** | Enable real-time editing for instant visual feedback of your front-end application. [More details](../live-preview/overview). |
| **`components`** | Swap in your own React components to be used within this Collection. [More details](../admin/components#collections). |
| **`listSearchableFields`** | Specify which fields should be searched in the List search view. [More details](#list-searchable-fields). |
| **`pagination`** | Set pagination-specific options for this Collection. [More details](#pagination). |
#### Preview
It is possible to display a Preview Button in the Admin Panel within the Edit View. This will allow editors to visit the frontend of your app the corresponds to the document they are actively editing. This way they can preview the latest, potentially unpublished changes.
To configure the Preview Button, set the `admin.preview` property to a function in your Collection Config:
```ts
import { CollectionConfig } from 'payload'
export const Posts: CollectionConfig = {
// ...
admin: {
// highlight-start
preview: (doc, { locale }) => {
if (doc?.slug) {
return `/${doc.slug}?locale=${locale}`
}
return null
},
// highlight-end
},
}
```
The preview function receives two arguments:
| Argument | Description |
| --- | --- |
| **`doc`** | The document being edited |
| **`ctx`** | An object containing `locale` and `token` properties. The `token` is the currently logged-in user's JWT. |
<Banner type="success">
<strong>Reminder:</strong>
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
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.
To configure pagination options, use the `admin.pagination` property in your Collection Config:
```ts
import { CollectionConfig } from 'payload'
export const Posts: CollectionConfig = {
// ...
admin: {
// highlight-start
pagination: {
defaultLimit: 10,
limits: [10, 20, 50],
},
// highlight-end
},
}
```
The following options are available:
| Option | Description |
| -------------- | --------------------------------------------------------------------------------------------------- |
| `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. |
#### 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.
To define which fields should be searched, use the `admin.listSearchableFields` property in your Collection Config:
```ts
import { CollectionConfig } from 'payload'
export const Posts: CollectionConfig = {
// ...
admin: {
// highlight-start
listSearchableFields: ['title', 'slug'],
// highlight-end
},
}
```
<Banner type="warning">
<strong>Tip:</strong>
If you are adding `listSearchableFields`, make sure you index each of these fields so your admin queries can remain performant.
</Banner>
You can customize the way that the [Admin Panel](../admin/overview) behaves on a Collection-by-Collection basis. To learn more, go to the [Collection Admin Options](../admin/collections) documentation.
## TypeScript
You can import Collection types as follows:
You can import types from Payload to help make writing your Collection configs easier and type-safe. There are two main types that represent the Collection Config, `CollectionConfig` and `SanitizeCollectionConfig`.
The `CollectionConfig` type represents a raw Collection Config in its full form, where only the bare minimum properties are marked as required. The `SanitizedCollectionConfig` type represents a Collection Config after it has been fully sanitized. Generally, this is only used internally by Payload.
```ts
import { CollectionConfig } from 'payload'
// This is the type used for incoming Collection configs.
// Only the bare minimum properties are marked as required.
```
```ts
import { SanitizedCollectionConfig } from 'payload'
// This is the type used after an incoming Collection config is fully sanitized.
// Generally, this is only used internally by Payload.
import { CollectionConfig, SanitizedCollectionConfig } from 'payload'
```

View File

@@ -6,7 +6,7 @@ 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
---
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.
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 Document is stored in the [Database](../database/overview) based on the [Fields](../fields/overview) that you define, and automatically generates a [Local API](../local-api/overview), [REST API](../rest-api/overview), and [GraphQL API](../graphql/overview) used to manage your Documents.
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.
@@ -68,12 +68,12 @@ The following options are available:
| Option | Description |
| ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`access`** | Provide Access Control functions to define exactly who should be able to do what with this Global. [More details](../access-control/globals). |
| **`admin`** | The configuration options for the Admin Panel. [More details](#admin-options). |
| **`admin`** | The configuration options for the Admin Panel. [More details](../admin/globals). |
| **`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. |
| **`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. |
| **`fields`** \* | Array of field types that will determine the structure and functionality of the data stored within this Global. [More details](../fields/overview). |
| **`graphQL.name`** | Text used in schema generation. Auto-generated from slug if not defined. |
| **`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. |
@@ -97,84 +97,14 @@ Fields define the schema of the Global. To learn more, go to the [Fields](../fie
### Admin Options
You can customize the way that the [Admin Panel](../admin/overview) behaves on a Global-by-Global basis.
To configure Admin Options for Globals, use the `admin` property in your Global Config:
```ts
import { GlobalConfig } from 'payload'
const MyGlobal: GlobalConfig = {
// ...
admin: { // highlight-line
// ...
},
}
```
The following options are available:
| Option | Description |
| ------------- | --------------------------------------------------------------------------------------------------------------------------------- |
| **`group`** | Text used as a label for grouping Collection and Global links together in the navigation. |
| **`hidden`** | Set to true or a function, called with the current user, returning true to exclude this Global from navigation and admin routing. |
| **`components`** | Swap in your own React components to be used within this Global. [More details](../admin/components#globals). |
| **`preview`** | Function to generate a preview URL within the [Admin Panel](../admin/overview) for this Global that can point to your app. [More details](#preview). |
| **`livePreview`** | Enable real-time editing for instant visual feedback of your front-end application. [More details](../live-preview/overview). |
| **`hideAPIURL`** | Hides the "API URL" meta field while editing documents within this collection. |
| **`meta`** | Metadata overrides to apply to the [Admin Panel](../admin/overview). Included properties are `description` and `openGraph`. |
#### Preview
It is possible to display a Preview Button in the Admin Panel within the Edit View. This will allow editors to visit the frontend of your app the corresponds to the document they are actively editing. This way they can preview the latest, potentially unpublished changes.
To configure the Preview Button, set the `admin.preview` property to a function in your Global Config:
```ts
import { GlobalConfig } from 'payload'
export const MainMenu: GlobalConfig = {
// ...
admin: {
// highlight-start
preview: (doc, { locale }) => {
if (doc?.slug) {
return `/${doc.slug}?locale=${locale}`
}
return null
},
// highlight-end
},
}
```
The preview function receives two arguments:
| Argument | Description |
| --- | --- |
| **`doc`** | The document being edited |
| **`ctx`** | An object containing `locale` and `token` properties. The `token` is the currently logged-in user's JWT. |
<Banner type="success">
<strong>Reminder:</strong>
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>
You can customize the way that the [Admin Panel](../admin/overview) behaves on a Global-by-Global basis. To learn more, go to the [Global Admin Options](../admin/globals) documentation.
## TypeScript
You can import Global types as follows:
You can import types from Payload to help make writing your Global configs easier and type-safe. There are two main types that represent the Global Config, `GlobalConfig` and `SanitizeGlobalConfig`.
The `GlobalConfig` type represents a raw Global Config in its full form, where only the bare minimum properties are marked as required. The `SanitizedGlobalConfig` type represents a Global Config after it has been fully sanitized. Generally, this is only used internally by Payload.
```ts
import { GlobalConfig } from 'payload'
// This is the type used for incoming Global configs.
// Only the bare minimum properties are marked as required.
```
```ts
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.
import { GlobalConfig, SanitizedGlobalConfig } from 'payload'
```

View File

@@ -58,56 +58,56 @@ export default buildConfig({
```
<Banner type="success">
<strong>Reminder:</strong>
<strong>Note:</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:
| Option | Description |
| ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`admin`** | The configuration options for the Admin Panel, including Custom Components, Live Preview, etc. [More details](../admin/overview#admin-options). |
| **`bin`** | Register custom bin scripts with the `payload` bin function. |
| **`editor`** | The Rich Text Editor which will be used by `richText` fields. [More details](../rich-text/overview). |
| **`db`** \* | The Database Adapter which will be used by Payload. [More details](../database/overview). |
| **`serverURL`** | A string used to define the absolute URL of your app including the protocol, for example `https://example.com`. No paths allowed, only protocol, domain and (optionally) port |
| **`collections`** | An array of Collections for Payload to manage. [More details](./collections). |
| **`globals`** | An array of Globals for Payload to manage. [More details](./globals). |
| **`cors`** | Cross-origin resource sharing (CORS) is a mechanism that accept incoming requests from given domains. You can also customize the `Access-Control-Allow-Headers` header. [More](#cors) |
| **`localization`** | Opt-in and control how Payload handles the translation of your content into multiple locales. [More details](./localization). |
| **`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](../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. |
| **`upload`** | Base Payload upload configuration. [More details](../upload/overview#payload-wide-upload-options). |
| **`routes`** | Control the routing structure that Payload binds itself to. Specify `admin`, `api`, `graphQL`, and `graphQLPlayground`. [More details](../admin/overview#root-level-routes). |
| **`email`** | Configure the Email Adapter for Payload to use. [More details](../email/overview). |
| **`debug`** | Enable to expose more detailed error information. |
| **`telemetry`** | Disable Payload telemetry by passing `false`. [More details](#telemetry). |
| **`rateLimit`** | Control IP-based rate limiting for all Payload resources. Used to prevent DDoS attacks, etc. [More details](../production/preventing-abuse#rate-limiting-requests). |
| **`hooks`** | Tap into Payload-wide hooks. [More details](../hooks/overview). |
| **`plugins`** | An array of Payload plugins. [More details](../plugins/overview). |
| **`endpoints`** | An array of custom API endpoints added to the Payload router. [More details](../rest-api/overview#custom-endpoints). |
| **`custom`** | Extension point for adding custom data (e.g. for plugins). |
| **`i18n`** | Internationalization configuration. Pass all i18n languages you'd like the admin UI to support. Defaults to English-only. [More details](./i18n). |
| **`secret`** \* | A secure, unguessable string that Payload will use for any encryption workflows - for example, password salt / hashing. |
| **`sharp`** | If you would like Payload to offer cropping, focal point selection, and automatic media resizing, install and pass the Sharp module to the config here. |
| **`typescript`** | Configure TypeScript settings here. [More details](#typescript). |
| Option | Description |
|----------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **`admin`** | The configuration options for the Admin Panel, including Custom Components, Live Preview, etc. [More details](../admin/overview#admin-options). |
| **`bin`** | Register custom bin scripts for Payload to execute. |
| **`editor`** | The Rich Text Editor which will be used by `richText` fields. [More details](../rich-text/overview). |
| **`db`** \* | The Database Adapter which will be used by Payload. [More details](../database/overview). |
| **`serverURL`** | A string used to define the absolute URL of your app. This includes the protocol, for example `https://example.com`. No paths allowed, only protocol, domain and (optionally) port. |
| **`collections`** | An array of Collections for Payload to manage. [More details](./collections). |
| **`globals`** | An array of Globals for Payload to manage. [More details](./globals). |
| **`cors`** | Cross-origin resource sharing (CORS) is a mechanism that accept incoming requests from given domains. You can also customize the `Access-Control-Allow-Headers` header. [More details](#cors). |
| **`localization`** | Opt-in to translate your content into multiple locales. [More details](./localization). |
| **`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 to accept cookies from. [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](../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`. [More details](../queries/depth). |
| **`indexSortableFields`** | Automatically index all sortable top-level fields in the database to improve sort performance and add database compatibility for Azure Cosmos and similar. |
| **`upload`** | Base Payload upload configuration. [More details](../upload/overview#payload-wide-upload-options). |
| **`routes`** | Control the routing structure that Payload binds itself to. [More details](../admin/overview#root-level-routes). |
| **`email`** | Configure the Email Adapter for Payload to use. [More details](../email/overview). |
| **`debug`** | Enable to expose more detailed error information. |
| **`telemetry`** | Disable Payload telemetry by passing `false`. [More details](#telemetry). |
| **`rateLimit`** | Control IP-based rate limiting for all Payload resources. Used to prevent DDoS attacks, etc. [More details](../production/preventing-abuse#rate-limiting-requests). |
| **`hooks`** | An array of Root Hooks. [More details](../hooks/overview). |
| **`plugins`** | An array of Plugins. [More details](../plugins/overview). |
| **`endpoints`** | An array of Custom Endpoints added to the Payload router. [More details](../rest-api/overview#custom-endpoints). |
| **`custom`** | Extension point for adding custom data (e.g. for plugins). |
| **`i18n`** | Internationalization configuration. Pass all i18n languages you'd like the admin UI to support. Defaults to English-only. [More details](./i18n). |
| **`secret`** \* | A secure, unguessable string that Payload will use for any encryption workflows - for example, password salt / hashing. |
| **`sharp`** | If you would like Payload to offer cropping, focal point selection, and automatic media resizing, install and pass the Sharp module to the config here. |
| **`typescript`** | Configure TypeScript settings here. [More details](#typescript). |
_\* An asterisk denotes that a property is required._
<Banner type="warning">
<strong>Reminder:</strong>
<strong>Note:</strong>
Some properties are removed from the client-side bundle. [More details](../admin/components#accessing-the-payload-config).
</Banner>
### TypeScript
### Typescript Config
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.
Payload exposes a variety of TypeScript settings that you can leverage. These settings are used to auto-generate TypeScript interfaces for your [Collections](../configuration/collections) and [Globals](../configuration/globals), and to ensure that Payload uses your [Generated Types](../typescript/overview) for all [Local API](../local-api/overview) methods.
To customize the TypeScript settings, use the `typescript` property in your Payload Config:
@@ -130,39 +130,59 @@ The following options are available:
| **`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`.
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:
In development mode, if the configuration file is not found at the root, Payload will attempt to read your `tsconfig.json`, and search in the directory specified in `compilerOptions.rootDir` (typically "src").
1. The root current working directory
1. The `compilerOptions` in your `tsconfig`*
1. The `dist` directory*
In production mode, Payload will first attempt to find the config file in the output directory specified in `compilerOptions.outDir` of your `tsconfig.json`, then fallback to the source directory (`compilerOptions.rootDir`), and finally will check the 'dist' directory.
_\* Config location detection is different between development and production environments. See below for more details._
Please ensure your `tsconfig.json` is properly configured if you want Payload to accurately auto-detect your configuration file location. If `tsconfig.json` does not exist or doesn't specify `rootDir` or `outDir`, Payload will default to the current working directory.
<Banner type="warning">
<strong>Important:</strong>
Ensure your `tsconfig.json` is properly configured for Payload to auto-detect your config location. If if does not exist, or does not specify the proper `compilerOptions`, Payload will default to the current working directory.
</Banner>
**Development Mode**
In development mode, if the configuration file is not found at the root, Payload will attempt to read your `tsconfig.json`, and attempt to find the config file specified in the `rootDir`:
```json
{
// ...
// highlight-start
"compilerOptions": {
"rootDir": "src"
}
// highlight-end
}
```
**Production Mode**
In production mode, Payload will first attempt to find the config file in the `outDir` of your `tsconfig.json`, and if not found, will fallback to the `rootDor` directory:
```json
{
// ...
// highlight-start
"compilerOptions": {
"outDir": "dist",
"rootDir": "src"
}
// highlight-end
}
```
If none was in either location, Payload will finally check the `dist` directory.
### Customizing the Config Location
In addition to the above automated detection, you can specify your own location for the Payload Config. This is done by using the environment variable `PAYLOAD_CONFIG_PATH`. The path you provide via this environment variable can either be absolute or relative to your current working directory. This can be useful in situations where your Payload Config is not in a standard location, or you wish to switch between multiple configurations.
In addition to the above automated detection, you can specify your own location for the Payload Config. This can be useful in situations where your config is not in a standard location, or you wish to switch between multiple configurations. To do this, Payload exposes an [Environment Variable](..environment-variables) to bypass all automatic config detection.
**Example in package.json:**
To use a custom config location, set the `PAYLOAD_CONFIG_PATH` environment variable:
```json
{
@@ -172,7 +192,10 @@ 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.
<Banner type="info">
<strong>Tip:</strong>
`PAYLOAD_CONFIG_PATH` can be either an absolute path, or path relative to your current working directory.
</Banner>
## Telemetry
@@ -186,8 +209,8 @@ Cross-origin resource sharing (CORS) can be configured with either a whitelist a
| Option | Description |
| --------- | --------------------------------------------------------------------------------------------------------------------------------------- |
| `origins` | Either a whitelist array of URLS to allow CORS requests from, or a wildcard string (`'*'`) to accept incoming requests from any domain. |
| `headers | A list of allowed headers that will be appended in `Access-Control-Allow-Headers`. |
| **`origins`** | Either a whitelist array of URLS to allow CORS requests from, or a wildcard string (`'*'`) to accept incoming requests from any domain. |
| **`headers`** | A list of allowed headers that will be appended in `Access-Control-Allow-Headers`. |
Here's an example showing how to allow incoming requests from any domain:
@@ -196,7 +219,7 @@ import { buildConfig } from 'payload/config'
export default buildConfig({
// ...
cors: '*'
cors: '*' // highlight-line
})
```
@@ -207,9 +230,21 @@ import { buildConfig } from 'payload/config'
export default buildConfig({
// ...
// highlight-start
cors: {
origins: ['http://localhost:3000']
headers: ['x-custom-header']
}
// highlight-end
})
```
## TypeScript
You can import types from Payload to help make writing your config easier and type-safe. There are two main types that represent the Payload Config, `Config` and `SanitizedConfig`.
The `Config` type represents a raw Payload Config in its full form. Only the bare minimum properties are marked as required. The `SanitizedConfig` type represents a Payload Config after it has been fully sanitized. Generally, this is only used internally by Payload.
```ts
import { Config, SanitizedConfig } from 'payload'
```

View File

@@ -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 [auth-related emails](../authentication/email) for things like password resets, new user verification, and any other email sending needs you may have.
## Configuration

View File

@@ -34,7 +34,7 @@ keywords: array, fields, config, configuration, documentation, Content Managemen
| **`validate`** | Provide a custom validation function that will be executed on both the [Admin Panel](../admin/overview) and the backend. [More](/docs/fields/overview#validation) |
| **`minRows`** | A number for the fewest allowed items during validation when a value is present. |
| **`maxRows`** | A number for the most allowed items during validation when a value is present. |
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/config), include its data in the user JWT. |
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/overview), include its data in the user JWT. |
| **`hooks`** | Provide Field Hooks to control logic for this field. [More details](../hooks/fields). |
| **`access`** | Provide Field Access Control to denote what users can see and do with this field's data. [More details](../access-control/fields). |
| **`hidden`** | Restrict this field's visibility from all APIs entirely. Will still be saved to the database, but will not appear in any API or the Admin Panel. |

View File

@@ -36,7 +36,7 @@ keywords: blocks, fields, config, configuration, documentation, Content Manageme
| **`validate`** | Provide a custom validation function that will be executed on both the Admin Panel and the backend. [More](/docs/fields/overview#validation) |
| **`minRows`** | A number for the fewest allowed items during validation when a value is present. |
| **`maxRows`** | A number for the most allowed items during validation when a value is present. |
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/config), include its data in the user JWT. |
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/overview), include its data in the user JWT. |
| **`hooks`** | Provide Field Hooks to control logic for this field. [More details](../hooks/fields). |
| **`access`** | Provide Field Access Control to denote what users can see and do with this field's data. [More details](../access-control/fields). |
| **`hidden`** | Restrict this field's visibility from all APIs entirely. Will still be saved to the database, but will not appear in any API response or the Admin Panel. |

View File

@@ -23,7 +23,7 @@ keywords: checkbox, fields, config, configuration, documentation, Content Manage
| **`label`** | Text used as a field label in the Admin Panel or an object with keys for each language. |
| **`validate`** | Provide a custom validation function that will be executed on both the Admin Panel and the backend. [More](/docs/fields/overview#validation) |
| **`index`** | Build an [index](/docs/database/overview) for this field to produce faster queries. Set this field to `true` if your users will perform queries on this field's data often. |
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/config), include its data in the user JWT. |
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/overview), include its data in the user JWT. |
| **`hooks`** | Provide Field Hooks to control logic for this field. [More details](../hooks/fields). |
| **`access`** | Provide Field Access Control to denote what users can see and do with this field's data. [More details](../access-control/fields). |
| **`hidden`** | Restrict this field's visibility from all APIs entirely. Will still be saved to the database, but will not appear in any API or the Admin Panel. |

View File

@@ -32,7 +32,7 @@ This field uses the `monaco-react` editor syntax highlighting.
| **`minLength`** | Used by the default validation function to ensure values are of a minimum character length. |
| **`maxLength`** | Used by the default validation function to ensure values are of a maximum character length. |
| **`validate`** | Provide a custom validation function that will be executed on both the Admin Panel and the backend. [More](/docs/fields/overview#validation) |
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/config), include its data in the user JWT. |
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/overview), include its data in the user JWT. |
| **`hooks`** | Provide Field Hooks to control logic for this field. [More details](../hooks/fields). |
| **`access`** | Provide Field Access Control to denote what users can see and do with this field's data. [More details](../access-control/fields). |
| **`hidden`** | Restrict this field's visibility from all APIs entirely. Will still be saved to the database, but will not appear in any API or the Admin Panel. |

View File

@@ -28,7 +28,7 @@ This field uses [`react-datepicker`](https://www.npmjs.com/package/react-datepic
| **`label`** | Text used as a field label in the Admin Panel or an object with keys for each language. |
| **`index`** | Build an [index](/docs/database/overview) for this field to produce faster queries. Set this field to `true` if your users will perform queries on this field's data often. |
| **`validate`** | Provide a custom validation function that will be executed on both the Admin Panel and the backend. [More](/docs/fields/overview#validation) |
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/config), include its data in the user JWT. |
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/overview), include its data in the user JWT. |
| **`hooks`** | Provide Field Hooks to control logic for this field. [More details](../hooks/fields). |
| **`access`** | Provide Field Access Control to denote what users can see and do with this field's data. [More details](../access-control/fields). |
| **`hidden`** | Restrict this field's visibility from all APIs entirely. Will still be saved to the database, but will not appear in any API or the Admin Panel. |

View File

@@ -24,7 +24,7 @@ keywords: email, fields, config, configuration, documentation, Content Managemen
| **`unique`** | Enforce that each entry in the Collection has a unique value for this field. |
| **`index`** | Build an [index](/docs/database/overview) for this field to produce faster queries. Set this field to `true` if your users will perform queries on this field's data often. |
| **`validate`** | Provide a custom validation function that will be executed on both the Admin Panel and the backend. [More](/docs/fields/overview#validation) |
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/config), include its data in the user JWT. |
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/overview), include its data in the user JWT. |
| **`hooks`** | Provide Field Hooks to control logic for this field. [More details](../hooks/fields). |
| **`access`** | Provide Field Access Control to denote what users can see and do with this field's data. [More details](../access-control/fields). |
| **`hidden`** | Restrict this field's visibility from all APIs entirely. Will still be saved to the database, but will not appear in any API or the Admin Panel. |

View File

@@ -26,7 +26,7 @@ keywords: group, fields, config, configuration, documentation, Content Managemen
| **`fields`** \* | Array of field types to nest within this Group. |
| **`label`** | Used as a heading in the Admin Panel and to name the generated GraphQL type. |
| **`validate`** | Provide a custom validation function that will be executed on both the Admin Panel and the backend. [More](/docs/fields/overview#validation) |
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/config), include its data in the user JWT. |
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/overview), include its data in the user JWT. |
| **`hooks`** | Provide Field Hooks to control logic for this field. [More details](../hooks/fields). |
| **`access`** | Provide Field Access Control to denote what users can see and do with this field's data. [More details](../access-control/fields). |
| **`hidden`** | Restrict this field's visibility from all APIs entirely. Will still be saved to the database, but will not appear in any API or the Admin Panel. |

View File

@@ -31,7 +31,7 @@ This field uses the `monaco-react` editor syntax highlighting.
| **`index`** | Build an [index](/docs/database/overview) for this field to produce faster queries. Set this field to `true` if your users will perform queries on this field's data often. |
| **`validate`** | Provide a custom validation function that will be executed on both the Admin Panel and the backend. [More](/docs/fields/overview#validation) |
| **`jsonSchema`** | Provide a JSON schema that will be used for validation. [JSON schemas](https://json-schema.org/learn/getting-started-step-by-step) |
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/config), include its data in the user JWT. |
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/overview), include its data in the user JWT. |
| **`hooks`** | Provide Field Hooks to control logic for this field. [More details](../hooks/fields). |
| **`access`** | Provide Field Access Control to denote what users can see and do with this field's data. [More details](../access-control/fields). |
| **`hidden`** | Restrict this field's visibility from all APIs entirely. Will still be saved to the database, but will not appear in any API or the Admin Panel. |

View File

@@ -32,7 +32,7 @@ keywords: number, fields, config, configuration, documentation, Content Manageme
| **`unique`** | Enforce that each entry in the Collection has a unique value for this field. |
| **`index`** | Build an [index](/docs/database/overview) for this field to produce faster queries. Set this field to `true` if your users will perform queries on this field's data often. |
| **`validate`** | Provide a custom validation function that will be executed on both the Admin Panel and the backend. [More](/docs/fields/overview#validation) |
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/config), include its data in the user JWT. |
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/overview), include its data in the user JWT. |
| **`hooks`** | Provide Field Hooks to control logic for this field. [More details](../hooks/fields). |
| **`access`** | Provide Field Access Control to denote what users can see and do with this field's data. [More details](../access-control/fields). |
| **`hidden`** | Restrict this field's visibility from all APIs entirely. Will still be saved to the database, but will not appear in any API or the Admin Panel. |

View File

@@ -375,6 +375,8 @@ export const MyCollection: CollectionConfig = {
<Banner type="warning">
<strong>Reminder:</strong>
The Custom ID Fields can only be of type [`Number`](./number) or [`Text`](./text).
Custom ID fields with type `text` must not contain `/` or `.` characters.
</Banner>
## TypeScript

View File

@@ -34,7 +34,7 @@ The data structure in the database matches the GeoJSON structure to represent po
| **`unique`** | Enforce that each entry in the Collection has a unique value for this field. |
| **`index`** | Build an [index](/docs/database/overview) for this field to produce faster queries. To support location queries, point index defaults to `2dsphere`, to disable the index set to `false`. |
| **`validate`** | Provide a custom validation function that will be executed on both the Admin Panel and the backend. [More](/docs/fields/overview#validation) |
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/config), include its data in the user JWT. |
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/overview), include its data in the user JWT. |
| **`hooks`** | Provide Field Hooks to control logic for this field. [More details](../hooks/fields). |
| **`access`** | Provide Field Access Control to denote what users can see and do with this field's data. [More details](../access-control/fields). |
| **`hidden`** | Restrict this field's visibility from all APIs entirely. Will still be saved to the database, but will not appear in any API or the Admin Panel. |

View File

@@ -27,7 +27,7 @@ keywords: radio, fields, config, configuration, documentation, Content Managemen
| **`label`** | Text used as a field label in the Admin Panel or an object with keys for each language. |
| **`validate`** | Provide a custom validation function that will be executed on both the Admin Panel and the backend. [More](/docs/fields/overview#validation) |
| **`index`** | Build an [index](/docs/database/overview) for this field to produce faster queries. Set this field to `true` if your users will perform queries on this field's data often. |
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/config), include its data in the user JWT. |
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/overview), include its data in the user JWT. |
| **`hooks`** | Provide Field Hooks to control logic for this field. [More details](../hooks/fields). |
| **`access`** | Provide Field Access Control to denote what users can see and do with this field's data. [More details](../access-control/fields). |
| **`hidden`** | Restrict this field's visibility from all APIs entirely. Will still be saved to the database, but will not appear in any API or the Admin Panel. |

View File

@@ -39,7 +39,7 @@ keywords: relationship, fields, config, configuration, documentation, Content Ma
| **`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) |
| **`index`** | Build an [index](/docs/database/overview) for this field to produce faster queries. Set this field to `true` if your users will perform queries on this field's data often. |
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/config), include its data in the user JWT. |
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/overview), include its data in the user JWT. |
| **`hooks`** | Provide Field Hooks to control logic for this field. [More details](../hooks/fields). |
| **`access`** | Provide Field Access Control to denote what users can see and do with this field's data. [More details](../access-control/fields). |
| **`hidden`** | Restrict this field's visibility from all APIs entirely. Will still be saved to the database, but will not appear in any API or the Admin Panel. |

View File

@@ -46,7 +46,7 @@ Right now, Payload is officially supporting two rich text editors:
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
| **`label`** | Text used as a field label in the Admin Panel or an object with keys for each language. |
| **`validate`** | Provide a custom validation function that will be executed on both the Admin Panel and the backend. [More](/docs/fields/overview#validation) |
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/config), include its data in the user JWT. |
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/overview), include its data in the user JWT. |
| **`hooks`** | Provide Field Hooks to control logic for this field. [More details](../hooks/fields). |
| **`access`** | Provide Field Access Control to denote what users can see and do with this field's data. [More details](../access-control/fields). |
| **`hidden`** | Restrict this field's visibility from all APIs entirely. Will still be saved to the database, but will not appear in any API or the Admin Panel. |

View File

@@ -29,7 +29,7 @@ keywords: select, multi-select, fields, config, configuration, documentation, Co
| **`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) |
| **`index`** | Build an [index](/docs/database/overview) for this field to produce faster queries. Set this field to `true` if your users will perform queries on this field's data often. |
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/config), include its data in the user JWT. |
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/overview), include its data in the user JWT. |
| **`hooks`** | Provide Field Hooks to control logic for this field. [More details](../hooks/fields). |
| **`access`** | Provide Field Access Control to denote what users can see and do with this field's data. [More details](../access-control/fields). |
| **`hidden`** | Restrict this field's visibility from all APIs entirely. Will still be saved to the database, but will not appear in any API or the Admin Panel. |

View File

@@ -29,7 +29,7 @@ keywords: text, fields, config, configuration, documentation, Content Management
| **`maxLength`** | Used by the default validation function to ensure values are of a maximum character length. |
| **`validate`** | Provide a custom validation function that will be executed on both the Admin Panel and the backend. [More](/docs/fields/overview#validation) |
| **`index`** | Build an [index](/docs/database/overview) for this field to produce faster queries. Set this field to `true` if your users will perform queries on this field's data often. |
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/config), include its data in the user JWT. |
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/overview), include its data in the user JWT. |
| **`hooks`** | Provide Field Hooks to control logic for this field. [More details](../hooks/fields). |
| **`access`** | Provide Field Access Control to denote what users can see and do with this field's data. [More details](../access-control/fields). |
| **`hidden`** | Restrict this field's visibility from all APIs entirely. Will still be saved to the database, but will not appear in any API or the Admin Panel. |

View File

@@ -29,7 +29,7 @@ keywords: textarea, fields, config, configuration, documentation, Content Manage
| **`maxLength`** | Used by the default validation function to ensure values are of a maximum character length. |
| **`validate`** | Provide a custom validation function that will be executed on both the Admin Panel and the backend. [More](/docs/fields/overview#validation) |
| **`index`** | Build an [index](/docs/database/overview) for this field to produce faster queries. Set this field to `true` if your users will perform queries on this field's data often. |
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/config), include its data in the user JWT. |
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/overview), include its data in the user JWT. |
| **`hooks`** | Provide Field Hooks to control logic for this field. [More details](../hooks/fields). |
| **`access`** | Provide Field Access Control to denote what users can see and do with this field's data. [More details](../access-control/fields). |
| **`hidden`** | Restrict this field's visibility from all APIs entirely. Will still be saved to the database, but will not appear in any API or the Admin Panel. |

View File

@@ -44,7 +44,7 @@ keywords: upload, images media, fields, config, configuration, documentation, Co
| **`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) |
| **`index`** | Build an [index](/docs/database/overview) for this field to produce faster queries. Set this field to `true` if your users will perform queries on this field's data often. |
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/config), include its data in the user JWT. |
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/overview), include its data in the user JWT. |
| **`hooks`** | Provide Field Hooks to control logic for this field. [More details](../hooks/fields). |
| **`access`** | Provide Field Access Control to denote what users can see and do with this field's data. [More details](../access-control/fields). |
| **`hidden`** | Restrict this field's visibility from all APIs entirely. Will still be saved to the database, but will not appear in any API or the Admin Panel. |

View File

@@ -18,11 +18,11 @@ Payload is database agnostic, meaning you can use any type of database behind Pa
## Collections
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).
A Collection is a group of records, called Documents, that all share a common schema. Each Collection is stored in the [Database](../database/overview) based on the [Fields](../fields/overview) that you define. [More details](../configuration/collections).
## Globals
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).
Globals are in many ways similar to [Collections](../configuration/collections), except they correspond to only a single Document. Each Global is stored in the [Database](../database/overview) based on the [Fields](../fields/overview) that you define. [More details](../configuration/globals).
## Fields
@@ -30,23 +30,23 @@ Fields are the building blocks of Payload. They define the schema of the Documen
## Hooks
Hooks allow you to execute your own logic during specific events of the Document lifecycle, such as read or update. [More details](../hooks/overview).
Hooks allow you to execute your own side effects during specific events of the Document lifecycle, such as before read, after create, etc. [More details](../hooks/overview).
## Authentication
Payload provides a secure, portable way to manage user accounts out of the box. Payload Authentication is designed to be used in both the Admin Panel, all well as your own external applications. [More details](../authentication/overview).
## Access Control
Access Control determines what a user can and cannot do with any given Document. [More details](../access-control/overview).
Access Control determines what a user can and cannot do with any given Document, such as read, update, etc., as well as what they can and cannot see within the Admin Panel. [More details](../access-control/overview).
## Admin Panel
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).
## 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:
Everything Payload does (create, read, update, delete, login, logout, etc.) is exposed to you via three APIs:
- [Local API](#local-api) - Extremely fast, direct-to-database access
- [REST API](#rest-api) - Standard HTTP endpoints for querying and mutating data
@@ -59,11 +59,11 @@ Everything Payload does (create, read, update, delete, login, logout, etc) is ex
### 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.
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 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:
Here's a quick example of a React Server Component fetching data using the Local API:
```tsx
import React from 'react'
@@ -100,9 +100,9 @@ const MyServerComponent: React.FC = () => {
### REST API
By default, the Payload [REST API](../rest-api/overview) will be mounted automatically for you at the `/api` path of your app.
By default, the Payload [REST API](../rest-api/overview) is mounted automatically for you at the `/api` path of your app.
For example, if you have a [Collection](../configuration/collections) called `pages`:
For example, if you have a Collection called `pages`:
```ts
fetch('https://localhost:3000/api/pages') // highlight-line
@@ -116,27 +116,17 @@ fetch('https://localhost:3000/api/pages') // highlight-line
### GraphQL API
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`.
You'll also find a full GraphQL Playground which can be accessible via `http://localhost:3000/api/graphql-playground`.
Payload automatically exposes GraphQL queries and mutations through a dedicated [GraphQL API](../graphql/overview). By default, the GraphQL route handler is mounted at the `/api/graphql` path of your app. You'll also find a full GraphQL Playground which can be accessible at the `/api/graphql-playground` path of your app.
You can use any GraphQL client with Payload's GraphQL endpoint. Here are a few packages:
- [`graphql-request`](https://www.npmjs.com/package/graphql-request) - a very lightweight GraphQL client
- [`@apollo/client`](https://www.apollographql.com/docs/react/api/core/ApolloClient/) - an industry-standard GraphQL client with lots of nice features
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.
<Banner type="info">
For more information about the GraphQL API, [click here](../graphql/overview).
</Banner>
### Depth
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).
## Package Structure
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.
@@ -180,4 +170,7 @@ You can choose which Database Adapter you'd like to use for your project, and no
Payload's Rich Text functionality is abstracted into separate packages and if you want to enable Rich Text in your project, you'll need to install one of these packages. We recommend Lexical for all new projects, and this is where Payload will focus its efforts on from this point, but Slate is still supported if you have already built with it.
Rich Text is entirely optional and you may not need it for your project.
<Banner type="info">
<strong>Note:</strong>
Rich Text is entirely optional and you may not need it for your project.
</Banner>

View File

@@ -63,23 +63,13 @@ To install a Database Adapter, you can run **one** of the following commands:
```
<Banner type="success">
<strong>Reminder:</strong>
<strong>Note:</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 Admin Panel UI.
You can copy the Payload `/app` folder files from the Payload blank template on GitHub:
```
https://github.com/payloadcms/payload/tree/beta/templates/blank-3.0/src/app/(payload)
```
Once you have the required Payload files in place in your `/app` folder, you should have something like this:
Payload installs directly in your Next.js `/app` folder, and you'll need to place some files into that folder for Payload to run. You can copy these files from the [Blank Template](https://github.com/payloadcms/payload/tree/beta/templates/blank-3.0/src/app/(payload)) on GitHub. Once you have the required Payload files in place in your `/app` folder, you should have something like this:
```plaintext
app/
@@ -93,6 +83,8 @@ app/
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>
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.
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).
#### 3. Add the Payload Plugin to your Next.js config

View File

@@ -15,7 +15,7 @@ keywords: documentation, getting started, guide, Content Management System, cms,
- 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
- Instant REST, GraphQL, and straight-to-DB Node.js APIs
- Authentication which can be used in your own apps
- A deeply customizable access control pattern
- File storage and image management tools like cropping / focal point selection
@@ -30,12 +30,14 @@ No matter what you're building, Payload will give you backend superpowers. It ca
It's fully open source with an MIT license and you can self-host anywhere that you can run a Node app. You can also deploy serverless to hosts like Vercel, right inside your existing Next.js app folder.
### Code-first and version controlled
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.
### Fully extensible
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.
## 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.

View File

@@ -21,28 +21,10 @@ export const CollectionWithHooks: CollectionConfig = {
}
```
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)
<Banner type="info">
<strong>Tip:</strong>
You can also set hooks on the field-level to isolate hook logic to specific fields. [More details](./fields).
</Banner>
## Config Options
@@ -89,9 +71,9 @@ Available Collection operations include `create`, `read`, `update`, `delete`, `l
import type { CollectionBeforeOperationHook } from 'payload'
const beforeOperationHook: CollectionBeforeOperationHook = async ({
args, // original arguments passed into the operation
operation, // name of the operation
req, // full Request object
args,
operation,
req,
}) => {
return args // return modified operation arguments as necessary
}

View File

@@ -8,7 +8,7 @@ keywords: hooks, context, payload context, payloadcontext, data, extra data, sha
The `context` object is used to share data across different Hooks. This persists throughout the entire lifecycle of a request and is available within every Hook. By setting properties to `req.context`, you can effectively logic across multiple Hooks.
## When to use Context
## When To Use Context
Context gives you a way forward on otherwise difficult problems such as:
@@ -17,11 +17,11 @@ Context gives you a way forward on otherwise difficult problems such as:
3. **Passing data to local API**: Setting values on the `req.context` and pass it to `payload.create()` you can provide additional data to hooks without adding extraneous fields.
4. **Passing data between hooks and middleware or custom endpoints**: Hooks could set context across multiple collections and then be used in a final `postMiddleware`.
## How to Use Context
## How To Use Context
Let's see examples on how context can be used in the first two scenarios mentioned above:
### Passing data between hooks
### Passing Data Between Hooks
To pass data between hooks, you can assign values to context in an earlier hook in the lifecycle of a request and expect it the context in a later hook.
@@ -58,7 +58,7 @@ const Customer: CollectionConfig = {
}
```
### Preventing infinite loops
### Preventing Infinite Loops
Let's say you have an `afterChange` hook, and you want to do a calculation inside the hook (as the document ID needed for the calculation is available in the `afterChange` hook, but not in the `beforeChange` hook). Once that's done, you want to update the document with the result of the calculation.

View File

@@ -21,14 +21,6 @@ export const FieldWithHooks: Field = {
}
```
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.

View File

@@ -21,13 +21,10 @@ export const GlobalWithHooks: GlobalConfig = {
}
```
The following Global Hooks are available:
- [`beforeValidate`](#beforevalidate)
- [`beforeChange`](#beforechange)
- [`afterChange`](#afterchange)
- [`beforeRead`](#beforeread)
- [`afterRead`](#afterread)
<Banner type="info">
<strong>Tip:</strong>
You can also set hooks on the field-level to isolate hook logic to specific fields. [More details](./fields).
</Banner>
## Config Options
@@ -58,11 +55,11 @@ Runs before the `update` operation. This hook allows you to add or format data b
import type { GlobalBeforeValidateHook } from 'payload'
const beforeValidateHook: GlobalBeforeValidateHook = async ({
data, // incoming data to update or create with
req, // full Request object
originalDoc, // original document
data,
req,
originalDoc,
}) => {
return data // Return data to update the document with
return data
}
```
@@ -84,11 +81,11 @@ Immediately following validation, `beforeChange` hooks will run within the `upda
import type { GlobalBeforeChangeHook } from 'payload'
const beforeChangeHook: GlobalBeforeChangeHook = async ({
data, // incoming data to update or create with
req, // full Request object
originalDoc, // original document
data,
req,
originalDoc,
}) => {
return data // Return data to update the document with
return data
}
```
@@ -110,9 +107,9 @@ After a global is updated, the `afterChange` hook runs. Use this hook to purge c
import type { GlobalAfterChangeHook } from 'payload'
const afterChangeHook: GlobalAfterChangeHook = async ({
doc, // full document data
previousDoc, // document data before updating the collection
req, // full Request object
doc,
previousDoc,
req,
}) => {
return data
}
@@ -136,8 +133,8 @@ Runs before `findOne` global operation is transformed for output by `afterRead`.
import type { GlobalBeforeReadHook } from 'payload'
const beforeReadHook: GlobalBeforeReadHook = async ({
doc, // full document data
req, // full Request object
doc,
req,
}) => {...}
```
@@ -158,9 +155,9 @@ Runs as the last step before a global is returned. Flattens locales, hides prote
import type { GlobalAfterReadHook } from 'payload'
const afterReadHook: GlobalAfterReadHook = async ({
doc, // full document data
req, // full Request object
findMany, // boolean to denote if this hook is running against finding one, or finding many (useful in versions)
doc,
req,
findMany,
}) => {...}
```

View File

@@ -2,13 +2,13 @@
title: Hooks Overview
label: Overview
order: 10
desc: Hooks allow you to add your own logic to Payload, including integrating with third-party APIs, adding auto-generated data, or modifing Payload's base functionality.
desc: Hooks allow you to add your own logic to Payload, including integrating with third-party APIs, adding auto-generated data, or modifying Payload's base functionality.
keywords: hooks, overview, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
Hooks allow you to execute your own side effects 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 logic, third-party integrations, etc. during precise moments within the data lifecycle.
Hooks allow you to execute your own side effects during specific events of the Document lifecycle. They allow you to do things like mutate data, perform business logic, integrate with third-parties, or anything else, all during precise moments within your application.
There are many use cases for Hooks, including:
With Hooks, you can transform Payload from a traditional CMS into a fully-fledged application framework. There are many use cases for Hooks, including:
- Modify data before it is read or updated
- Encrypt and decrypt sensitive data
@@ -18,17 +18,67 @@ There are many use cases for Hooks, including:
- Send emails when contact forms are submitted
- Track data ownership or changes over time
There are three main types of Hooks in Payload:
There are four main types of Hooks in Payload:
- [Root Hooks](#root-hooks)
- [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).
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>
## Root Hooks
Root Hooks are not associated with any specific Collection, Global, or Field. They are useful for globally-oriented side effects, such as when an error occurs at the application level.
To add Root Hooks, use the `hooks` property in your [Payload Config](/docs/configuration/config):
```ts
import { buildConfig } from 'payload'
export default buildConfig({
// ...
// highlight-start
hooks: {
afterError: () => {...}
},
// highlight-end
})
```
The following options are available:
| Option | Description |
|--------------|-----------------------------------------------------------------------------------------------|
| **`afterError`** | Runs after an error occurs in the Payload application. |
### afterError
The `afterError` Hook is triggered when an error occurs in the Payload application. This can be useful for logging errors to a third-party service, sending an email to the development team, logging the error to Sentry or DataDog, etc.
```ts
import { buildConfig } from 'payload'
export default buildConfig({
// ...
hooks: {
afterError: async ({ error }) => {
// Do something
}
},
})
```
The following arguments are provided to the `afterError` Hook:
| Argument | Description |
|----------|-----------------------------------------------------------------------------------------------|
| **`error`** | The error that occurred. |
| **`context`** | Custom context passed between Hooks. [More details](./context). |
## Async vs. Synchronous
All Hooks can be written as either synchronous or asynchronous functions. Choosing the right type depends on your use case, but switching between the two is as simple as adding or removing the `async` keyword.

View File

@@ -8,7 +8,7 @@ keywords: live preview, preview, live, iframe, iframe preview, visual editing, d
With Live Preview you can render your front-end application directly within the [Admin Panel](../admin/overview). As you type, your changes take effect in real-time. No need to save a draft or publish your changes. This works in both [Server-side](./server) as well as [Client-side](./client) environments.
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.
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.
To add Live Preview, use the `admin.livePreview` property in your [Payload Config](../configuration/overview):
@@ -28,12 +28,16 @@ const config = buildConfig({
}
})
```
<Banner type="warning">
<strong>Reminder:</strong>
Alternatively, you can define the <code>admin.livePreview</code> property on individual [Collection Admin Configs](../admin/collections) and [Global Admin Configs](../admin/globals). Settings defined here will be merged into the top-level as overrides.
</Banner>
{/* 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.
Setting up Live Preview is easy. This can be done either globally through the [Root Admin Config](../admin/overview), or on individual [Collection Admin Configs](../admin/collections) and [Global Admin Configs](../admin/globals). 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:
@@ -46,11 +50,6 @@ The following options are available:
_\* An asterisk denotes that a property is required._
<Banner type="warning">
<strong>Reminder:</strong>
Alternatively, you can define the <code>admin.livePreview</code> property on individual [Collection](../configuration/collections) and [Global](../configuration/globals) configs. Settings defined here will be merged into the top-level as overrides.
</Banner>
### URL
The `url` property is a string that points to your front-end application. This value is used as the `src` attribute of the iframe rendering your front-end. Once loaded, the Admin Panel will communicate directly with your app through `window.postMessage` events.
@@ -74,7 +73,7 @@ const config = buildConfig({
#### Dynamic URLs
You can also pass a function in order to dynamically format URLs. This is useful for multi-tenant applications, localization, or any other scenario where the URL needs to be generated based on the document being edited.
You can also pass a function in order to dynamically format URLs. This is useful for multi-tenant applications, localization, or any other scenario where the URL needs to be generated based on the Document being edited.
To set dynamic URLs, set the `admin.livePreview.url` property in your [Payload Config](../configuration/overview) to a function:
@@ -105,8 +104,8 @@ The following arguments are provided to the `url` function:
| Path | Description |
| ------------------ | ----------------------------------------------------------------------------------------------------------------- |
| **`data`** | The data of the document being edited. This includes changes that have not yet been saved. |
| **`documentInfo`** | Information about the document being edited like collection slug. [More details](../admin/hooks#usedocumentinfo). |
| **`data`** | The data of the Document being edited. This includes changes that have not yet been saved. |
| **`documentInfo`** | Information about the Document being edited like collection slug. [More details](../admin/hooks#usedocumentinfo). |
| **`locale`** | The locale currently being edited (if applicable). [More details](../configuration/localization). |
### Breakpoints

View File

@@ -180,7 +180,6 @@ import {
useFormInitializing,
useFormModified,
useFormProcessing,
useFormQueryParams,
useFormSubmitted,
useHotkey,
useIntersect,
@@ -221,7 +220,6 @@ import {
EntityVisibilityProvider,
FieldComponentsProvider,
FieldPropsProvider,
FormQueryParamsProvider,
ListInfoProvider,
ListQueryProvider,
LocaleProvider,

View File

@@ -6,7 +6,7 @@ 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 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 developers to easily inject custom—sometimes complex—functionality into Payload apps from a very small touch-point. This is especially useful is sharing your work across multiple projects or with the greater Payload community.
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).

View File

@@ -47,7 +47,7 @@ deploying to Production, it's a good idea to double-check that you are making pr
### The Secret Key
When you initialize Payload, you provide it with a `secret` property. This property should be impossible to guess and
extremely difficult for brute-force attacks to crack. Make sure your Production `secret` is a long, complex string.
extremely difficult for brute-force attacks to crack. Make sure your Production `secret` is a long, complex string.
### Double-check and thoroughly test all Access Control
@@ -78,7 +78,7 @@ Note that this is different than running `next dev`. Generally, Next.js apps com
### Secure Cookie Settings
You should be using an SSL certificate for production Payload instances, which means you
can [enable secure cookies](/docs/authentication/config) in your Authentication-enabled Collection configs.
can [enable secure cookies](/docs/authentication/overview) in your Authentication-enabled Collection configs.
### Preventing API Abuse
@@ -88,7 +88,7 @@ more. [Click here to learn more](/docs/production/preventing-abuse).
## Database
Payload can be used with any Postgres database or MongoDB-compatible database including AWS DocumentDB or Azure Cosmos DB. Make sure your production environment has access to the database that Payload uses.
Payload can be used with any Postgres database or MongoDB-compatible database including AWS DocumentDB or Azure Cosmos DB. Make sure your production environment has access to the database that Payload uses.
Out of the box, Payload templates pass the `process.env.DATABASE_URI` environment variable to its database adapters, so make sure you've got that environment variable (and all others that you use) assigned in your deployment platform.

View File

@@ -38,7 +38,7 @@ If you do not need GraphQL it is advised that you disable it altogether with the
Payload does not execute uploaded files on the server, but depending on your setup it may be used to transmit and store potentially dangerous files. If your configuration allows file uploads there is the potential that a bad actor uploads a malicious file that is then served to other users. Consider the following ways to mitigate the risks.
First, enable email [verification](/docs/authentication/config#email-verification) when users are allowed to register new accounts and add other bot prevention services.
First, enable email [verification](/docs/authentication/overview#email-verification) when users are allowed to register new accounts and add other bot prevention services.
Review that `create` and `update` access on file upload collections are as restrictive as your application needs allow. Consider limiting `read` access of uploaded user's files and how you might limit user uploaded files from being served outside of Payload.

View File

@@ -6,7 +6,7 @@ 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
---
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.
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 through an intuitive and standardized structure.
Payload provides three common APIs for querying your data:

View File

@@ -599,7 +599,7 @@ export const Orders: CollectionConfig = {
{
path: '/:id/tracking',
method: 'get',
handler: (req) => {
handler: async (req) => {
const tracking = await getTrackingInfo(req.params.id)
if (!tracking) {
@@ -614,7 +614,7 @@ export const Orders: CollectionConfig = {
{
path: '/:id/tracking',
method: 'post',
handler: (req) => {
handler: async (req) => {
// `data` is not automatically appended to the request
// if you would like to read the body of the request
// you can use `data = await req.json()`
@@ -654,7 +654,7 @@ import { addDataAndFileToRequest } from '@payloadcms/next/utilities'
{
path: '/:id/tracking',
method: 'post',
handler: (req) => {
handler: async (req) => {
await addDataAndFileToRequest(req)
await req.payload.update({
collection: 'tracking',
@@ -680,7 +680,7 @@ import { addLocalesToRequestFromData } from '@payloadcms/next/utilities'
{
path: '/:id/tracking',
method: 'post',
handler: (req) => {
handler: async (req) => {
await addLocalesToRequestFromData(req)
// you now can access req.locale & req.fallbackLocale
return Response.json({ message: 'success' })

View File

@@ -106,7 +106,7 @@ For example, let's look at the following simple Payload Config:
import type { Config } from 'payload'
const config: Config = {
serverURL: process.env.PAYLOAD_PUBLIC_SERVER_URL,
serverURL: process.env.NEXT_PUBLIC_SERVER_URL,
admin: {
user: 'users',
},

View File

@@ -95,7 +95,7 @@ See the [Collections](https://payloadcms.com/docs/configuration/collections) doc
### Security
The [`cors`](https://payloadcms.com/docs/production/preventing-abuse#cross-origin-resource-sharing-cors), [`csrf`](https://payloadcms.com/docs/production/preventing-abuse#cross-site-request-forgery-csrf), and [`cookies`](https://payloadcms.com/docs/authentication/config#options) settings are all configured to ensure that the admin panel and front-end can communicate with each other securely.
The [`cors`](https://payloadcms.com/docs/production/preventing-abuse#cross-origin-resource-sharing-cors), [`csrf`](https://payloadcms.com/docs/production/preventing-abuse#cross-site-request-forgery-csrf), and [`cookies`](https://payloadcms.com/docs/authentication/overview#options) settings are all configured to ensure that the admin panel and front-end can communicate with each other securely.
For additional help, see the [Authentication](https://payloadcms.com/docs/authentication/overview#authentication-overview) docs.

View File

@@ -37,18 +37,20 @@ See the [Collections](https://payloadcms.com/docs/configuration/collections) doc
The `pages` collection is draft-enabled and has access control that restricts public users from viewing pages with a `_status` of `draft`. To fetch draft documents on your front-end, simply include the `draft=true` query param along with the `Authorization` header once you have entered [Preview Mode](#preview-mode).
```ts
const preview = true; // set this based on your own front-end environment (see `Preview Mode` below)
const pageSlug = 'example-page'; // same here
const searchParams = `?where[slug][equals]=${pageSlug}&depth=1${preview ? `&draft=true` : ''}`
const preview = true // set this based on your own front-end environment (see `Preview Mode` below)
const pageSlug = 'example-page' // same here
const searchParams = `?where[slug][equals]=${pageSlug}&depth=1${preview ? `&draft=true` : ''}`
// when previewing, send the payload token to bypass draft access control
const pageReq = await fetch(`${process.env.NEXT_PUBLIC_PAYLOAD_URL}/api/pages${searchParams}`, {
headers: {
...preview ? {
Authorization: `JWT ${payloadToken}`,
} : {},
},
})
// when previewing, send the payload token to bypass draft access control
const pageReq = await fetch(`${process.env.NEXT_PUBLIC_PAYLOAD_URL}/api/pages${searchParams}`, {
headers: {
...(preview
? {
Authorization: `JWT ${payloadToken}`,
}
: {}),
},
})
```
For more details on how to extend this functionality, see the [Authentication](https://payloadcms.com/docs/authentication) docs.
@@ -71,7 +73,7 @@ You might also want to render an admin bar on your front-end so that logged-in u
### CORS
The [`cors`](https://payloadcms.com/docs/production/preventing-abuse#cross-origin-resource-sharing-cors), [`csrf`](https://payloadcms.com/docs/production/preventing-abuse#cross-site-request-forgery-csrf), and [`cookies`](https://payloadcms.com/docs/authentication/config#options) settings are configured to ensure that the admin panel and front-end can communicate with each other securely. If you are combining your front-end and admin panel into a single application that runs of a shared port and domain, you can simplify your config by removing these settings.
The [`cors`](https://payloadcms.com/docs/production/preventing-abuse#cross-origin-resource-sharing-cors), [`csrf`](https://payloadcms.com/docs/production/preventing-abuse#cross-site-request-forgery-csrf), and [`cookies`](https://payloadcms.com/docs/authentication/overview#options) settings are configured to ensure that the admin panel and front-end can communicate with each other securely. If you are combining your front-end and admin panel into a single application that runs of a shared port and domain, you can simplify your config by removing these settings.
For more details on this, see the [CORS](https://payloadcms.com/docs/production/preventing-abuse#cross-origin-resource-sharing-cors) docs.

View File

@@ -1,4 +1,4 @@
# Payload Multi-Tenant Example
# Payload Multi-Tenant Example (Single Domain)
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.
@@ -6,12 +6,16 @@ This example demonstrates how to achieve a multi-tenancy in [Payload](https://gi
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`
1. Clone this repo
1. `cd` into this directory and run `pnpm i --ignore-workspace`\*, `yarn`, or `npm install`
> \*If you are running using pnpm within the Payload Monorepo, the `--ignore-workspace` flag is needed so that pnpm generates a lockfile in this example's directory despite the fact that one exists in root.
1. `pnpm dev`, `yarn dev` or `npm run dev` to start the server
- Press `y` when prompted to seed the database
1. `open http://localhost:3000` to access the home page
1. `open http://localhost:3000/admin` to access the admin panel
- Login with email `demo@payloadcms.com` and password `demo`
## How it works

View File

@@ -0,0 +1,8 @@
import { withPayload } from '@payloadcms/next/withPayload'
/** @type {import('next').NextConfig} */
const nextConfig = {
// Your Next.js config here
}
export default withPayload(nextConfig)

View File

@@ -1,21 +1,18 @@
{
"name": "multi-tenant-single-domain",
"description": "An example of a multi tenant application, using a single domain",
"version": "1.0.0",
"description": "An example of a multi tenant application, using a single domain",
"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",
"dev": "cross-env NODE_OPTIONS=--no-deprecation && pnpm seed && next dev --turbo",
"generate:schema": "payload-graphql generate:schema",
"seed": "tsx ./scripts/seed.ts"
"generate:types": "payload generate:types",
"payload": "cross-env NODE_OPTIONS=--no-deprecation payload",
"seed": "npm run payload migrate:fresh",
"start": "cross-env NODE_OPTIONS=--no-deprecation next start"
},
"dependencies": {
"@payloadcms/db-mongodb": "3.0.0-beta.58",
@@ -42,6 +39,9 @@
"tsx": "^4.16.2",
"typescript": "5.5.2"
},
"engines": {
"node": "^18.20.2 || >=20.9.0"
},
"pnpm": {
"overrides": {
"@types/react": "npm:types-react@19.0.0-beta.2",

View File

@@ -1,184 +0,0 @@
/**
* This is an example of a standalone script that loads in the Payload config
* and uses the Payload Local API to query the database.
*/
process.env.PAYLOAD_DROP_DATABASE = 'true'
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: ['tenant-admin'],
tenant: tenant1.id,
},
],
username: 'tenant1',
},
payload,
})
await findOrCreateUser({
data: {
email: 'tenant2@payloadcms.com',
password: 'test',
tenants: [
{
roles: ['tenant-admin'],
tenant: tenant2.id,
},
],
username: 'tenant2',
},
payload,
})
await findOrCreateUser({
data: {
email: 'multi-admin@payloadcms.com',
password: 'test',
tenants: [
{
roles: ['tenant-admin'],
tenant: tenant1.id,
},
{
roles: ['tenant-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)

View File

@@ -2,7 +2,7 @@ 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 { headers as getHeaders } from 'next/headers'
import { notFound, redirect } from 'next/navigation'
import React from 'react'

View File

@@ -1 +0,0 @@
export default {};

View File

@@ -1,5 +0,0 @@
import type { PayloadRequest } from "payload";
export const isPayloadAdminPanel = (req: PayloadRequest) => {
return req.headers.has('referer') && req.headers.get('referer')?.startsWith(`${process.env.NEXT_PUBLIC_SERVER_URL}${req.payload.config.routes.admin}`)
}

View File

@@ -2,8 +2,8 @@ import type { Access } from 'payload'
import { parseCookies } from 'payload'
import { isSuperAdmin } from '../../../access/isSuperAdmin.js'
import { getTenantAccessIDs } from '../../../utilities/getTenantAccessIDs.js'
import { isSuperAdmin } from '../../../access/isSuperAdmin'
import { getTenantAccessIDs } from '../../../utilities/getTenantAccessIDs'
export const filterByTenantRead: Access = (args) => {
const req = args.req

View File

@@ -2,7 +2,7 @@ import type { FieldHook } from 'payload'
import { ValidationError } from 'payload'
import { getTenantAccessIDs } from '../../../utilities/getTenantAccessIDs.js'
import { getTenantAccessIDs } from '../../../utilities/getTenantAccessIDs'
export const ensureUniqueSlug: FieldHook = async ({ data, originalDoc, req, value }) => {
// if value is unchanged, skip validation

View File

@@ -1,10 +1,10 @@
import type { CollectionConfig } from 'payload'
import { tenantField } from '../../fields/TenantField/index.js'
import { isPayloadAdminPanel } from '../../utilities/isPayloadAdminPanel.js'
import { canMutatePage, filterByTenantRead } from './access/byTenant.js'
import { externalReadAccess } from './access/externalReadAccess.js'
import { ensureUniqueSlug } from './hooks/ensureUniqueSlug.js'
import { tenantField } from '../../fields/TenantField'
import { isPayloadAdminPanel } from '../../utilities/isPayloadAdminPanel'
import { canMutatePage, filterByTenantRead } from './access/byTenant'
import { externalReadAccess } from './access/externalReadAccess'
import { ensureUniqueSlug } from './hooks/ensureUniqueSlug'
export const Pages: CollectionConfig = {
slug: 'pages',

View File

@@ -2,8 +2,8 @@ import type { Access } from 'payload'
import { parseCookies } from 'payload'
import { isSuperAdmin } from '../../../access/isSuperAdmin.js'
import { getTenantAccessIDs } from '../../../utilities/getTenantAccessIDs.js'
import { isSuperAdmin } from '../../../access/isSuperAdmin'
import { getTenantAccessIDs } from '../../../utilities/getTenantAccessIDs'
export const filterByTenantRead: Access = (args) => {
const req = args.req

View File

@@ -1,7 +1,7 @@
import type { Access } from 'payload'
import { isSuperAdmin } from '../../../access/isSuperAdmin.js'
import { getTenantAccessIDs } from '../../../utilities/getTenantAccessIDs.js'
import { isSuperAdmin } from '../../../access/isSuperAdmin'
import { getTenantAccessIDs } from '../../../utilities/getTenantAccessIDs'
export const tenantRead: Access = (args) => {
const req = args.req

View File

@@ -1,7 +1,7 @@
import type { CollectionConfig } from 'payload'
import { isSuperAdmin } from '../../access/isSuperAdmin.js'
import { canMutateTenant, filterByTenantRead } from './access/byTenant.js'
import { isSuperAdmin } from '../../access/isSuperAdmin'
import { canMutateTenant, filterByTenantRead } from './access/byTenant'
export const Tenants: CollectionConfig = {
slug: 'tenants',

View File

@@ -2,8 +2,8 @@ import type { Access } from 'payload'
import type { User } from '../../../../payload-types'
import { isSuperAdmin } from '../../../access/isSuperAdmin.js'
import { getTenantAdminTenantAccessIDs } from '../../../utilities/getTenantAccessIDs.js'
import { isSuperAdmin } from '../../../access/isSuperAdmin'
import { getTenantAdminTenantAccessIDs } from '../../../utilities/getTenantAccessIDs'
export const createAccess: Access<User> = (args) => {
const { req } = args

View File

@@ -1,6 +1,6 @@
import type { Access } from 'payload'
import { isSuperAdmin } from '../../../access/isSuperAdmin.js'
import { isAccessingSelf } from './isAccessingSelf.js'
import { isSuperAdmin } from '../../../access/isSuperAdmin'
import { isAccessingSelf } from './isAccessingSelf'
export const isSuperAdminOrSelf: Access = (args) => isSuperAdmin(args) || isAccessingSelf(args)

View File

@@ -0,0 +1,51 @@
import type { User } from '@/payload-types'
import type { Access, Where } from 'payload'
import { parseCookies } from 'payload'
import { isSuperAdmin } from '../../../access/isSuperAdmin'
import { getTenantAdminTenantAccessIDs } from '../../../utilities/getTenantAccessIDs'
export const readAccess: Access<User> = (args) => {
const { req } = args
if (!req?.user) return false
const cookies = parseCookies(req.headers)
const superAdmin = isSuperAdmin(args)
const selectedTenant = cookies.get('payload-tenant')
if (selectedTenant) {
// If it's a super admin,
// give them read access to only pages for that tenant
if (superAdmin) {
return {
'tenants.tenant': {
equals: selectedTenant,
},
}
}
const tenantAccessIDs = getTenantAdminTenantAccessIDs(req.user)
const hasTenantAccess = tenantAccessIDs.some((id) => id === selectedTenant)
// If NOT super admin,
// give them access only if they have access to tenant ID set in cookie
if (hasTenantAccess) {
return {
'tenants.tenant': {
equals: selectedTenant,
},
}
}
}
if (superAdmin) return true
const adminTenantAccessIDs = getTenantAdminTenantAccessIDs(req.user)
return {
'tenants.tenant': {
in: adminTenantAccessIDs,
},
} as Where
}

View File

@@ -1,7 +1,7 @@
import type { Access } from 'payload'
import { isSuperAdmin } from '../../../access/isSuperAdmin.js'
import { getTenantAdminTenantAccessIDs } from '../../../utilities/getTenantAccessIDs.js'
import { isSuperAdmin } from '../../../access/isSuperAdmin'
import { getTenantAdminTenantAccessIDs } from '../../../utilities/getTenantAccessIDs'
export const updateAndDeleteAccess: Access = (args) => {
const { req } = args

View File

@@ -2,7 +2,7 @@ import type { FieldHook } from 'payload'
import { ValidationError } from 'payload'
import { getTenantAccessIDs } from '../../../utilities/getTenantAccessIDs.js'
import { getTenantAccessIDs } from '../../../utilities/getTenantAccessIDs'
export const ensureUniqueUsername: FieldHook = async ({ data, originalDoc, req, value }) => {
// if value is unchanged, skip validation

View File

@@ -2,32 +2,19 @@ import type { CollectionConfig } from 'payload'
import type { User } from '../../../payload-types'
import { isSuperAdmin } from '../../access/isSuperAdmin.js'
import { getTenantAdminTenantAccessIDs } from '../../utilities/getTenantAccessIDs.js'
import { createAccess } from './access/create.js'
import { updateAndDeleteAccess } from './access/updateAndDelete.js'
import { externalUsersLogin } from './endpoints/externalUsersLogin.js'
import { ensureUniqueUsername } from './hooks/ensureUniqueUsername.js'
import { getTenantAdminTenantAccessIDs } from '../../utilities/getTenantAccessIDs'
import { createAccess } from './access/create'
import { readAccess } from './access/read'
import { updateAndDeleteAccess } from './access/updateAndDelete'
import { externalUsersLogin } from './endpoints/externalUsersLogin'
import { ensureUniqueUsername } from './hooks/ensureUniqueUsername'
const Users: CollectionConfig = {
slug: 'users',
access: {
create: createAccess,
delete: updateAndDeleteAccess,
read: (args) => {
const { req } = args
if (!req?.user) return false
if (isSuperAdmin(args)) return true
const adminTenantAccessIDs = getTenantAdminTenantAccessIDs(req.user)
return {
'tenants.tenant': {
in: adminTenantAccessIDs,
},
}
},
read: readAccess,
update: updateAndDeleteAccess,
},
admin: {
@@ -51,12 +38,24 @@ const Users: CollectionConfig = {
name: 'tenant',
type: 'relationship',
filterOptions: ({ user }) => {
if (user?.roles?.includes('super-admin'))
if (!user) {
// Would like to query where exists true on id
// but that is not working
return {
id: {
exists: true,
like: '',
},
}
}
if (user?.roles?.includes('super-admin')) {
// Would like to query where exists true on id
// but that is not working
return {
id: {
like: '',
},
}
}
const adminTenantAccessIDs = getTenantAdminTenantAccessIDs(user as User)
return {
id: {

View File

@@ -1,7 +1,7 @@
import { cookies as getCookies } from 'next/headers'
import React from 'react'
import { TenantSelector } from './index.client.js'
import { TenantSelector } from './index.client'
export const TenantSelectorRSC = () => {
const cookies = getCookies()

View File

@@ -1,7 +1,7 @@
import type { FieldAccess } from 'payload'
import { isSuperAdmin } from '../../../access/isSuperAdmin.js'
import { getTenantAccessIDs } from '../../../utilities/getTenantAccessIDs.js'
import { isSuperAdmin } from '../../../access/isSuperAdmin'
import { getTenantAccessIDs } from '../../../utilities/getTenantAccessIDs'
export const tenantFieldUpdate: FieldAccess = (args) => {
const tenantIDs = getTenantAccessIDs(args.req.user)

View File

@@ -1,6 +1,6 @@
import type { FieldHook } from 'payload'
import { getTenantAccessIDs } from '../../../utilities/getTenantAccessIDs.js'
import { getTenantAccessIDs } from '../../../utilities/getTenantAccessIDs'
export const autofillTenant: FieldHook = ({ req, value }) => {
// If there is no value,

View File

@@ -1,9 +1,9 @@
import type { Field } from 'payload'
import { isSuperAdmin } from '../../access/isSuperAdmin.js'
import { tenantFieldUpdate } from './access/update.js'
import { TenantFieldComponent } from './components/Field.js'
import { autofillTenant } from './hooks/autofillTenant.js'
import { isSuperAdmin } from '../../access/isSuperAdmin'
import { tenantFieldUpdate } from './access/update'
import { TenantFieldComponent } from './components/Field'
import { autofillTenant } from './hooks/autofillTenant'
export const tenantField: Field = {
name: 'tenant',

View File

@@ -0,0 +1,131 @@
import type { MigrateUpArgs } from '@payloadcms/db-mongodb'
export async function up({ payload }: MigrateUpArgs): Promise<void> {
await payload.create({
collection: 'users',
data: {
email: 'demo@payloadcms.com',
password: 'demo',
roles: ['super-admin'],
},
})
const tenant1 = await payload.create({
collection: 'tenants',
data: {
name: 'Tenant 1',
slug: 'tenant-1',
},
})
const tenant2 = await payload.create({
collection: 'tenants',
data: {
name: 'Tenant 2',
slug: 'tenant-2',
},
})
const tenant3 = await payload.create({
collection: 'tenants',
data: {
name: 'Tenant 3',
slug: 'tenant-3',
},
})
await payload.create({
collection: 'users',
data: {
email: 'tenant1@payloadcms.com',
password: 'test',
tenants: [
{
roles: ['tenant-admin'],
tenant: tenant1.id,
},
],
username: 'tenant1',
},
})
await payload.create({
collection: 'users',
data: {
email: 'tenant2@payloadcms.com',
password: 'test',
tenants: [
{
roles: ['tenant-admin'],
tenant: tenant2.id,
},
],
username: 'tenant2',
},
})
await payload.create({
collection: 'users',
data: {
email: 'tenant3@payloadcms.com',
password: 'test',
tenants: [
{
roles: ['tenant-admin'],
tenant: tenant3.id,
},
],
username: 'tenant3',
},
})
await payload.create({
collection: 'users',
data: {
email: 'multi-admin@payloadcms.com',
password: 'test',
tenants: [
{
roles: ['tenant-admin'],
tenant: tenant1.id,
},
{
roles: ['tenant-admin'],
tenant: tenant2.id,
},
{
roles: ['tenant-admin'],
tenant: tenant3.id,
},
],
username: 'tenant3',
},
})
await payload.create({
collection: 'pages',
data: {
slug: 'home',
tenant: tenant1.id,
title: 'Page for Tenant 1',
},
})
await payload.create({
collection: 'pages',
data: {
slug: 'home',
tenant: tenant2.id,
title: 'Page for Tenant 2',
},
})
await payload.create({
collection: 'pages',
data: {
slug: 'home',
tenant: tenant3.id,
title: 'Page for Tenant 3',
},
})
}

View File

@@ -0,0 +1 @@
export default {}

View File

@@ -131,4 +131,4 @@ export interface Auth {
declare module 'payload' {
export interface GeneratedTypes extends Config {}
}
}

View File

@@ -4,10 +4,10 @@ import path from 'path'
import { buildConfig } from 'payload'
import { fileURLToPath } from 'url'
import { Pages } from './cms/collections/Pages/index.js'
import { Tenants } from './cms/collections/Tenants/index.js'
import Users from './cms/collections/Users/index.js'
import { TenantSelectorRSC } from './cms/components/TenantSelector/index.js'
import { Pages } from './collections/Pages'
import { Tenants } from './collections/Tenants'
import Users from './collections/Users'
import { TenantSelectorRSC } from './components/TenantSelector'
const filename = fileURLToPath(import.meta.url)
const dirname = path.dirname(filename)

View File

@@ -0,0 +1,10 @@
import type { PayloadRequest } from 'payload'
export const isPayloadAdminPanel = (req: PayloadRequest) => {
return (
req.headers.has('referer') &&
req.headers
.get('referer')
?.startsWith(`${process.env.NEXT_PUBLIC_SERVER_URL}${req.payload.config.routes.admin}`)
)
}

View File

@@ -27,10 +27,10 @@
"./src/*"
],
"@payload-config": [
"./src/payload.config.ts"
"src/payload.config.ts"
],
"@payload-types": [
"./src/payload-types.ts"
"src/payload-types.ts"
]
},
"target": "ES2017"

View File

@@ -1,6 +1,6 @@
{
"name": "payload-monorepo",
"version": "3.0.0-beta.64",
"version": "3.0.0-beta.68",
"private": true,
"type": "module",
"scripts": {

View File

@@ -1,6 +1,6 @@
{
"name": "create-payload-app",
"version": "3.0.0-beta.64",
"version": "3.0.0-beta.68",
"homepage": "https://payloadcms.com",
"repository": {
"type": "git",

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/db-mongodb",
"version": "3.0.0-beta.64",
"version": "3.0.0-beta.68",
"description": "The officially supported MongoDB database adapter for Payload",
"homepage": "https://payloadcms.com",
"repository": {
@@ -34,7 +34,6 @@
},
"dependencies": {
"bson-objectid": "2.0.4",
"deepmerge": "4.3.1",
"http-status": "1.6.2",
"mongoose": "6.12.3",
"mongoose-paginate-v2": "1.7.22",

Some files were not shown because too many files have changed in this diff Show More